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

Footnotes: use core’s meta revisioning if available #52988

Merged
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
8a169de
Footnotes: use core’s meta revisioning if available
adamsilverstein Jul 26, 2023
f8c55c2
Merge branch 'trunk' into redo-footnote-revisioning
adamsilverstein Sep 8, 2023
59bc54f
Ensure preview menu is closed after opening preview
adamsilverstein Sep 8, 2023
fd9d4a0
Improve docs and add some new conditionals
adamsilverstein Sep 9, 2023
c18cae0
Add test to verify published post meta is unchanged when previewing m…
adamsilverstein Sep 9, 2023
7d944d2
Correct overwriting of live published post meta when previewing
adamsilverstein Sep 9, 2023
fb6d61e
Comment out tests that require core changes to pass
adamsilverstein Sep 11, 2023
c91b95b
Merge branch 'trunk' into redo-footnote-revisioning
adamsilverstein Sep 26, 2023
d7a96e1
Include test to verify published post uneffected when previewing meta…
adamsilverstein Sep 26, 2023
a67bc45
Global styles tests: fire hooks when updating post
adamsilverstein Sep 26, 2023
9b1115d
Improve published post navigation in test
adamsilverstein Sep 26, 2023
037eb5a
Comment out failing test for published post
adamsilverstein Sep 26, 2023
766a777
Remove incorrect comment line
adamsilverstein Sep 26, 2023
cb37c48
Try: remove filters present in core already
adamsilverstein Sep 27, 2023
10edd9c
Merge branch 'trunk' into redo-footnote-revisioning
adamsilverstein Sep 27, 2023
c580c79
Move footnote filter shim to an external compat file
adamsilverstein Sep 27, 2023
82ad972
phpcbf
adamsilverstein Sep 27, 2023
9d2f120
Remove remaining hooks from footnotes that are causing issues
adamsilverstein Sep 27, 2023
1109df2
Revert "Remove remaining hooks from footnotes that are causing issues"
adamsilverstein Sep 28, 2023
7fee4f5
Temporarily disable slashing test
adamsilverstein Sep 28, 2023
2a55084
Restore test to verify that the published post is unchanged after pre…
adamsilverstein Sep 28, 2023
352bba5
Move the meta revision compat code to the footnotes shim file
adamsilverstein Sep 28, 2023
de6882c
remove hooks from footnotes file
adamsilverstein Sep 28, 2023
95f6b42
Ensure functions are guarded against redeclaration.
adamsilverstein Sep 28, 2023
a8e98f6
phpcbf
adamsilverstein Sep 28, 2023
90057fc
phpcbf2
adamsilverstein Sep 28, 2023
c614958
restore typing “3”
adamsilverstein Sep 28, 2023
90d7472
remove extra space
adamsilverstein Sep 28, 2023
6a4f28b
Restore slashed data test
adamsilverstein Sep 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
250 changes: 250 additions & 0 deletions lib/compat/plugin/footnotes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
<?php
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ellatrix If I'm not wrong this file should be moved to lib/compat/wordpress-6.4 because it's just here to support versions priori to 6.4 right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, although maybe I don't think these make sense anymore after the revision support was added. Cc @adamsilverstein

/**
* Compatibility shim for the footnotes bloct to enable test passing while awaiting the tested code to be merged to core.
*
* See https://github.com/WordPress/gutenberg/pull/52988.
*
* Once merged, this shim can be removed.
*
* @package gutenberg
*/

