Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block meta attributes and Custom Fields panel conflict #23078

Open
nk-o opened this issue Jun 10, 2020 · 9 comments
Open

Block meta attributes and Custom Fields panel conflict #23078

nk-o opened this issue Jun 10, 2020 · 9 comments
Labels
[Feature] Meta Boxes A draggable box shown on the post editing screen [Type] Bug An existing feature does not function as intended

Comments

@nk-o
Copy link
Contributor

nk-o commented Jun 10, 2020

Describe the bug
We have a block with an attribute, which saves in post meta. This block is working with no problem. Then we activate the Custom Fields panel and now changed in block attribute value will not be saved in post meta.

To reproduce
Steps to reproduce the behavior:

  1. Create a block with meta attribute - https://developer.wordpress.org/block-editor/tutorials/metabox/meta-block-3-add/

  2. Don't forget to register meta field in PHP - https://developer.wordpress.org/block-editor/tutorials/metabox/meta-block-2-register-meta/

  3. Insert this block in the post, fill the text control and update the post
    image

  4. Make sure your meta value saved in post (reload the page and you will see this value in field)

  5. Activate Custom Fields panel
    image

  6. Try to change the block value, then update the post and reload the page

  7. You will see, that your new meta value was not saved

Expected behavior
Custom meta should be synchronized automatically when editing block attributes and editing Custom Fields panel.

Editor version:

  • WordPress version: 5.4.1
  • Does the website has Gutenberg plugin installed, or is it using the block editor that comes by default? Default and Gutenberg Plugin
  • If the Gutenberg plugin is installed, which version is it? v8.2.1

Desktop:

  • OS: Windows
  • Browser Chrome
  • Version 83

Additional context

@annezazu annezazu added the [Type] Help Request Help with setup, implementation, or "How do I?" questions. label Jun 22, 2020
@ellatrix ellatrix added the [Feature] Meta Boxes A draggable box shown on the post editing screen label Aug 19, 2020
@getsource getsource added [Type] Bug An existing feature does not function as intended and removed [Type] Help Request Help with setup, implementation, or "How do I?" questions. labels Jul 6, 2021
@talldan
Copy link
Contributor

talldan commented Jul 6, 2021

A different issue, but the same problem was discussed in a slack triage session:
https://wordpress.slack.com/archives/C02QB2JS7/p1625549733336200

I think the problem happens because there are two API requests happening in the background. One REST request to update the post, and that's followed by an ajax request to post.php to update metaboxes. My hunch is that the second request overwrites the values set by the first.

I can think of two potential fixes:

  • update the value of metaboxes with the saved value from the first REST request before firing the second ajax request
  • omit already saved meta values from the second ajax request.

Probably other options too.

@bobbingwide
Copy link
Contributor

I think the problem happens because there are two API requests happening in the background.

I came to the same conclusion trying to develop a generic post meta field block.
bobbingwide/sb-field-block#2 (comment)

Notes:

  • I wasn't using Custom Fields, but my own Fields meta box.
  • Disabling the Fields meta box didn't resolve the issue.
  • I didn't try disabling the Custom Fields box as well.

I can think of two potential fixes:

Are these fixes something that would be implemented by core or would each block have to do it?
If the latter, what mechanisms are available?

@talldan
Copy link
Contributor

talldan commented Jul 6, 2021

Are these fixes something that would be implemented by core or would each block have to do it?

I'm thinking this would be in the Gutenberg codebase. This is where metabox saving happens:

