/**
 		@brief		Syncs the terms of a taxonomy from the parent blog in the BCD to the current blog.
 		@details	If $bcd->add_new_taxonomies is set, new taxonomies will be created, else they are ignored.
 
 		Upon syncing, the broadcasting data will contain an array of the equivalent source terms <-> child terms in:
 		$bcd->parent_blog_taxonomies[ $taxonomy ][ 'equivalent_terms' ][ $blog_id ]
 
 		@param		broadcasting_data		$bcd			The broadcasting data.
 		@param		string					$taxonomy		The taxonomy to sync.
 		@since		20131004
 	**/
 public function sync_terms($bcd, $taxonomy)
 {
     $source_terms = $bcd->parent_blog_taxonomies[$taxonomy]['terms'];
     if (!isset($bcd->parent_blog_taxonomies[$taxonomy]['equivalent_terms'])) {
         $bcd->parent_blog_taxonomies[$taxonomy]['equivalent_terms'] = [];
     }
     // Select only those terms that exist in the blog. We select them by slugs.
     $needed_slugs = [];
     foreach ($source_terms as $source_term) {
         $needed_slugs[$source_term->slug] = true;
     }
     $target_terms = get_terms($taxonomy, ['slug' => array_keys($needed_slugs), 'hide_empty' => false]);
     $target_terms = $this->array_rekey($target_terms, 'term_id');
     $this->debug('Target terms: %s', $target_terms);
     $refresh_cache = false;
     // Keep track of which terms we've found.
     $found_targets = [];
     $found_sources = [];
     // Also keep track of which sources we haven't found on the target blog.
     $unfound_sources = $source_terms;
     // Rekey the terms in order to find them faster.
     $source_slugs = [];
     foreach ($source_terms as $source_term_id => $source_term) {
         $source_slugs[$source_term->slug] = $source_term_id;
     }
     $target_slugs = [];
     foreach ($target_terms as $target_term) {
         $target_slugs[$target_term->slug] = $target_term->term_id;
     }
     // Step 1.
     $this->debug('Find out which of the source terms exist on the target blog.');
     foreach ($source_slugs as $source_slug => $source_term_id) {
         if (!isset($target_slugs[$source_slug])) {
             continue;
         }
         $target_term_id = $target_slugs[$source_slug];
         $this->debug('Found source term %s. Source ID: %s. Target ID: %s.', $source_slug, $source_term_id, $target_term_id);
         $found_targets[$target_term_id] = $source_term_id;
         $found_sources[$source_term_id] = $target_term_id;
         unset($unfound_sources[$source_term_id]);
     }
     // These sources were not found. Add them.
     if (isset($bcd->add_new_taxonomies) && $bcd->add_new_taxonomies) {
         $this->debug('%s taxonomies are missing on this blog.', count($unfound_sources));
         foreach ($unfound_sources as $unfound_source_id => $unfound_source) {
             // We need to clone because we will be modifying the source.
             $unfound_source = clone $unfound_source;
             if ($unfound_source->parent > 0) {
                 $this->debug('The unfound source needs a parent.');
                 $parent_of_equivalent_source_term = $unfound_source->parent;
                 $unfound_source->parent = 0;
                 // Does the parent of the source have an equivalent target?
                 if (isset($found_sources[$parent_of_equivalent_source_term])) {
                     $unfound_source->parent = $found_sources[$parent_of_equivalent_source_term];
                 }
                 // Recursively insert ancestors if needed, and get the target term's parent's ID
                 if ($unfound_source->parent == 0) {
                     $this->debug('Inserting parent term for %s', $unfound_source->slug);
                     $unfound_source->parent = $this->insert_term_ancestors($unfound_source, $taxonomy, $found_targets, $bcd->parent_blog_taxonomies[$taxonomy]['terms']);
                 }
             }
             $action = new actions\wp_insert_term();
             $action->taxonomy = $taxonomy;
             $action->term = $unfound_source;
             $action->execute();
             if ($action->new_term) {
                 $new_term = $action->new_term;
                 $new_term_id = $new_term->term_id;
                 $target_terms[$new_term_id] = $new_term;
                 $found_sources[$unfound_source_id] = $new_term_id;
                 $found_targets[$new_term_id] = $unfound_source_id;
                 $refresh_cache = true;
             }
         }
     }
     // Now we know which of the terms on our target blog exist on the source blog.
     // Next step: see if the parents are the same on the target as they are on the source.
     // "Same" meaning pointing to the same slug.
     $this->debug('About to update taxonomy terms.');
     foreach ($found_targets as $target_term_id => $source_term_id) {
         $source_term = (object) $source_terms[$source_term_id];
         $target_term = (object) $target_terms[$target_term_id];
         $action = new actions\wp_update_term();
         $action->taxonomy = $taxonomy;
         // The old term is the target term, since it contains the old values.
         $action->set_old_term($target_term);
         // The new term is the source term, since it has the newer data.
         $action->set_new_term($source_term);
         // ... but the IDs have to be switched around, since the target term has the new ID.
         $action->switch_data();
         // Does the source term even have a parent?
         if ($source_term->parent > 0) {
             $parent_of_equivalent_source_term = $source_term->parent;
             $this->debug('Parent of equivalent source term: %s', $parent_of_equivalent_source_term);
             // Does the parent of the source have an equivalent target?
             if (isset($found_sources[$parent_of_equivalent_source_term])) {
                 $new_parent = $found_sources[$parent_of_equivalent_source_term];
             }
         } else {
             $new_parent = 0;
         }
         $action->switch_data('parent');
         $action->new_term->parent = $new_parent;
         $action->execute();
         $refresh_cache |= $action->updated;
     }
     // Save the equivalent sources for later use.
     $blog_id = get_current_blog_id();
     $bcd->parent_blog_taxonomies[$taxonomy]['equivalent_terms'][$blog_id] = $found_sources;
     // wp_update_category alone won't work. The "cache" needs to be cleared.
     // see: http://wordpress.org/support/topic/category_children-how-to-recalculate?replies=4
     if ($refresh_cache) {
         delete_option('category_children');
     }
 }
 /**
 		@brief		Broadcast a post.
 		@details	The BC data parameter contains all necessary information about what is being broadcasted, to which blogs, options, etc.
 		@param		broadcasting_data		$broadcasting_data		The broadcasting data object.
 		@since		20130603
 	**/
 public function broadcast_post($broadcasting_data)
 {
     $bcd = $broadcasting_data;
     // To prevent recursion
     array_push($this->broadcasting, $bcd);
     $this->debug('Broadcast version %s.', THREEWP_BROADCAST_VERSION);
     $this->debug('Broadcasting the post %s <pre>%s</pre>', $bcd->post->ID, $bcd->post);
     $this->debug('The POST is <pre>%s</pre>', $bcd->_POST);
     // See: For nested broadcasts. Just in case.
     switch_to_blog($bcd->parent_blog_id);
     if ($bcd->link) {
         $this->debug('Linking is enabled.');
         if ($broadcasting_data->broadcast_data === null) {
             // Prepare the broadcast data for linked children.
             $bcd->broadcast_data = $this->get_post_broadcast_data($bcd->parent_blog_id, $bcd->post->ID);
             // Does this post type have parent support, so that we can link to a parent?
             if ($bcd->post_type_is_hierarchical && $bcd->post->post_parent > 0) {
                 $parent_broadcast_data = $this->get_post_broadcast_data($bcd->parent_blog_id, $bcd->post->post_parent);
             }
             $this->debug('Post type is hierarchical: %s', $this->yes_no($bcd->post_type_is_hierarchical));
         }
     } else {
         $this->debug('Linking is disabled.');
     }
     if ($bcd->taxonomies) {
         $this->debug('Will broadcast taxonomies.');
         $this->collect_post_type_taxonomies($bcd);
         $this->debug('Parent taxonomies dump: %s', $bcd->parent_post_taxonomies);
     } else {
         $this->debug('Will not broadcast taxonomies.');
     }
     $bcd->attachment_data = [];
     $attached_files = get_children('post_parent=' . $bcd->post->ID . '&post_type=attachment');
     $has_attached_files = count($attached_files) > 0;
     if ($has_attached_files) {
         $this->debug('Has %s attachments.', count($attached_files));
         foreach ($attached_files as $attached_file) {
             try {
                 $data = attachment_data::from_attachment_id($attached_file);
                 $data->set_attached_to_parent($bcd->post);
                 $bcd->attachment_data[$attached_file->ID] = $data;
                 $this->debug('Attachment %s found.', $attached_file->ID);
             } catch (Exception $e) {
                 $this->debug('Exception adding attachment: ' . $e->getMessage());
             }
         }
     }
     if ($bcd->custom_fields !== false) {
         if (!is_object($bcd->custom_fields)) {
             $bcd->custom_fields = (object) [];
         }
         $this->debug('Custom fields: Will broadcast custom fields.');
         if (isset($GLOBALS['wpseo_metabox'])) {
             $this->debug('Yoast SEO detected. Activating workaround. Asking metabox to save its settings.');
             $GLOBALS['wpseo_metabox']->save_postdata($bcd->post->ID);
         }
         // Save the original custom fields for future use.
         $bcd->custom_fields->original = get_post_custom($bcd->post->ID);
         // Obsolete!
         $bcd->post_custom_fields = $bcd->custom_fields->original;
         $this->debug('The custom fields are <pre>%s</pre>', $bcd->custom_fields()->to_array());
         // Start handling the thumbnail
         unset($bcd->thumbnail);
         $bcd->has_thumbnail = $bcd->custom_fields()->has('_thumbnail_id');
         // Check that the thumbnail ID is > 0
         if ($bcd->has_thumbnail) {
             $thumbnail_id = $bcd->custom_fields()->get_single('_thumbnail_id');
             $thumbnail_post = get_post($thumbnail_id);
             $bcd->has_thumbnail = $thumbnail_id > 0 && $thumbnail_post !== null;
         }
         if ($bcd->has_thumbnail) {
             $bcd->thumbnail_id = $thumbnail_id;
             $this->debug('Custom fields: Post has a thumbnail (featured image): %s', $bcd->thumbnail_id);
             $bcd->thumbnail = $thumbnail_post;
             $bcd->custom_fields()->forget('_thumbnail_id');
             // There is a new thumbnail id for each blog.
             try {
                 $data = attachment_data::from_attachment_id($thumbnail_id);
                 $data->set_attached_to_parent($bcd->post);
                 $bcd->attachment_data[$thumbnail_id] = $data;
             } catch (Exception $e) {
                 $this->debug('Exception adding attachment: ' . $e->getMessage());
             }
         } else {
             $this->debug('Custom fields: Post does not have a thumbnail (featured image).');
         }
         $bcd->custom_fields->blacklist = array_filter(explode(' ', $this->get_site_option('custom_field_blacklist')));
         $this->debug('The custom field blacklist is: %s', $bcd->custom_fields->blacklist);
         $bcd->custom_fields->protectlist = array_filter(explode(' ', $this->get_site_option('custom_field_protectlist')));
         $this->debug('The custom field protectlist is: %s', $bcd->custom_fields->protectlist);
         $bcd->custom_fields->whitelist = array_filter(explode(' ', $this->get_site_option('custom_field_whitelist')));
         $this->debug('The custom field whitelist is: %s', $bcd->custom_fields->whitelist);
         foreach ($bcd->custom_fields() as $custom_field => $ignore) {
             $keep = true;
             // Skip the exceptions.
             if ($bcd->custom_fields()->blacklist_has($custom_field)) {
                 $keep = false;
             }
             // If we do not broadcast them, then check the whitelist.
             if (!$keep and $bcd->custom_fields()->whitelist_has($custom_field)) {
                 $keep = true;
             }
             if (!$keep) {
                 $this->debug('Custom fields: Deleting custom field %s', $custom_field);
                 $bcd->custom_fields()->forget($custom_field);
             } else {
                 $this->debug('Custom fields: Keeping custom field %s', $custom_field);
             }
         }
     } else {
         $this->debug('Will not broadcast custom fields.');
     }
     // Handle any galleries.
     $bcd->galleries = new collection();
     $matches = $this->find_shortcodes($bcd->post->post_content, 'gallery');
     $this->debug('Found %s gallery shortcodes.', count($matches[2]));
     // [2] contains only the shortcode command / key. No options.
     foreach ($matches[2] as $index => $key) {
         // We've found a gallery!
         $bcd->has_galleries = true;
         $gallery = (object) [];
         $bcd->galleries->push($gallery);
         // Complete matches are in 0.
         $gallery->old_shortcode = $matches[0][$index];
         // Extract the IDs
         $gallery->ids_string = preg_replace('/.*ids=\\"([0-9,]*)".*/', '\\1', $gallery->old_shortcode);
         $this->debug('Gallery %s has IDs: %s', $gallery->old_shortcode, $gallery->ids_string);
         $gallery->ids_array = explode(',', $gallery->ids_string);
         foreach ($gallery->ids_array as $id) {
             $this->debug('Gallery has attachment %s.', $id);
             try {
                 $data = attachment_data::from_attachment_id($id);
                 $data->set_attached_to_parent($bcd->post);
                 $bcd->attachment_data[$id] = $data;
             } catch (Exception $e) {
                 $this->debug('Exception adding attachment: ' . $e->getMessage());
             }
         }
     }
     // Handle sticky status. This can be done in two ways: by _POST and by the options.
     // If the user is using the nromal editor, look in the post.
     if (isset($_POST['_wp_http_referer'])) {
         $this->debug('Sticky data found in POST.');
         $bcd->post_is_sticky = isset($_POST['sticky']);
     } else {
         // Look in the options table.
         $this->debug('Looking for sticky data via a function.');
         $bcd->post_is_sticky = is_sticky($bcd->post->ID);
     }
     $this->debug('Post sticky status: %s', intval($bcd->post_is_sticky));
     // POST is no longer needed. Empty it so that other plugins don't use it.
     $action = new actions\maybe_clear_post();
     $action->post = $_POST;
     $action->execute();
     // This is for any other plugins that might be interested in the _POST.
     $_POST = $action->post;
     // This is a stupid exception: edit_post() checks the _POST for the sticky checkbox.
     // And edit_post() is run after save_post()... :(
     // So if the post is sticky, we have to put the checkbox back in the post.
     // This can be avoided by either not clearing the post or forcing the user to update twice.
     // Neither solution is any good: not clearing the post makes _some_ plugins go crazy, updating twice is not expected behavior.
     if ($bcd->post_is_sticky) {
         $_POST['sticky'] = 'sticky';
     }
     // wp_upload_dir is incorrect on child sites, so we override it during broadcasting.
     // See the broadcasting_upload_dir method.
     $this->__siteurl = get_option('siteurl');
     $this->add_action('upload_dir', 'broadcasting_upload_dir');
     $action = new actions\broadcasting_started();
     $action->broadcasting_data = $bcd;
     $action->execute();
     $this->debug('The attachment data is: %s', $bcd->attachment_data);
     $this->debug('Beginning child broadcast loop.');
     foreach ($bcd->blogs as $child_blog) {
         $child_blog->switch_to();
         $bcd->current_child_blog_id = $child_blog->get_id();
         $this->debug('Switched to blog %s (%s)', get_bloginfo('name'), $bcd->current_child_blog_id);
         // Create new post data from the original stuff.
         $bcd->new_post = clone $bcd->post;
         $bcd->new_child_created = false;
         foreach (['guid', 'ID'] as $key) {
             unset($bcd->new_post->{$key});
         }
         foreach (['comment_count', 'post_parent'] as $key) {
             $bcd->new_post->{$key} = 0;
         }
         $action = new actions\broadcasting_after_switch_to_blog();
         $action->broadcasting_data = $bcd;
         $action->execute();
         if (!$action->broadcast_here) {
             $this->debug('Skipping this blog.');
             $child_blog->switch_from();
             continue;
         }
         // Force a reload the broadcast data?
         $bcd->broadcast_data = $this->get_post_broadcast_data($bcd->parent_blog_id, $bcd->post->ID);
         // Post parent
         if ($bcd->link && isset($parent_broadcast_data)) {
             if ($parent_broadcast_data->has_linked_child_on_this_blog()) {
                 $linked_parent = $parent_broadcast_data->get_linked_child_on_this_blog();
                 $bcd->new_post->post_parent = $linked_parent;
             }
         }
         // Insert new? Or update? Depends on whether the parent post was linked before or is newly linked?
         $need_to_insert_post = true;
         if ($bcd->broadcast_data !== null) {
             if ($bcd->broadcast_data->has_linked_child_on_this_blog()) {
                 $child_post_id = $bcd->broadcast_data->get_linked_child_on_this_blog();
                 $this->debug('There is already a child post on this blog: %s', $child_post_id);
                 // Does this child post still exist?
                 $child_post = get_post($child_post_id);
                 if ($child_post !== null) {
                     $temp_post_data = $bcd->new_post;
                     $temp_post_data->ID = $child_post_id;
                     wp_update_post($temp_post_data);
                     $bcd->new_post->ID = $child_post_id;
                     $need_to_insert_post = false;
                 } else {
                     $this->debug('Warning: The child post has disappeared. Recreating.');
                     $need_to_insert_post = true;
                 }
             }
         }
         if ($need_to_insert_post) {
             $temp_post_data = clone $bcd->new_post;
             $this->debug('Creating a new post: %s', $temp_post_data);
             unset($temp_post_data->ID);
             $result = wp_insert_post($temp_post_data, true);
             // Did we manage to insert the post properly?
             if (intval($result) < 1) {
                 $this->debug('Unable to insert the child post.');
                 continue;
             }
             // Yes we did.
             $bcd->new_post->ID = $result;
             $bcd->new_child_created = true;
             $this->debug('New child created: %s', $result);
             if ($bcd->link) {
                 $this->debug('Adding link to child.');
                 $bcd->broadcast_data->add_linked_child($bcd->current_child_blog_id, $bcd->new_post('ID'));
             }
         }
         $bcd->equivalent_posts()->set($bcd->parent_blog_id, $bcd->post->ID, $bcd->current_child_blog_id, $bcd->new_post('ID'));
         $this->debug('Equivalent of %s/%s is %s/%s', $bcd->parent_blog_id, $bcd->post->ID, $bcd->current_child_blog_id, $bcd->new_post('ID'));
         if ($bcd->taxonomies) {
             $this->debug('Taxonomies: Starting.');
             foreach ($bcd->parent_post_taxonomies as $parent_post_taxonomy => $parent_post_terms) {
                 $this->debug('Taxonomies: %s', $parent_post_taxonomy);
                 // If we're updating a linked post, remove all the taxonomies and start from the top.
                 if ($bcd->link) {
                     if ($bcd->broadcast_data->has_linked_child_on_this_blog()) {
                         wp_set_object_terms($bcd->new_post('ID'), [], $parent_post_taxonomy);
                     }
                 }
                 // Skip this iteration if there are no terms
                 if (!is_array($parent_post_terms)) {
                     $this->debug('Taxonomies: Skipping %s because the parent post does not have any terms set for this taxonomy.', $parent_post_taxonomy);
                     continue;
                 }
                 // Get a list of terms that the target blog has.
                 $target_blog_terms = $this->get_current_blog_taxonomy_terms($parent_post_taxonomy);
                 // Go through the original post's terms and compare each slug with the slug of the target terms.
                 $taxonomies_to_add_to = [];
                 foreach ($parent_post_terms as $parent_post_term) {
                     $found = false;
                     $parent_slug = $parent_post_term->slug;
                     foreach ($target_blog_terms as $target_blog_term) {
                         if ($target_blog_term->slug == $parent_slug) {
                             $this->debug('Taxonomies: Found existing taxonomy %s.', $parent_slug);
                             $found = true;
                             $taxonomies_to_add_to[] = intval($target_blog_term->term_id);
                             break;
                         }
                     }
                     // Should we create the taxonomy term if it doesn't exist?
                     if (!$found) {
                         // Does the term have a parent?
                         $target_parent_id = 0;
                         if ($parent_post_term->parent != 0) {
                             // Recursively insert ancestors if needed, and get the target term's parent's ID
                             $target_parent_id = $this->insert_term_ancestors($parent_post_term, $parent_post_taxonomy, $target_blog_terms, $bcd->parent_blog_taxonomies[$parent_post_taxonomy]['terms']);
                         }
                         $new_term = clone $parent_post_term;
                         $new_term->parent = $target_parent_id;
                         $action = new actions\wp_insert_term();
                         $action->taxonomy = $parent_post_taxonomy;
                         $action->term = $new_term;
                         $action->execute();
                         if ($action->new_term) {
                             $term_id = intval($action->new_term->term_id);
                             $taxonomies_to_add_to[] = $term_id;
                             $this->debug('Taxonomies: Created taxonomy %s (%s).', $parent_post_term->name, $term_id);
                         } else {
                             $this->debug('Taxonomies: Taxonomy %s was not created.', $parent_post_term->name);
                         }
                     }
                 }
                 $this->debug('Taxonomies: Syncing terms.');
                 $this->sync_terms($bcd, $parent_post_taxonomy);
                 $this->debug('Taxonomies: Synced terms.');
                 if (count($taxonomies_to_add_to) > 0) {
                     // This relates to the bug mentioned in the method $this->set_term_parent()
                     delete_option($parent_post_taxonomy . '_children');
                     clean_term_cache('', $parent_post_taxonomy);
                     $this->debug('Setting taxonomies for %s: %s', $parent_post_taxonomy, $taxonomies_to_add_to);
                     wp_set_object_terms($bcd->new_post('ID'), $taxonomies_to_add_to, $parent_post_taxonomy);
                 }
             }
             $this->debug('Taxonomies: Finished.');
         }
         // Maybe remove the current attachments.
         if ($bcd->delete_attachments) {
             $attachments_to_remove = get_children('post_parent=' . $bcd->new_post('ID') . '&post_type=attachment');
             $this->debug('%s attachments to remove.', count($attachments_to_remove));
             foreach ($attachments_to_remove as $attachment_to_remove) {
                 $this->debug('Deleting existing attachment: %s', $attachment_to_remove->ID);
                 wp_delete_attachment($attachment_to_remove->ID);
             }
         } else {
             $this->debug('Not deleting child attachments.');
         }
         // Copy the attachments
         $bcd->copied_attachments = [];
         $this->debug('Looking through %s attachments.', count($bcd->attachment_data));
         foreach ($bcd->attachment_data as $key => $attachment) {
             $o = clone $bcd;
             $o->attachment_data = clone $attachment;
             $o->attachment_data->post = clone $attachment->post;
             $this->debug("The attachment's post parent is %s.", $o->attachment_data->post->post_parent);
             if ($o->attachment_data->is_attached_to_parent()) {
                 $this->debug('Assigning new post parent ID (%s) to attachment %s.', $bcd->new_post('ID'), $o->attachment_data->post->ID);
                 $o->attachment_data->post->post_parent = $bcd->new_post('ID');
             } else {
                 $this->debug('Resetting post parent for attachment %s.', $o->attachment_data->post->ID);
                 $o->attachment_data->post->post_parent = 0;
             }
             $this->maybe_copy_attachment($o);
             $bcd->copied_attachments()->add($attachment->post, get_post($o->attachment_id));
             $this->debug('Copied attachment %s to %s', $attachment->post->ID, $o->attachment_id);
         }
         // Maybe modify the post content with new URLs to attachments and what not.
         $unmodified_post = (object) $bcd->new_post;
         $modified_post = clone $unmodified_post;
         // If there were any image attachments copied...
         if (count($bcd->copied_attachments()) > 0) {
             $this->debug('%s attachments were copied.', count($bcd->copied_attachments()));
             // Update the URLs in the post to point to the new images.
             $new_upload_dir = wp_upload_dir();
             foreach ($bcd->copied_attachments() as $a) {
                 $count = 0;
                 // Replace the GUID with the new one.
                 $modified_post->post_content = str_replace($a->old->guid, $a->new->guid, $modified_post->post_content, $count);
                 if ($count > 0) {
                     $this->debug('Modified attachment guid from %s to %s: %s times', $a->old->guid, $a->new->guid, $count);
                 }
                 // And replace the IDs present in any image captions.
                 $modified_post->post_content = str_replace('id="attachment_' . $a->old->id . '"', 'id="attachment_' . $a->new->id . '"', $modified_post->post_content, $count);
                 if ($count > 0) {
                     $this->debug('Modified attachment link from %s to %s: %s times', $a->old->id, $a->new->id, $count);
                 }
             }
         } else {
             $this->debug('No attachments were copied.');
         }
         // If there are galleries...
         $this->debug('%s galleries are to be handled.', count($bcd->galleries));
         foreach ($bcd->galleries as $gallery) {
             // Work on a copy.
             $gallery = clone $gallery;
             $new_ids = [];
             // Go through all the attachment IDs
             foreach ($gallery->ids_array as $id) {
                 $new_id = $bcd->copied_attachments()->get($id);
                 if ($new_id) {
                     $new_ids[] = $new_id;
                 }
             }
             $new_ids_string = implode(',', $new_ids);
             $new_shortcode = $gallery->old_shortcode;
             $new_shortcode = str_replace($gallery->ids_string, $new_ids_string, $gallery->old_shortcode);
             $this->debug('Replacing gallery shortcode %s with %s.', $gallery->old_shortcode, $new_shortcode);
             $modified_post->post_content = str_replace($gallery->old_shortcode, $new_shortcode, $modified_post->post_content);
         }
         $bcd->modified_post = $modified_post;
         $action = new actions\broadcasting_modify_post();
         $action->broadcasting_data = $bcd;
         $action->execute();
         $this->debug('Checking for post modifications.');
         $post_modified = false;
         foreach ((array) $unmodified_post as $key => $value) {
             if ($unmodified_post->{$key} != $modified_post->{$key}) {
                 $this->debug('Post has been modified because of %s.', $key);
                 $post_modified = true;
             }
         }
         // Maybe updating the post is not necessary.
         if ($post_modified) {
             $this->debug('Modifying new post.');
             wp_update_post($modified_post);
             // Or maybe it is.
         } else {
             $this->debug('No need to modify the post.');
         }
         if ($bcd->custom_fields) {
             $this->debug('Custom fields: Started.');
             $child_fields = $bcd->custom_fields()->child_fields();
             $child_fields->load();
             // new_post_old_custom_fields is obsolete. Remove the first part in a few versions.
             $bcd->new_post_old_custom_fields = $child_fields;
             $this->debug('Custom fields of the child post: %s', $child_fields->to_array());
             $protected_field = [];
             foreach ($child_fields as $key => $value) {
                 // Do we delete this custom field?
                 $delete = true;
                 // For the protectlist to work the custom field has to already exist on the child.
                 if ($bcd->custom_fields()->protectlist_has($key)) {
                     if (!$child_fields->has($key)) {
                         continue;
                     }
                     if (!$bcd->custom_fields()->has($key)) {
                         continue;
                     }
                     $protected_field[$key] = true;
                     $delete = false;
                 }
                 if ($delete) {
                     $this->debug('Custom fields: Deleting custom field %s.', $key);
                     $child_fields->delete_meta($key);
                 } else {
                     $this->debug('Custom fields: Keeping custom field %s.', $key);
                 }
             }
             foreach ($bcd->custom_fields() as $meta_key => $meta_value) {
                 // Protected = ignore.
                 if (isset($protected_field[$meta_key])) {
                     continue;
                 }
                 if (is_array($meta_value)) {
                     foreach ($meta_value as $single_meta_value) {
                         $single_meta_value = maybe_unserialize($single_meta_value);
                         $this->debug('Custom fields: Adding array value %s', $meta_key);
                         $child_fields->add_meta($meta_key, $single_meta_value);
                     }
                 } else {
                     $meta_value = maybe_unserialize($meta_value);
                     $this->debug('Custom fields: Adding value %s', $meta_key);
                     $child_fields->add_meta($meta_key, $meta_value);
                 }
             }
             // Attached files are custom fields... but special custom fields.
             if ($bcd->has_thumbnail) {
                 $new_thumbnail_id = $bcd->copied_attachments()->get($bcd->thumbnail_id);
                 $this->debug('Handling post thumbnail for post %s. Thumbnail ID is now %s', $bcd->new_post('ID'), $new_thumbnail_id);
                 update_post_meta($bcd->new_post('ID'), '_thumbnail_id', $new_thumbnail_id);
             }
             $this->debug('Custom fields: Finished.');
         }
         // Sticky behaviour
         $child_post_is_sticky = is_sticky($bcd->new_post('ID'));
         $this->debug('Sticky status: %s', intval($child_post_is_sticky));
         if ($bcd->post_is_sticky && !$child_post_is_sticky) {
             $this->debug('Sticking post.');
             stick_post($bcd->new_post('ID'));
         }
         if (!$bcd->post_is_sticky && $child_post_is_sticky) {
             $this->debug('Unsticking post.');
             unstick_post($bcd->new_post('ID'));
         }
         if ($bcd->link) {
             $new_post_broadcast_data = $this->get_post_broadcast_data($bcd->current_child_blog_id, $bcd->new_post('ID'));
             $new_post_broadcast_data->set_linked_parent($bcd->parent_blog_id, $bcd->post->ID);
             $this->debug('Saving broadcast data of child: %s', $new_post_broadcast_data);
             $this->set_post_broadcast_data($bcd->current_child_blog_id, $bcd->new_post('ID'), $new_post_broadcast_data);
             // Save the parent also.
             $this->debug('Saving parent broadcast data: %s', $bcd->broadcast_data);
             $this->set_post_broadcast_data($bcd->parent_blog_id, $bcd->post->ID, $bcd->broadcast_data);
         }
         $action = new actions\broadcasting_before_restore_current_blog();
         $action->broadcasting_data = $bcd;
         $action->execute();
         $child_blog->switch_from();
     }
     // SEE: For nested broadcasts. Just in case.
     restore_current_blog();
     $action = new actions\broadcasting_finished();
     $action->broadcasting_data = $bcd;
     $action->execute();
     // We are done with the upload dir override.
     unset($this->__siteurl);
     remove_action('upload_dir', [$this, 'broadcasting_upload_dir']);
     // Finished broadcasting.
     array_pop($this->broadcasting);
     if ($this->debugging_to_browser()) {
         if (!$this->is_broadcasting()) {
             if (isset($bcd->stop_after_broadcast) && !$bcd->stop_after_broadcast) {
                 $this->debug('Finished broadcasting.');
             } else {
                 $this->debug('Finished broadcasting. Now stopping Wordpress.');
                 exit;
             }
         } else {
             $this->debug('Still broadcasting.');
         }
     }
     $this->load_language();
     return $bcd;
 }