/**
* Remove footnote revision hooks when plugin is running on a version of core that already supports meta revisions.
*/
if ( function_exists( 'wp_post_revision_meta_keys' ) ) {
if ( has_action( 'rest_after_insert_post', 'wp_add_footnotes_revisions_to_post_meta' ) ) {
remove_action( 'rest_after_insert_post', 'wp_add_footnotes_revisions_to_post_meta' );
}
if ( has_action( 'rest_after_insert_page', 'wp_add_footnotes_revisions_to_post_meta' ) ) {
remove_action( 'rest_after_insert_page', 'wp_add_footnotes_revisions_to_post_meta' );
}
if ( has_action( 'wp_after_insert_post', 'wp_save_footnotes_meta' ) ) {
remove_action( 'wp_after_insert_post', 'wp_save_footnotes_meta' );
}
if ( has_action( '_wp_put_post_revision', 'wp_keep_footnotes_revision_id' ) ) {
remove_action( '_wp_put_post_revision', 'wp_keep_footnotes_revision_id' );
}
if ( has_action( 'wp_restore_post_revision', 'wp_restore_footnotes_from_revision' ) ) {
remove_action( 'wp_restore_post_revision', 'wp_restore_footnotes_from_revision' );
}
if ( has_action( 'wp_creating_autosave', '_wp_rest_api_autosave_meta' ) ) {
remove_action( 'wp_creating_autosave', '_wp_rest_api_autosave_meta' );
}
if ( has_action( '_wp_put_post_revision', '_wp_rest_api_autosave_meta' ) ) {
remove_action( '_wp_put_post_revision', '_wp_rest_api_autosave_meta' );
}
if ( has_filter( 'rest_pre_insert_post', '_wp_rest_api_force_autosave_difference' ) ) {
remove_filter( 'rest_pre_insert_post', '_wp_rest_api_force_autosave_difference' );
}
} else {
/**
* For versions of core that don't support meta revisions, use hooks to add.
*/
if ( ! function_exists( 'wp_save_footnotes_meta' ) ) {
/**
* Saves the footnotes meta value to the revision.
*
* @since 6.3.0
* @since 6.4.0 Core added post meta revisions, so this is no longer needed.
*
* @param int $revision_id The revision ID.
*/
function wp_save_footnotes_meta( $revision_id ) {
$post_id = wp_is_post_revision( $revision_id );

if ( $post_id ) {
$footnotes = get_post_meta( $post_id, 'footnotes', true );

if ( $footnotes ) {
// Can't use update_post_meta() because it doesn't allow revisions.
update_metadata( 'post', $revision_id, 'footnotes', wp_slash( $footnotes ) );
}
}
}
if ( ! function_exists( 'wp_post_revision_meta_keys' ) ) {
add_action( 'wp_after_insert_post', 'wp_save_footnotes_meta' );
}
}

if ( ! function_exists( 'wp_keep_footnotes_revision_id' ) ) {
/**
* Keeps track of the revision ID for "rest_after_insert_{$post_type}".
*
* @since 6.3.0
* @since 6.4.0 Core added post meta revisions, so this is no longer needed.
*
* @global int $wp_temporary_footnote_revision_id The footnote revision ID.
*
* @param int $revision_id The revision ID.
*/
function wp_keep_footnotes_revision_id( $revision_id ) {
global $wp_temporary_footnote_revision_id;
$wp_temporary_footnote_revision_id = $revision_id;
}
if ( ! function_exists( 'wp_post_revision_meta_keys' ) ) {
add_action( '_wp_put_post_revision', 'wp_keep_footnotes_revision_id' );
}
}

if ( ! function_exists( 'wp_add_footnotes_revisions_to_post_meta' ) ) {

/**
* This is a specific fix for the REST API. The REST API doesn't update
* the post and post meta in one go (through `meta_input`). While it
* does fix the `wp_after_insert_post` hook to be called correctly after
* updating meta, it does NOT fix hooks such as post_updated and
* save_post, which are normally also fired after post meta is updated
* in `wp_insert_post()`. Unfortunately, `wp_save_post_revision` is
* added to the `post_updated` action, which means the meta is not
* available at the time, so we have to add it afterwards through the
* `"rest_after_insert_{$post_type}"` action.
*
* @since 6.3.0
* @since 6.4.0 Core added post meta revisions, so this is no longer needed.
*
* @global int $wp_temporary_footnote_revision_id The footnote revision ID.
*
* @param WP_Post $post The post object.
*/
function wp_add_footnotes_revisions_to_post_meta( $post ) {
global $wp_temporary_footnote_revision_id;

if ( $wp_temporary_footnote_revision_id ) {
$revision = get_post( $wp_temporary_footnote_revision_id );

if ( ! $revision ) {
return;
}

$post_id = $revision->post_parent;

// Just making sure we're updating the right revision.
if ( $post->ID === $post_id ) {
$footnotes = get_post_meta( $post_id, 'footnotes', true );

if ( $footnotes ) {
// Can't use update_post_meta() because it doesn't allow revisions.
update_metadata( 'post', $wp_temporary_footnote_revision_id, 'footnotes', wp_slash( $footnotes ) );
}
}
}
}

if ( ! function_exists( 'wp_post_revision_meta_keys' ) ) {
add_action( 'rest_after_insert_post', 'wp_add_footnotes_revisions_to_post_meta' );
add_action( 'rest_after_insert_page', 'wp_add_footnotes_revisions_to_post_meta' );
}
}

if ( ! function_exists( 'wp_restore_footnotes_from_revision' ) ) {

/**
* Restores the footnotes meta value from the revision.
*
* @since 6.3.0
* @since 6.4.0 Core added post meta revisions, so this is no longer needed.
*
* @param int $post_id The post ID.
* @param int $revision_id The revision ID.
*/
function wp_restore_footnotes_from_revision( $post_id, $revision_id ) {
$footnotes = get_post_meta( $revision_id, 'footnotes', true );

if ( $footnotes ) {
update_post_meta( $post_id, 'footnotes', wp_slash( $footnotes ) );
} else {
delete_post_meta( $post_id, 'footnotes' );
}
}
if ( ! function_exists( 'wp_post_revision_meta_keys' ) ) {
add_action( 'wp_restore_post_revision', 'wp_restore_footnotes_from_revision', 10, 2 );
}
}

if ( ! function_exists( '_wp_rest_api_autosave_meta' ) ) {

/**
* The REST API autosave endpoint doesn't save meta, so we can use the
* `wp_creating_autosave` when it updates an exiting autosave, and
* `_wp_put_post_revision` when it creates a new autosave.
*
* @since 6.3.0
* @since 6.4.0 Core added post meta revisions, so this is no longer needed.
*
* @param int|array $autosave The autosave ID or array.
*/
function _wp_rest_api_autosave_meta( $autosave ) {
// Ensure it's a REST API request.
if ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) {
return;
}

$body = rest_get_server()->get_raw_data();
$body = json_decode( $body, true );

if ( ! isset( $body['meta']['footnotes'] ) ) {
return;
}

// `wp_creating_autosave` passes the array,
// `_wp_put_post_revision` passes the ID.
$id = is_int( $autosave ) ? $autosave : $autosave['ID'];

if ( ! $id ) {
return;
}

// Can't use update_post_meta() because it doesn't allow revisions.
update_metadata( 'post', $id, 'footnotes', wp_slash( $body['meta']['footnotes'] ) );
}

if ( ! function_exists( 'wp_post_revision_meta_keys' ) ) {
// See https://github.com/WordPress/wordpress-develop/blob/2103cb9966e57d452c94218bbc3171579b536a40/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php#L391C1-L391C1.
add_action( 'wp_creating_autosave', '_wp_rest_api_autosave_meta' );
// See https://github.com/WordPress/wordpress-develop/blob/2103cb9966e57d452c94218bbc3171579b536a40/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php#L398.
// Then https://github.com/WordPress/wordpress-develop/blob/2103cb9966e57d452c94218bbc3171579b536a40/src/wp-includes/revision.php#L367.
add_action( '_wp_put_post_revision', '_wp_rest_api_autosave_meta' );
}
}