export function* requestMetaBoxUpdates() {
yield {
type: 'REQUEST_META_BOX_UPDATES',
};
// Saves the wp_editor fields
if ( window.tinyMCE ) {
window.tinyMCE.triggerSave();
}
// Additional data needed for backward compatibility.
// If we do not provide this data, the post will be overridden with the default values.
const post = yield controls.select( editorStore.name, 'getCurrentPost' );
const additionalData = [
post.comment_status ? [ 'comment_status', post.comment_status ] : false,
post.ping_status ? [ 'ping_status', post.ping_status ] : false,
post.sticky ? [ 'sticky', post.sticky ] : false,
post.author ? [ 'post_author', post.author ] : false,
].filter( Boolean );
// We gather all the metaboxes locations data and the base form data
const baseFormData = new window.FormData(
document.querySelector( '.metabox-base-form' )
);
const activeMetaBoxLocations = yield controls.select(
editPostStore.name,
'getActiveMetaBoxLocations'
);
const formDataToMerge = [
baseFormData,
...activeMetaBoxLocations.map(
( location ) =>
new window.FormData( getMetaBoxContainer( location ) )
),
];
// Merge all form data objects into a single one.
const formData = reduce(
formDataToMerge,
( memo, currentFormData ) => {
for ( const [ key, value ] of currentFormData ) {
memo.append( key, value );
}
return memo;
},
new window.FormData()
);
additionalData.forEach( ( [ key, value ] ) =>
formData.append( key, value )
);
try {
// Save the metaboxes
yield apiFetch( {
url: window._wpMetaBoxUrl,
method: 'POST',
body: formData,
parse: false,
} );
yield controls.dispatch( editPostStore.name, 'metaBoxUpdatesSuccess' );
} catch {
yield controls.dispatch( editPostStore.name, 'metaBoxUpdatesFailure' );
}
}

So that might be a place to investigate.

@kraftner
Copy link

kraftner commented Apr 27, 2022

EDIT: Please have a look at #23078 (comment) for a much better workaround.


Since this can cause major issues and breakage I was looking for a workaround.

I didn't see any other solution than the nuclear option to completely disable the Custom Fields panel.

Please ensure you know what you are doing here before proceeding since

  • this is a dirty hack
  • with possible unwanted side effects
  • a temporary workaround at best
  • can break any time

⚠️💀 Completely disabling the Custom Fields panel 💀⚠️

There are actually two parts to it:

  • Force-Disabling the Custom Fields panel
  • Removing the setting in the preferences panel

Force-Disabling the Custom Fields panel

Since the preference whether to show the Custom Fields panel is stored in user meta we can just force it to always be false.

add_filter('get_user_metadata', function($value, $object_id, $meta_key, $single, $meta_type){
    if($meta_key !== 'enable_custom_fields'){
        return $value;
    }
    return false;
}, 10, 5);

Removing the setting in the preferences panel

You can still see the toggle to enable the Custom Fields panel in the preferences panel though. But it doesn't have any effect any more which is very bad/confusing UX. So:

Due to this check

getEditorSettings().enableCustomFields !== undefined,

we can hide the setting like this:

add_filter('block_editor_settings_all', function ($editorSettings, $editorContext) ){
    unset($editorSettings['enableCustomFields']);
    return $editorSettings;
}, 10, 2);

@kraftner
Copy link

Okay, scrap that, it is actually way easier. Just remove the meta box which also hides the settings panel. You can even do it just for those post types you want. Way better than what I had in #23078 (comment). 🤣

add_action('add_meta_boxes', function( $post_type, $post ){
    if ($post_type !== 'my-custom-post-type') {
        return;
    }
    remove_meta_box(
        'postcustom',
        null,
        'normal'
    );
},10, 2);

@gin0115
Copy link

gin0115 commented Mar 8, 2023

I found you can either prepend your meta key with an _ to denote it as a private key, or use the is_protected_meta to mark your keys as private (again) and also excluded from the custom field panel/meta box.

@Rilele
Copy link

Rilele commented Dec 8, 2023

I found you can either prepend your meta key with an _ to denote it as a private key, or use the is_protected_meta to mark your keys as private (again) and also excluded from the custom field panel/meta box.

I tried this an I got an error that I'm not allowed to edit the field. Did I miss something?

lipemat added a commit to lipemat/js-boilerplate-gutenberg that referenced this issue Mar 12, 2024
@lipemat
Copy link
Contributor

lipemat commented Mar 13, 2024

I found you can either prepend your meta key with an _ to denote it as a private key, or use the is_protected_meta to mark your keys as private (again) and also excluded from the custom field panel/meta box.

I tried this an I got an error that I'm not allowed to edit the field. Did I miss something?

Turns out you also need to add 'auth_callback' => '__return_true' when you register the meta or register_meta will set $args['auth_callback'] = '__return_false'.

@SantosGuillamot
Copy link
Contributor

I have started this pull request trying to solve this issue. Although I must say that I am not familiar with that code and I am not sure if that's a viable approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Meta Boxes A draggable box shown on the post editing screen [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

No branches or pull requests