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 attributes don't update custom meta fields #12794

Closed
izachros opened this issue Dec 11, 2018 · 13 comments
Closed

Block attributes don't update custom meta fields #12794

izachros opened this issue Dec 11, 2018 · 13 comments
Labels
[Feature] Block API API that allows to express the block paradigm. [Type] Help Request Help with setup, implementation, or "How do I?" questions.

Comments

@izachros
Copy link

izachros commented Dec 11, 2018

Describe the bug
I created a block that gets the values of some custom meta fields and adds them to block attributes. However, when I try to save the new value of a field it seems that the editor saves the value but when I refresh the page the block displays the old value. It actually didn't save the new value to meta field.

I added support for 'custom-fields' and I use the following code for the block:

el( InspectorControls, {}, el( TextControl, { label: 'Meta Field', value: props.attributes.meta_field, onChange: ( value ) => { props.setAttributes( { meta_field: value } ); }, } ) )

Also, i have one more field that doesn't get the value from a meta field and it seems to work great as it saves the new value (not to a meta field).

Does anyone have a solution for this? Thanks in advance!

@izachros
Copy link
Author

Also I can't display the value on the frontend. I can see it on backend but on the frontend it is empty. Any ideas?

@swissspidy swissspidy added [Type] Help Request Help with setup, implementation, or "How do I?" questions. [Feature] Block API API that allows to express the block paradigm. labels Dec 11, 2018
@swissspidy
Copy link
Member

You need to use register_post_meta() to make your meta data available in the REST API so that the values can be updated by the editor.

See https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-attributes/#considerations

@izachros
Copy link
Author

izachros commented Dec 11, 2018

@swissspidy

I have already added register_post_meta() but it doesn't work. I don't even get the values on the frontend.

The meta data is available in the REST API but it is not updated.

@swissspidy
Copy link
Member

Would you mind sharing your whole block registration code here then so we can verify this?

@swissspidy swissspidy reopened this Dec 11, 2018
@izachros
Copy link
Author

izachros commented Dec 11, 2018

Sure. Here it is:

index.php file:

function basic_info_block_init() {
	wp_enqueue_script(
		'basic-info-block',
		plugins_url( 'basic-info-block.js', __FILE__ ),
		array( 'wp-blocks', 'wp-element', 'wp-components', 'wp-editor' )
	);
	register_block_type( 'myblock/basic-info-block', array(
		'attributes'      => array(
			'style' => array(
				'type' => 'string',
			),
			'event_short_info' => array(
				'type' => 'string',
				'source' => 'meta',
				'meta' => 'event_short_info',
			),
			'event_start_date' => array(
				'type' => 'string',
				'source' => 'meta',
				'meta' => 'event_start_date',
			),
			'event_end_date' => array(
				'type' => 'string',
				'source' => 'meta',
				'meta' => 'event_end_date',
			),
			'event_free_entrance' => array(
				'type' => 'string',
				'source' => 'meta',
				'meta' => 'event_free_entrance',
			),
		),
		'editor_script'   => 'basic-info-block',
		'render_callback' => 'basic_info_block',
	) );
}
add_action( 'init', 'basic_info_block_init' );

and basic-info-block.js:

var el = wp.element.createElement,
	registerBlockType = wp.blocks.registerBlockType,
	ServerSideRender = wp.components.ServerSideRender,
	TextControl = wp.components.TextControl,
	SelectControl = wp.components.SelectControl,
	InspectorControls = wp.editor.InspectorControls;

registerBlockType( 'myblock/basic-info-block', {
	title: 'JTEC - Basic Info',
	icon: 'megaphone',
	category: 'widgets',

	edit: function( props ) {
		return  [
			el( ServerSideRender, {
				block: 'myblock/basic-info-block',
				attributes: props.attributes,
			} ),
			el( InspectorControls, {},
				el( SelectControl, {
					label: 'Style',
					value: props.attributes.style,
					options: [
						{ value: 'style-1', label: 'Style 1' },
						{ value: 'style-2', label: 'Style 2' },
					],
					onChange: ( value ) => { props.setAttributes( { style: value } ); },
				} ),
				el( TextControl, {
					label: 'Short Info',
					value: props.attributes.event_short_info,
					onChange: ( value ) => { props.setAttributes( { event_short_info: value } ); },
				} ),
				el( TextControl, {
					label: 'Start Date',
					value: props.attributes.event_start_date,
					onChange: ( value ) => { props.setAttributes( { event_start_date: value } ); },
				} ),
				el( TextControl, {
					label: 'End Date',
					value: props.attributes.event_end_date,
					onChange: ( value ) => { props.setAttributes( { event_end_date: value } ); },
				} ),
				el( SelectControl, {
					label: 'Free Entrance',
					value: props.attributes.event_free_entrance,
					options: [
						{ value: 'no', label: 'No' },
						{ value: 'yes', label: 'Yes' },
					],
					onChange: ( value ) => { props.setAttributes( { event_free_entrance: value } ); },
				} ),
			),
		];
	},

	save: function( ) {
		return  null;
	},
} );

