Skip to content

Commit

Permalink
Manually revert the relevant portions of #32229 in order to reproduce…
Browse files Browse the repository at this point in the history
… the wp_option data corruption bug
  • Loading branch information
fullofcaffeine committed Jun 17, 2021
1 parent 699cadc commit 17eb33b
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 142 deletions.
91 changes: 64 additions & 27 deletions lib/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,42 +185,79 @@ function gutenberg_auto_draft_get_sample_permalink( $permalink, $id, $title, $na
add_filter( 'get_sample_permalink', 'gutenberg_auto_draft_get_sample_permalink', 10, 5 );

/**
* Filters WP_User_Query arguments when querying users via the REST API.
* Expose the custom_logo theme-mod in the settings REST API.
*/
register_setting(
'general',
'theme_mods_' . get_option( 'stylesheet' ),
array(
'type' => 'object',
'show_in_rest' => array(
'name' => 'theme_mods_' . get_option( 'stylesheet' ),
'schema' => array(
'type' => 'object',
'properties' => array(
'custom_logo' => array( 'type' => 'integer' ),
),
),
),
)
);

/**
* Expose the "stylesheet" setting in the REST API.
*/
register_setting(
'general',
'stylesheet',
array(
'type' => 'string',
'show_in_rest' => true,
)
);

/**
* Filters the value of a setting recognized by the REST API.
*
* Allow using the has_published_post argument.
* Hijacks the value for custom_logo theme-mod.
*
* @param array $prepared_args Array of arguments for WP_User_Query.
* @param WP_REST_Request $request The REST API request.
* @param mixed $result Value to use for the requested setting. Can be a scalar
* matching the registered schema for the setting, or null to
* follow the default get_option() behavior.
* @param string $name Setting name (as shown in REST API responses).
*
* @return array Returns modified $prepared_args.
* @return null|array
*/
function gutenberg_rest_user_query_has_published_posts( $prepared_args, $request ) {
if ( ! empty( $request['has_published_posts'] ) ) {
$prepared_args['has_published_posts'] = ( true === $request['has_published_posts'] )
? get_post_types( array( 'show_in_rest' => true ), 'names' )
: (array) $request['has_published_posts'];
function gutenberg_rest_pre_get_setting_filter_custom_logo( $result, $name ) {
if ( 'theme_mods_' . get_option( 'stylesheet' ) === $name ) {
return array(
'custom_logo' => get_theme_mod( 'custom_logo' ),
);
}
return $prepared_args;
}
add_filter( 'rest_user_query', 'gutenberg_rest_user_query_has_published_posts', 10, 2 );

add_filter( 'rest_pre_get_setting', 'gutenberg_rest_pre_get_setting_filter_custom_logo', 10, 2 );

/**
* Filters REST API collection parameters for the users controller.
* Filters whether to preempt a setting value update via the REST API.
*
* Hijacks the saving method for theme-mods.
*
* @param array $query_params JSON Schema-formatted collection parameters.
* @param bool $result Whether to override the default behavior for updating the
* value of a setting.
* @param string $name Setting name (as shown in REST API responses).
* @param mixed $value Updated setting value.
*
* @return array Returns the $query_params with "has_published_posts".
* @return bool
*/
function gutenberg_rest_user_collection_params_has_published_posts( $query_params ) {
$query_params['has_published_posts'] = array(
'description' => __( 'Limit result set to users who have published posts.', 'gutenberg' ),
'type' => array( 'boolean', 'array' ),
'items' => array(
'type' => 'string',
'enum' => get_post_types( array( 'show_in_rest' => true ), 'names' ),
),
);
return $query_params;
function gutenberg_rest_pre_set_setting_filter_theme_mods( $result, $name, $value ) {
$theme_mods_setting_name = 'theme_mods_' . get_option( 'stylesheet' );
if ( $theme_mods_setting_name === $name ) {
$value = (array) $value;
$value = wp_parse_args( $value, get_option( $theme_mods_setting_name, array() ) );

update_option( $theme_mods_setting_name, $value );
return true;
}
}
add_filter( 'rest_user_collection_params', 'gutenberg_rest_user_collection_params_has_published_posts' );

add_filter( 'rest_pre_update_setting', 'gutenberg_rest_pre_set_setting_filter_theme_mods', 10, 3 );
62 changes: 37 additions & 25 deletions packages/block-library/src/site-logo/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,33 +255,45 @@ export default function LogoEdit( {
const [ logoUrl, setLogoUrl ] = useState();
const [ error, setError ] = useState();
const ref = useRef();
const { mediaItemData, siteLogo, url } = useSelect( ( select ) => {
const siteSettings = select( coreStore ).getEditedEntityRecord(
'root',
'site'
);
const mediaItem = siteSettings.site_logo
? select( coreStore ).getEntityRecord(
'root',
'media',
siteSettings.site_logo
)
: null;
return {
mediaItemData: mediaItem && {
url: mediaItem.source_url,
alt: mediaItem.alt_text,
},
siteLogo: siteSettings.site_logo,
url: siteSettings.url,
};
}, [] );
const { mediaItemData, siteLogo, url, stylesheet } = useSelect(
( select ) => {
const siteSettings = select( coreStore ).getEditedEntityRecord(
'root',
'site'
);

const themeModOptionName = `theme_mods_${ siteSettings.stylesheet }`;

siteSettings[ themeModOptionName ] =
siteSettings[ themeModOptionName ] || {};
const mediaItem = siteSettings[ themeModOptionName ].custom_logo
? select( coreStore ).getEntityRecord(
'root',
'media',
siteSettings[ themeModOptionName ].custom_logo
)
: null;
return {
mediaItemData: mediaItem && {
url: mediaItem.source_url,
alt: mediaItem.alt_text,
},
siteLogo: siteSettings[ themeModOptionName ].custom_logo,
url: siteSettings.url,
stylesheet: siteSettings.stylesheet,
};
},
[]
);

const { editEntityRecord } = useDispatch( coreStore );
const setLogo = ( newValue ) =>
editEntityRecord( 'root', 'site', undefined, {
site_logo: newValue,
} );
const setLogo = ( newValue ) => {
const settingsVal = {};
settingsVal[ `theme_mods_${ stylesheet }` ] = {
custom_logo: newValue,
};
editEntityRecord( 'root', 'site', undefined, settingsVal );
};

let alt = null;
if ( mediaItemData ) {
Expand Down
91 changes: 1 addition & 90 deletions packages/block-library/src/site-logo/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ function render_block_core_site_logo( $attributes ) {

$custom_logo = get_custom_logo();

remove_filter( 'wp_get_attachment_image_src', $adjust_width_height_filter );

if ( empty( $custom_logo ) ) {
return ''; // Return early if no custom logo is set, avoiding extraneous wrapper div.
}
Expand Down Expand Up @@ -58,27 +56,10 @@ function render_block_core_site_logo( $attributes ) {

$wrapper_attributes = get_block_wrapper_attributes( array( 'class' => implode( ' ', $classnames ) ) );
$html = sprintf( '<div %s>%s</div>', $wrapper_attributes, $custom_logo );
remove_filter( 'wp_get_attachment_image_src', $adjust_width_height_filter );
return $html;
}

/**
* Register a core site setting for a site logo
*/
function register_block_core_site_logo_setting() {
register_setting(
'general',
'site_logo',
array(
'show_in_rest' => array(
'name' => 'site_logo',
),
'type' => 'integer',
'description' => __( 'Site logo.' ),
)
);
}

add_action( 'rest_api_init', 'register_block_core_site_logo_setting', 10 );

/**
* Registers the `core/site-logo` block on the server.
Expand All @@ -91,74 +72,4 @@ function register_block_core_site_logo() {
)
);
}

add_action( 'init', 'register_block_core_site_logo' );

/**
* Overrides the custom logo with a site logo, if the option is set.
*
* @param string $custom_logo The custom logo set by a theme.
*
* @return string The site logo if set.
*/
function _override_custom_logo_theme_mod( $custom_logo ) {
$site_logo = get_option( 'site_logo' );
return false === $site_logo ? $custom_logo : $site_logo;
}

add_filter( 'theme_mod_custom_logo', '_override_custom_logo_theme_mod' );

/**
* Updates the site_logo option when the custom_logo theme-mod gets updated.
*
* This function is hooked on "update_option_theme_mods_$theme" and not
* "pre_set_theme_mod_custom_logo" because by hooking in `update_option`
* the function accounts for remove_theme_mod() as well.
*
* @param mixed $old_value The old option value.
* @param mixed $value The new option value.
*/
function _sync_custom_logo_to_site_logo( $old_value, $value ) {
// Delete the option when the custom logo does not exist or was removed.
// This step ensures the option stays in sync.
if ( empty( $value['custom_logo'] ) ) {
delete_option( 'site_logo' );
} else {
remove_action( 'update_option_site_logo', '_sync_site_logo_to_custom_logo' );
update_option( 'site_logo', $value['custom_logo'] );
add_action( 'update_option_site_logo', '_sync_site_logo_to_custom_logo', 10, 2 );
}
}

/**
* Hooks `_sync_custom_logo_to_site_logo` in `update_option_theme_mods_$theme`.
*
* Runs on `setup_theme` to account for dynamically-switched themes in the Customizer.
*/
function _sync_custom_logo_to_site_logo_on_setup_theme() {
$theme = get_option( 'stylesheet' );
add_action( "update_option_theme_mods_$theme", '_sync_custom_logo_to_site_logo', 10, 2 );
}
add_action( 'setup_theme', '_sync_custom_logo_to_site_logo_on_setup_theme', 11 );

/**
* Updates the custom_logo theme-mod when the site_logo option gets updated.
*
* @param mixed $old_value The old option value.
* @param mixed $value The new option value.
*
* @return void
*/
function _sync_site_logo_to_custom_logo( $old_value, $value ) {
// Delete the option when the custom logo does not exist or was removed.
// This step ensures the option stays in sync.
if ( empty( $value ) ) {
remove_theme_mod( 'custom_logo' );
} else {
remove_filter( 'pre_set_theme_mod_custom_logo', '_sync_custom_logo_to_site_logo' );
set_theme_mod( 'custom_logo', $value );
add_filter( 'pre_set_theme_mod_custom_logo', '_sync_custom_logo_to_site_logo' );
}
}

add_action( 'update_option_site_logo', '_sync_site_logo_to_custom_logo', 10, 2 );

0 comments on commit 17eb33b

Please sign in to comment.