how to update post meta in a custom field in response to a user
interaction in the editor?
editPost()
can be used for that, but https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/#meta-source-deprecated stated that:
Although attributes may be obtained from a post’s meta, meta attribute
sources are considered deprecated; EntityProvider and related hook
APIs
should be used instead, as shown in the Create Meta Block
how-to.
So that means (in a function component), we should use useEntityProp
to update a post meta via the block editor, which changes the post/editor state and then activates the submit button so that one can click on it to actually save the new meta value.
But then, here’s why it didn’t work
You commented that:
I’m verifying that changes aren’t being applied in two ways: visually
in the editor “custom fields” UI (after a page refresh) and by
checking the API output at?feed=placepress_locations_public
Which means the “Custom Fields” meta box was enabled on the post editing screen (for your locations
CPT), right?
Because if so, then you should know that the editor will make 2 AJAX requests:
-
Request 1 will save the post title, content, meta, etc. via the REST API.
-
Request 2 will save the active custom fields in the above meta box via the
wp-admin/post.php
route, where the request URL might look like so:https://example.com/wp-admin/post.php?post=149&action=edit&meta-box-loader=1&meta-box-loader-nonce=7be53e3b5b&_locale=user
So that means, your api_coordinates_pp
meta will be saved twice and thus I believe all your attempts/code for updating the meta actually worked, but then the value got overwritten via the second request above and because the block editor does not automatically update the meta in that meta box, then that’s why the value remained the same as when the meta box was initially loaded. I.e. The meta value remained the same as the one that was last saved.
How to easily fix/avoid the issue
-
Change your meta to a protected meta, i.e. prefix the meta key with
_
(an underscore). -
Or add your meta to the list of protected meta using the
is_protected_meta
filter:// Turn the api_coordinates_pp meta to a *protected* meta without having to change // the meta key (to _api_coordinates_pp). add_filter( 'is_protected_meta', 'wpse_408053_filter_is_protected_meta', 10, 3 ); function wpse_408053_filter_is_protected_meta( $protected, $meta_key, $meta_type ) { return ( 'post' === $meta_type && 'api_coordinates_pp' === $meta_key ) ? true : $protected; }
So whether you used that filter or that you actually changed the meta key (to _api_coordinates_pp
), the meta would now no longer be available in the “Custom Fields” meta box which then avoids the meta value from being overwritten.
PS: You could also update the meta in that meta box using JS, e.g. after calling updateMetaCoordinates()
, but why bother with the extra code when the above options are easier 🙂
Additional Notes
-
As I commented, you should use
useEffect
instead of the onload hack. You can see a full example here which uses Leaflet v1.8.0, and @wordpress/dom-ready for the view/front-end-only script, but the main parts are basically:function initMap( { clientId, attributes, setAttributes, updateMetaCoordinates } ) { const mapId = 'map-' + clientId; const latLng = [ attributes.lat, attributes.lon ]; const map = L.map( mapId ).setView( latLng, 13 ); ... const marker = L.marker( latLng, { draggable: true } ).addTo( map ); const popup = L.popup(); ... const onDragend = e => { const latLng = e.latlng || e.target.getLatLng(); const latLngStr = latLng.lat + ',' + latLng.lng; openPopup( latLng, 'Current latitude & longitude: ' + latLngStr ); setAttributes( { lat: latLng.lat, lon: latLng.lng, } ); updateMetaCoordinates( latLngStr ); }; marker.on( 'dragend', onDragend ); ... } function edit( props ) { const postType = useSelect( select => select( 'core/editor' ).getCurrentPostType(), [] ); const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' ); const updateMetaCoordinates = value => { setMeta( { ...meta, api_coordinates_pp: value } ); console.log( 'meta api_coordinates_pp set to ' + value ); }; const mapId = 'map-' + props.clientId; // Create the Leaflet map once this block has been attacted to the DOM. useEffect( () => initMap( { ...props, updateMetaCoordinates } ), [ mapId ] ); return ( <div { ...useBlockProps() }> <p> Current latitude: { props.attributes.lat }<br /> Current longitude: { props.attributes.lon } </p> <div id={ mapId } className="map-pp" style={ { height: '180px' } } > Loading map.. </div> </div> ); }
And if you want, you can quickly try my block by downloading this plugin: wpse-408053.zip 🙂
-
Leaflet has a plugin for React, so you might want to try/check it out: https://github.com/PaulLeCam/react-leaflet