Simple Multisite Crossposting: Hook Reference

From time to time, I am asked to add some functionality to the plugin. Let’s say 1 of 50 customers wants something custom specifically for the own project.

But as you can see from the plugin name “Simple Multisite Crossposting” where the key word is “simple”, my goal is to keep my plugin from bloated code as far away as possible.

Luckily, most of the requested functionality can be implemented with WordPress hooks.

Using hooks

If you are going to use a code snippet with a hook, the best way you can do it is with creating a custom plugin.

In order to do so, please create an empty PHP-file in you wp-content/plugins directory, for example my-custom-super-plg.php. Add these lines:

 * Plugin name: My plugin 
 * Network: true

/// here you can insert the snippets

And then “Network activate” it.

Action and Filter Hook Reference


With this filter hook you can manage what custom post types are allowed for crossposting. By default – all public post types.

In the example below – allow only pages.

add_filter( 'rudr_crosspost_allowed_post_types', function( $post_types ) {
	return array( 'page' ); // the result should be returned as an array
} );


What post statuses should trigger the crossposting? By default – publish, which means only published posts.

Let’s allow published posts and drafts:

add_filter( 'rudr_crosspost_allowed_post_statuses', function( $post_statuses ) {
	return array( 'publish', 'draft' ); // must be an array
} );


Black list of meta keys.

If you don’t what to copy to other websites meta data with specific keys, you can do that:

add_filter( 'rudr_crosspost_excluded_meta_keys', function( $meta_keys ) {
	$meta_keys[] = 'key_1';
	$meta_keys[] = '_some_custom_hidden_key';
	$meta_keys[] = 'hi_misha';
	return $meta_keys;
} );

By default plugin never copies these keys: _wp_old_slug, _edit_lock, and you can not change that.


By default plugin doesn’t handle post deletion. But you can turn it on with the hook:

add_filter( 'rudr_crosspost_allow_post_deletion', function( $allow ) {
	return true;
} );

Please note, that posts from the other blogs will be deleted only if a specific checkbox is checked and saved.

So, once you check this checkbox, don’t forget to click the update button, otherwise the post won’t deleted or you can delete a post you don’t want to.

gutenberg checkbox

Only after that you can delete a post.


Allows you to change CPT (custom post type) while crossposting a post.

add_filter( 'rudr_crosspost_post_type_destination', 'rudr_change_post_type', 20, 3 );

function rudr_change_post_type( $post_type, $blog_id, $data ){

	if( 3 === $blog_id ) {
		$post_type = 'page';
		// everything that is crossposting to blog ID 3 will have "page" post type
	return $post_type;

(string) The post type of the original post.
(integer) The blog ID where the post is going to be crossposted to.
(array) Contains all the data of the post.


Allows to change post’s taxonomy terms while crossposting it.

add_filter( 'rudr_crosspost_taxonomy_destination', 'rudr_change_terms', 20, 3 );

function rudr_change_terms( $terms, $blog_id, $data ){

	if( 3 === $blog_id ) {

		$terms = array(
			'category' => array( 'my-term-taxonomy' )

	return $terms;

(array) Associative array of taxonomy=>array(term slugs) of the original post.
(integer) The blog ID where the post is going to be crossposted to.
(array) Contains all the data of the post.


Allows to crosspost content as drafts only.

add_filter( 'rudr_crosspost_as_draft', 'rudr_copy_as_draft', 20, 3 );

function rudr_copy_as_draft( $should_be_draft, $blog_id, $data ){
	return true; // Yes, create post copies as drafts first
(bool) Set to true if you would like new crossposted content appear as drafts. Defaults to false (post statuses will persist).
(integer) The blog ID where the post is going to be crossposted to.
(array) Contains all the data of the post.


By default if a user can edit a specific post on one blog, he/she also can crosspost it to any available blogs.

But with this hook you can also add a blog-related capability check.

For example if a user is administrator on blog 1, but has a subscriber role on blog 2, you can disallow to crosspost on blog 2 with this snippet:

add_filter( 'rudr_crosspost_check_caps', function( $capability ) {
	return 'edit_posts'; // the capability name or role name here to check
} );


Allows to set some custom rules in case you decide to disallow crossposting from a specific blog.

For example with the help of code snippet below we can prevent only the updates made on site with ID = 2 from being posted to the original articles.

add_filter( 'rudr_crosspost_allowed_from', function( $is_allowed, $blog_id, $post_id ) {

	// only for blog with ID = 2
	if( 2 !== $blog_id ){
		return $is_allowed;
	// let's check if it is NOT original article, we can do that by checking guid against the site url
	$post = get_post( $post_id );
	if( $post && $post->guid !== site_url() . '/?p=' . $post->ID ) {
		// no original, disallow crosspost
		$is_allowed = false;

	return $is_allowed;

}, 10, 3 );


By default the checkboxes on the blogs where you’re crossposting to are checked. You can ask the plugin to not check them automatically with a single line of code:

add_filter( 'rudr_smc_do_checkboxes', '__return_false' );


By default the site names are displayed in WordPress admin in my plugin UI. But in some cases you may have multiple website with the same name and you would like the domains to be displayed instead. Which is also possible with a hook.

add_filter( 'rudr_crosspost_use_domains_as_names', '__return_true' );

The code allows the sites to be displayed like:

display domains instead of site names


By default plugin displays the maximum of 100 subsites at once. You can change this number with this hook.

add_filter( 'rudr_crosspost_max_sites', function( $max ) {
	return 50;
} );

Need more help?