Cmb2: Fields not saved on multisite

Created on 26 Apr 2018  路  15Comments  路  Source: CMB2/CMB2

I was debugging it in deep and found the issue

The CMB2_hookup->can_save() function returns false on multisite if at some moment any plugin (or WordPress itself) has switched to another blog (included a temporally switch) because ms_is_switched() will return true if any blog switch has made

So there should be another way to check if current blog is the same as where the box was placed

Probably adding a hidden field on multisites with the current site ID and checking it (similar to nonce checks) could solve the issue

Edit: Also, filtering the cmb2_can_save filter there is no way to access to the $type var

Most helpful comment

This would take some work for me to test right now. Rather, I would encourage you to do some investigation to see what is calling that switch_to_blog in the first place.

To debug, you could do some error logging to your debug.log file just before the stack is adjusted (e.g. put some logging here: https://github.com/WordPress/WordPress/blob/master/wp-includes/ms-blogs.php#L497)

You could add something like this to get some detailed info, including a call trace to see what called it:

$e = new Exception();
error_log( __FUNCTION__ . ':' . __LINE__ .') : '. print_r( array(
    '$new_blog'          => $new_blog,
    '$blog_id'           => $blog_id,
    'switching to same?' => $new_blog == $blog_id,
    'trace'              => $e->getTraceAsString(),
), true ) );

All 15 comments

I'm having this exact issue at the moment and need to find how to fix it urgently. I'm waiting to send the site live for the customer and this is the last fix I need. Please help

In the new-issue-template, we request that you include your CMB2 Field Registration Code. Without this, it's pretty difficult to try and duplicate your issue.

The main development environment I use when developing CMB2 is a multisite environment, and I have never had this issue. The only reason I can see that you might run into it is if you are doing odd things with switch_to_blog(), or potentially forgetting to restore_current_blog().

Same issue... any solution?

Any fix on this? We are also having this problem on multisite. The current error we are getting is;

Fatal error: Uncaught Error: Method name must be a string in /public_html/nwmulti/wp-content/plugins/insight-core/libs/cmb2/includes/CMB2_Field.php:512 Stack trace: #0 /public_html/nwmulti/wp-content/plugins/insight-core/libs/cmb2/includes/CMB2_Field.php(543): CMB2_Field->sanitization_cb(NULL) #1 /public_html/nwmulti/wp-content/plugins/insight-core/libs/cmb2/includes/CMB2_Field.php(529): CMB2_Field->save_field(NULL) #2 /public_html/nwmulti/wp-content/plugins/insight-core/libs/cmb2/includes/CMB2.php(777): CMB2_Field->save_field_from_data(Array) #3 /public_html/nwmulti/wp-content/plugins/insight-core/libs/cmb2/includes/CMB2.php(745): CMB2->process_field(Array) #4 /public_html/nwmulti/wp-content/plugins/insight-core/libs/cmb2/includes/CMB2.php(717): CMB2->process_fields() #5 /public_html/nwmulti/wp-content/plugins/insight-core/libs/cmb2-tabs/inc/cmb2-tabs.class.php(130): CMB2->save_fields() #6 /public_html/nwmulti/wp-includes/clas in /public_html/nwmulti/wp-content/plugins/insight-core/libs/cmb2/includes/CMB2_Field.php on line 512

https://github.com/CMB2/CMB2/issues/1125#issuecomment-385259957 Is still applicable here.

To add at least a little context, the line 512 is this:

// Sanitization via 'CMB2_Sanitize'
return $sanitizer->{$field_type}();

With $field_type being set earlier in the code via $field_type = $this->type();

That said, as Justin mentioned, providing your CMB2 configuration code will help us out a lot more, because it looks like something may not be getting set correctly with what you're using.

I've found we have this issue with sites cloned using NS Cloner:

https://en-gb.wordpress.org/plugins/ns-cloner-site-copier/

Everything except the saving of meta fields is working, though saving meta on Options pages is working.

As mentioned by @rubengc this seems to be down to ms_is_switched() returning true. Dumping the contents of $GLOBALS['_wp_switched_stack'] shows some switching has been made - but it's not by our theme (it's completely custom written by us, and I've checked) and neither plugins (they're all disabled).

