mirror of
https://github.com/WordPress/create-block-theme.git
synced 2026-07-26 21:42:48 +08:00
* Add can_modify_theme() permission helper with DISALLOW_FILE_* respect
* Wire 9 mutating REST routes to can_modify_theme()
* Add multisite permission tests (skip when not in multisite env)
* Keep DISALLOW_FILE_* authoritative over the cbt_file_mods_allowed filter
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Assert /font-families returns 200 SUCCESS, not just not-403
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Avoid constructor side effects in invoke_private test helper
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Grant super-admin on multisite to isolate file-mod hardening assertion
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Update docblock
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Restore docblock close marker dropped by Copilot suggestion
* Delegate file-mod check to WP Core's wp_is_file_mod_allowed
scruffian flagged that the previous implementation bypassed WordPress
Core's canonical `file_mod_allowed` filter — the mechanism hosts and
security plugins use to disable file modifications globally.
Now delegates the DISALLOW_FILE_MODS / file_mod_allowed branch to
wp_is_file_mod_allowed( 'create_block_theme_modify_theme' ). The
explicit DISALLOW_FILE_EDIT check is kept on top because Core's
helper does NOT cover that constant (it's specifically for the theme
file editor UI).
The cbt_file_mods_allowed filter remains as a test seam — it can only
further restrict, never re-enable, the policy decided by core.
* Add regression test for cbt filter not overriding core file_mod_allowed
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Use edit_themes + wp_is_file_mod_allowed for permission check
Refactors can_modify_theme() to compose two WordPress Core primitives
instead of reimplementing the same checks:
current_user_can( 'edit_themes' )
&& wp_is_file_mod_allowed( 'create_block_theme_modify_theme' )
The edit_themes capability already encodes the matrix this plugin
needs: held by Administrators on single-site, super-admins on multisite
(NOT sub-site admins), and automatically denied by Core when
DISALLOW_FILE_EDIT is defined. wp_is_file_mod_allowed handles
DISALLOW_FILE_MODS and the canonical file_mod_allowed filter.
That removes:
- the explicit is_multisite() / is_super_admin() branch
- the explicit DISALLOW_FILE_EDIT constant check
- the file_mods_allowed() helper
- the cbt_file_mods_allowed filter (was a test seam; tests now use
the canonical file_mod_allowed filter instead)
Functional matrix is unchanged.
* Document /reset-theme cap reuse for permission-surface consistency
* Hide UI when REST capability gate denies
Sub-site admins on multisite, DISALLOW_FILE_EDIT/DISALLOW_FILE_MODS
sites, and sites that deny file_mod_allowed for the
create_block_theme_modify_theme context now get 403s from every
mutating REST route — but the admin landing page and editor sidebar
were still registered behind edit_theme_options, so those users could
open the UI and click primary actions that the API rejects.
Make can_modify_theme() public static on CBT_Theme_API and gate
- the Appearance > Create Block Theme menu entry, and
- the site-editor plugin sidebar enqueue
on the same predicate, so the UI surface matches the REST surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Add multisite specific test runs
* Activate a block theme in UI-gate tests
Without an active block theme, both create_admin_menu() and
create_block_theme_sidebar_enqueue() return early on the
wp_is_block_theme() check — so the prior negative-only assertions
would have passed even if the cap gate did nothing. Activate a blank
block theme via the plugin's /create-blank endpoint (mirroring the
helper used in test-theme-fonts.php), then assert both directions:
menu/script register with the gate open, and drop out once
file_mod_allowed denies. This proves the cap gate (not the block-theme
guard) is what hides the UI.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Don't invoke sidebar enqueue under gate-open in test
The sidebar enqueue includes build/plugin-sidebar.asset.php on the
gate-open path; the CI test job doesn't build the plugin before
running PHP tests, so the previous version of this test errored on
that include. The cap-gate behaviour we care about is the gate-denied
path — that short-circuits before the include.
Drop the gate-open enqueue call and replace it with direct asserts on
the two preconditions (wp_is_block_theme() is true, $pagenow is
site-editor.php). That still proves the cap gate (not one of the
earlier guards) is what dropped the script, without depending on
build artefacts that CI doesn't produce.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61 lines
2 KiB
PHP
61 lines
2 KiB
PHP
<?php
|
|
|
|
/**
|
|
* The wp-admin landing page for the Create Block Theme plugin.
|
|
* @since 2.2.0
|
|
* @package Create_Block_Theme
|
|
* @subpackage Create_Block_Theme/includes
|
|
* @author WordPress.org
|
|
*/
|
|
class CBT_Admin_Landing {
|
|
|
|
public function __construct() {
|
|
add_action( 'admin_menu', array( $this, 'create_admin_menu' ) );
|
|
}
|
|
|
|
function create_admin_menu() {
|
|
if ( ! wp_is_block_theme() ) {
|
|
return;
|
|
}
|
|
|
|
// Mirror the REST surface gate (see CBT_Theme_API::can_modify_theme()):
|
|
// every primary action on this landing page calls a mutating route, so
|
|
// users who cannot pass that gate (sub-site admins on multisite,
|
|
// DISALLOW_FILE_EDIT/DISALLOW_FILE_MODS sites, file_mod_allowed denies)
|
|
// should not see the menu entry at all.
|
|
if ( ! CBT_Theme_API::can_modify_theme() ) {
|
|
return;
|
|
}
|
|
|
|
$landing_page_slug = 'create-block-theme-landing';
|
|
$landing_page_title = _x( 'Create Block Theme', 'UI String', 'create-block-theme' );
|
|
$landing_page_menu_title = $landing_page_title;
|
|
add_theme_page( $landing_page_title, $landing_page_menu_title, 'edit_themes', $landing_page_slug, array( 'CBT_Admin_Landing', 'admin_menu_page' ) );
|
|
|
|
}
|
|
|
|
public static function admin_menu_page() {
|
|
|
|
$asset_file = include plugin_dir_path( __DIR__ ) . 'build/admin-landing-page.asset.php';
|
|
|
|
// Enqueue CSS of the app
|
|
wp_enqueue_style( 'create-block-theme-app', plugins_url( 'build/admin-landing-page.css', __DIR__ ), array( 'wp-components' ), $asset_file['version'] );
|
|
|
|
// Load our app.js.
|
|
wp_enqueue_script( 'create-block-theme-app', plugins_url( 'build/admin-landing-page.js', __DIR__ ), $asset_file['dependencies'], $asset_file['version'] );
|
|
|
|
wp_localize_script(
|
|
'create-block-theme-app',
|
|
'cbt_landingpage_variables',
|
|
array(
|
|
'assets_url' => plugins_url( 'create-block-theme/assets/' ),
|
|
'editor_url' => admin_url( 'site-editor.php?canvas=edit' ),
|
|
)
|
|
);
|
|
|
|
// Enable localization in the app.
|
|
wp_set_script_translations( 'create-block-theme-app', 'create-block-theme' );
|
|
|
|
echo '<div id="create-block-theme-app"></div>';
|
|
}
|
|
}
|