Thanks in advance.

@izachros
Copy link
Author

izachros commented Dec 12, 2018

@swissspidy

Do you need something else? I also have this callback function to return the value:

function basic_info_block( $atts ) {
     return $atts['event_short_info'];
}

@izachros
Copy link
Author

I think I found the problem here.

I had to remove the save_post action from the old code as it replaced the new value with old one. However, it seems that I still can't display the value in the frontend. The callback function works great in the backend but on the frontend it is empty.

For example, if I add:

function basic_info_block( $atts ) {
     $short_info = 'Short Info: ' . $atts['event_short_info']
     return $short_info;
}

then I only get Short Info: in the frontend and the $atts['event_short_info'] is empty.

@swissspidy
Copy link
Member

That is to be expected. When you store attributes in post meta, they're not part of $atts.

You have to retrieve them using get_post_meta() instead.

@bracketsberlin
Copy link

bracketsberlin commented Jun 6, 2019

@izachros I am having the same problem as you. How did you fix it in the end? Unfortunately, I have no clue which function you mean with "save_post"?

I had to remove the save_post action from the old code as it replaced the new value with old one.

I am also able to save my meta value when creating a new post (custom post type), however, the update fails and sets the initial value/changes nothing.
el( TextControl, { label: 'Webseite', value: props.attributes.website, onChange: function( website ) { setAttributes({ website }); } } ),

Some other people seem to have the same problem and its a reported bug:

@swissspidy
Copy link
Member

@bracketsberlin I recommend you to create a new issue with your request instead of commenting on old, closed issues. Otherwise nobody will really notice your question.

Also, you need to share all your block's code (including how you configured attributes), otherwise it's impossible to know what is going wrong.

Please also note that you'll need to use register_post_meta() to properly make the meta data accessible via the REST API. Otherwise Gutenberg is not able to read/write to it.

Unfortunately, I have no clue which function you mean with "save_post"?

save_post is an action hook in WordPress, not a function. For your use case, that hook is irrelevant though.

@izachros
Copy link
Author

izachros commented Jun 7, 2019

@bracketsberlin

First, you have to register your custom meta fields using a function like this:

function my_plugin_register_post_metas_init() {
    register_post_meta( 'my_cpt', 'meta_field', array(
        'show_in_rest' => true,
        'single'       => true,
        'type'         => 'string',
    ) );
}
add_action( 'init', 'my_plugin_register_post_metas_init' );

Then, you have to change your code to:

el( SelectControl, {
        label: 'Website',
	value: props.attributes.website,
	onChange: ( value ) => { props.setAttributes( { website: value } ); },
} ),

Also, make sure that you use add_meta_boxes action as this:

function my_plugin_meta() {
    add_meta_box( 'my_plugin_meta_box',
        'Metabox Label',
        'display_my_plugin_meta_box',
        'my_cpt', 'normal', 'high',
        array(
            '__block_editor_compatible_meta_box' => true,
            '__back_compat_meta_box'             => true,
        )
    );
}
add_action( 'add_meta_boxes', 'my_plugin_meta' );

Hope this will help you fix the problem.

@bracketsberlin
Copy link

@izachros Thank you very much for your help. The add_meta_box() function seems to add meta boxes for custom post types that do not use Gutenberg blocks? I'd like to use Gutenberg blocks. I created a new issue here: #16023

Or do I get something wrong and you also propose your solution when it comes to working with Gutenberg blocks? As @swissspidy suggested, it probably makes more sense to work on the new issue.

Thanks for your help, guys.

@swissspidy
Copy link
Member

Yeah that add_meta_box part is unnecessary for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm. [Type] Help Request Help with setup, implementation, or "How do I?" questions.
Projects
None yet
Development

No branches or pull requests

3 participants