I'm struggling to find what's breaking the chain of resetting the switched blogs - any insight would be appreciated.

As per the new-issue-template:

Expected Behavior:

Fields should save

Actual Behavior:

Fields aren't saving due to ms_is_switched() returning true as part of the CMB2_hookup->can_save() function

Possible Solution

Not sure, as I believe it's due to how the site was cloned - not that I'd expect the creator of CMB2 to provide a fix, but possibly a nudge in the right direction as to WHY this is happening

Possible Solution's Risk Level

N/A

Steps to reproduce

  1. Use NS Cloner to clone the main site in the network
  2. Attempt to modify a CMB2 field in any post/page

CMB2 Field Registration Code:

// Video
    $video = new_cmb2_box([
        'id'           => 'video',
        'title'        => 'Video',
        'object_types' => ['media', 'product', 'knowledge', 'page'],
        'context'      => 'normal',
        'priority'     => 'high',
        'show_names'   => false
    ]);

    $video->add_field([
        'name'    => 'Video',
        'id'      => s_.'video',
        'type'    => 'text_url',
        'desc'    => 'Url for YouTube, Vimeo etc.'
    ]);

Your Environment

Environment doesn't matter, this happens locally (MAMP with PHP 7.1) or on our staging server (Cloudways via Digital Ocean, Nginx proxy to Apache with PHP 7.1)

Screenshots (if appropriate)

N/A

Hack to fix

In order to get around this issue I've implemented the following, though I've no idea of any consequences:

add_action('pre_post_update', 'sp_pre_post_update');
function sp_pre_post_update($post_id) {
    $GLOBALS['_wp_switched_stack'] = [];
}

For what it's worth, this is the core function for ms_is_switched

function ms_is_switched() {
    return ! empty( $GLOBALS['_wp_switched_stack'] );
}

The hack above simply inserts an empty array into the global and short circuits it since an empty array is a value. One that will return false on empty() checks, last I checked.

This would take some work for me to test right now. Rather, I would encourage you to do some investigation to see what is calling that switch_to_blog in the first place.

To debug, you could do some error logging to your debug.log file just before the stack is adjusted (e.g. put some logging here: https://github.com/WordPress/WordPress/blob/master/wp-includes/ms-blogs.php#L497)

You could add something like this to get some detailed info, including a call trace to see what called it:

$e = new Exception();
error_log( __FUNCTION__ . ':' . __LINE__ .') : '. print_r( array(
    '$new_blog'          => $new_blog,
    '$blog_id'           => $blog_id,
    'switching to same?' => $new_blog == $blog_id,
    'trace'              => $e->getTraceAsString(),
), true ) );

@jtsternberg with the logging I was able to find the issue pretty quickly. I managed to forget that disabling a network plugin doesn't disable it within the sites themselves - it was a plugin causing the switching (https://en-gb.wordpress.org/plugins/intuitive-custom-post-order) where the plugin is switching back to the current blog by using switch_to_blog( $curr_blog ) instead of restore_current_blog.

Won't be using that one again.

@MattPurland So you're good again?

@MattPurland that's awesome news. Keep that logging/exception tracing snippet around. It's a huge time-saver for debugging issues like this. :)

Oh, also, a good alternative (based on my quick view of the Intuitive Custom Post Order plugin page) for that plugin is this one from 10up: https://wordpress.org/plugins/simple-page-ordering/

@tw2113 Yup!
@jtsternberg definitely, never though of doing that before.

Unfortunately I need a plugin that can order posts and taxonomy terms - what I was using did exactly what I needed. I'm sure there's something else out there.

Thanks all for your help!

Edit: found one https://wordpress.org/plugins/simple-custom-post-order/

I will close this issue since after many test I was able to find that issue is caused by plugins that doesn't call the restore_current_blog() function

Was this page helpful?
0 / 5 - 0 ratings

Related issues

abuyoyo picture abuyoyo  路  7Comments

jquimera picture jquimera  路  8Comments

tw2113 picture tw2113  路  8Comments

angelorocha picture angelorocha  路  6Comments

kidatart picture kidatart  路  7Comments