if ( ! function_exists( '_wp_rest_api_force_autosave_difference' ) ) {

/**
* This is a workaround for the autosave endpoint returning early if the
* revision field are equal. The problem is that "footnotes" is not real
* revision post field, so there's nothing to compare against.
*
* This trick sets the "footnotes" field (value doesn't matter), which will
* cause the autosave endpoint to always update the latest revision. That should
* be fine, it should be ok to update the revision even if nothing changed. Of
* course, this is temporary fix.
*
* @since 6.3.0
* @since 6.4.0 Core added post meta revisions, so this is no longer needed.
*
* @param WP_Post $prepared_post The prepared post object.
* @param WP_REST_Request $request The request object.
*
* See https://github.com/WordPress/wordpress-develop/blob/2103cb9966e57d452c94218bbc3171579b536a40/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php#L365-L384.
* See https://github.com/WordPress/wordpress-develop/blob/2103cb9966e57d452c94218bbc3171579b536a40/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php#L219.
*/
function _wp_rest_api_force_autosave_difference( $prepared_post, $request ) {
// We only want to be altering POST requests.
if ( $request->get_method() !== 'POST' ) {
return $prepared_post;
}

// Only alter requests for the '/autosaves' route.
if ( substr( $request->get_route(), -strlen( '/autosaves' ) ) !== '/autosaves' ) {
return $prepared_post;
}

$prepared_post->footnotes = '[]';
return $prepared_post;
}
if ( ! function_exists( 'wp_post_revision_meta_keys' ) ) {
add_filter( 'rest_pre_insert_post', '_wp_rest_api_force_autosave_difference', 10, 2 );
}
}
}
1 change: 1 addition & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ function gutenberg_is_experiment_enabled( $name ) {

// Gutenberg plugin compat.
require __DIR__ . '/compat/plugin/edit-site-routes-backwards-compat.php';
require __DIR__ . '/compat/plugin/footnotes.php';

if ( ! class_exists( 'WP_HTML_Processor' ) ) {
require __DIR__ . '/compat/wordpress-6.4/html-api/class-gutenberg-html-tag-processor-6-4.php';
Expand Down
Loading
Loading