From acb24b0ba2d4a94934a6f8034e3196c18bfbb562 Mon Sep 17 00:00:00 2001 From: colinduwe Date: Tue, 7 Jan 2025 10:34:01 -0800 Subject: [PATCH 1/2] Initial commit to allow body classes to be sent from PHP and properly applied to iframe. Template class is modified when swapping templates. --- lib/block-editor-settings.php | 28 +++++++++++++++++++ .../src/components/iframe/index.js | 19 +++++++++---- .../post-template/reset-default-template.js | 20 ++++++++++++- .../post-template/swap-template-button.js | 20 ++++++++++++- 4 files changed, 79 insertions(+), 8 deletions(-) diff --git a/lib/block-editor-settings.php b/lib/block-editor-settings.php index 6448eb2e524853..d40e6cfeda3d66 100644 --- a/lib/block-editor-settings.php +++ b/lib/block-editor-settings.php @@ -159,6 +159,34 @@ function gutenberg_get_block_editor_settings( $settings ) { ); } + $body_classes = array(); + + $post = get_post(); + if ( $post ) { + $body_classes[] = 'post-type-' . sanitize_html_class( $post->post_type ); + $body_classes[] = 'post-status-' . sanitize_html_class( $post->post_status ); + + if ( post_type_supports( $post->post_type, 'post-formats' ) ) { + $post_format = get_post_format( $post ); + if ( $post_format && ! is_wp_error( $post_format ) ) { + $body_classes[] = 'post-format-' . sanitize_html_class( $post_format ); + } else { + $body_classes[] = 'post-format-standard'; + } + } + + $page_template = get_page_template_slug( $post ); + + if ( false !== $page_template ) { + $page_template = empty( $page_template ) ? 'default' : str_replace( '.', '-', basename( $page_template, '.php' ) ); + $body_classes[] = 'page-template-' . sanitize_html_class( $page_template ); + } + } + + $body_classes[] = 'locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_user_locale() ) ) ); + + $settings['bodyClasses'] = $body_classes; + return $settings; } add_filter( 'block_editor_settings_all', 'gutenberg_get_block_editor_settings', 0 ); diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index 8ec4b24106ebf3..28fd9209ccb728 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -16,7 +16,7 @@ import { import { __ } from '@wordpress/i18n'; import { useMergeRefs, useRefEffect, useDisabled } from '@wordpress/compose'; import { __experimentalStyleProvider as StyleProvider } from '@wordpress/components'; -import { useSelect } from '@wordpress/data'; +import { useSelect, dispatch } from '@wordpress/data'; /** * Internal dependencies @@ -118,7 +118,11 @@ function Iframe( { const { styles = '', scripts = '' } = resolvedAssets; /** @type {[Document, import('react').Dispatch]} */ const [ iframeDocument, setIframeDocument ] = useState(); - const [ bodyClasses, setBodyClasses ] = useState( [] ); + const bodyClasses = useSelect( ( select ) => { + const { getEditorSettings } = select( 'core/editor' ); + const editorSettings = getEditorSettings(); + return editorSettings.bodyClasses; + }, [] ); const clearerRef = useBlockSelectionClearer(); const [ before, writingFlowRef, after ] = useWritingFlow(); @@ -140,10 +144,11 @@ function Iframe( { clearerRef( documentElement ); - // Ideally ALL classes that are added through get_body_class should - // be added in the editor too, which we'll somehow have to get from - // the server in the future (which will run the PHP filters). - setBodyClasses( + // Initial body classes are provided by block-editor-settings.php and may include: + // post-type, post-status, post-format, page-template, and locale. + // That can be filtered via block_editor_settings_all on the server. + // below we update the core/editor settings to include some additional classes + const allBodyClasses = bodyClasses.concat( Array.from( ownerDocument.body.classList ).filter( ( name ) => name.startsWith( 'admin-color-' ) || @@ -151,6 +156,8 @@ function Iframe( { name === 'wp-embed-responsive' ) ); + const allBodyClasesSet = new Set( allBodyClasses ); + dispatch( 'core/editor' ).updateEditorSettings( { bodyClasses: Array.from( allBodyClasesSet ) } ); contentDocument.dir = ownerDocument.dir; diff --git a/packages/editor/src/components/post-template/reset-default-template.js b/packages/editor/src/components/post-template/reset-default-template.js index c730f6b06dee89..a2ca8286c45d95 100644 --- a/packages/editor/src/components/post-template/reset-default-template.js +++ b/packages/editor/src/components/post-template/reset-default-template.js @@ -3,7 +3,7 @@ */ import { MenuItem } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useDispatch } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; /** @@ -20,6 +20,12 @@ export default function ResetDefaultTemplate( { onClick } ) { const allowSwitchingTemplate = useAllowSwitchingTemplates(); const { postType, postId } = useEditedPostContext(); const { editEntityRecord } = useDispatch( coreStore ); + const bodyClasses = useSelect( ( select ) => { + const { getEditorSettings } = select( 'core/editor' ); + const editorSettings = getEditorSettings(); + return editorSettings.bodyClasses; + }, [] ); + const { updateEditorSettings } = useDispatch( 'core/editor' ); // The default template in a post is indicated by an empty string. if ( ! currentTemplateSlug || ! allowSwitchingTemplate ) { return null; @@ -34,6 +40,18 @@ export default function ResetDefaultTemplate( { onClick } ) { { template: '' }, { undoIgnore: true } ); + let hasPageTemplateClass = false; + const updatedBodyClasses = bodyClasses.map( className => { + if ( className.startsWith( 'page-template-' )) { + hasPageTemplateClass = true; + return `page-template-default`; + } + return className; + }); + if ( ! hasPageTemplateClass ) { + updatedBodyClasses.push( `page-template-default` ); + } + updateEditorSettings( { bodyClasses: updatedBodyClasses } ); onClick(); } } > diff --git a/packages/editor/src/components/post-template/swap-template-button.js b/packages/editor/src/components/post-template/swap-template-button.js index bdda349398406b..5094fd6256f233 100644 --- a/packages/editor/src/components/post-template/swap-template-button.js +++ b/packages/editor/src/components/post-template/swap-template-button.js @@ -6,7 +6,7 @@ import { decodeEntities } from '@wordpress/html-entities'; import { __experimentalBlockPatternsList as BlockPatternsList } from '@wordpress/block-editor'; import { MenuItem, Modal } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useDispatch } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; import { parse } from '@wordpress/blocks'; @@ -20,6 +20,12 @@ export default function SwapTemplateButton( { onClick } ) { const { postType, postId } = useEditedPostContext(); const availableTemplates = useAvailableTemplates( postType ); const { editEntityRecord } = useDispatch( coreStore ); + const bodyClasses = useSelect( ( select ) => { + const { getEditorSettings } = select( 'core/editor' ); + const editorSettings = getEditorSettings(); + return editorSettings.bodyClasses; + }, [] ); + const { updateEditorSettings } = useDispatch( 'core/editor' ); if ( ! availableTemplates?.length ) { return null; } @@ -31,6 +37,18 @@ export default function SwapTemplateButton( { onClick } ) { { template: template.name }, { undoIgnore: true } ); + let hasPageTemplateClass = false; + const updatedBodyClasses = bodyClasses.map( className => { + if ( className.startsWith( 'page-template-' )) { + hasPageTemplateClass = true; + return `page-template-${ template.name }`; + } + return className; + }); + if ( ! hasPageTemplateClass ) { + updatedBodyClasses.push( `page-template-${ template.name }` ); + } + updateEditorSettings( { bodyClasses: updatedBodyClasses } ); setShowModal( false ); // Close the template suggestions modal first. onClick(); }; From 80007830eb0d91c588ddb8fb112fd85249a878ed Mon Sep 17 00:00:00 2001 From: colinduwe Date: Sun, 26 Jan 2025 12:23:38 -0800 Subject: [PATCH 2/2] added support for is-dark-theme body class. Updated swap and reset to use store by variable. --- .../src/components/editor-styles/index.js | 18 ++++++++++++------ .../post-template/reset-default-template.js | 5 +++-- .../post-template/swap-template-button.js | 5 +++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/block-editor/src/components/editor-styles/index.js b/packages/block-editor/src/components/editor-styles/index.js index a59ac310bcd303..e9e3a8540ecae2 100644 --- a/packages/block-editor/src/components/editor-styles/index.js +++ b/packages/block-editor/src/components/editor-styles/index.js @@ -21,7 +21,7 @@ import { unlock } from '../../lock-unlock'; extend( [ namesPlugin, a11yPlugin ] ); -function useDarkThemeBodyClassName( styles, scope ) { +function useDarkThemeBodyClassName( scope, bodyClasses ) { return useCallback( ( node ) => { if ( ! node ) { @@ -58,12 +58,12 @@ function useDarkThemeBodyClassName( styles, scope ) { colordBackgroundColor.luminance() > 0.5 || colordBackgroundColor.alpha() === 0 ) { - body.classList.remove( 'is-dark-theme' ); - } else { - body.classList.add( 'is-dark-theme' ); + bodyClasses.filter( ( className ) => className !== 'is-dark-theme' ); + } else if( bodyClasses.includes( 'is-dark-theme' ) === false ) { + bodyClasses.push( 'is-dark-theme' ); } }, - [ styles, scope ] + [ scope, bodyClasses ] ); } @@ -98,12 +98,18 @@ function EditorStyles( { styles, scope, transformOptions } ) { ]; }, [ styles, overrides, scope, transformOptions ] ); + const bodyClasses = useSelect( ( select ) => { + const { getEditorSettings } = select( 'core/editor' ); + const editorSettings = getEditorSettings(); + return editorSettings.bodyClasses; + }, [] ); + return ( <> { /* Use an empty style element to have a document reference, but this could be any element. */ } diff --git a/packages/editor/src/components/post-template/reset-default-template.js b/packages/editor/src/components/post-template/reset-default-template.js index a2ca8286c45d95..fc8c407e976fac 100644 --- a/packages/editor/src/components/post-template/reset-default-template.js +++ b/packages/editor/src/components/post-template/reset-default-template.js @@ -14,6 +14,7 @@ import { useCurrentTemplateSlug, useEditedPostContext, } from './hooks'; +import { store as editorStore } from '../../store'; export default function ResetDefaultTemplate( { onClick } ) { const currentTemplateSlug = useCurrentTemplateSlug(); @@ -21,11 +22,11 @@ export default function ResetDefaultTemplate( { onClick } ) { const { postType, postId } = useEditedPostContext(); const { editEntityRecord } = useDispatch( coreStore ); const bodyClasses = useSelect( ( select ) => { - const { getEditorSettings } = select( 'core/editor' ); + const { getEditorSettings } = select( editorStore ); const editorSettings = getEditorSettings(); return editorSettings.bodyClasses; }, [] ); - const { updateEditorSettings } = useDispatch( 'core/editor' ); + const { updateEditorSettings } = useDispatch( editorStore ); // The default template in a post is indicated by an empty string. if ( ! currentTemplateSlug || ! allowSwitchingTemplate ) { return null; diff --git a/packages/editor/src/components/post-template/swap-template-button.js b/packages/editor/src/components/post-template/swap-template-button.js index 5094fd6256f233..c2aacbafa9d5f1 100644 --- a/packages/editor/src/components/post-template/swap-template-button.js +++ b/packages/editor/src/components/post-template/swap-template-button.js @@ -14,6 +14,7 @@ import { parse } from '@wordpress/blocks'; * Internal dependencies */ import { useAvailableTemplates, useEditedPostContext } from './hooks'; +import { store as editorStore } from '../../store'; export default function SwapTemplateButton( { onClick } ) { const [ showModal, setShowModal ] = useState( false ); @@ -21,11 +22,11 @@ export default function SwapTemplateButton( { onClick } ) { const availableTemplates = useAvailableTemplates( postType ); const { editEntityRecord } = useDispatch( coreStore ); const bodyClasses = useSelect( ( select ) => { - const { getEditorSettings } = select( 'core/editor' ); + const { getEditorSettings } = select( editorStore ); const editorSettings = getEditorSettings(); return editorSettings.bodyClasses; }, [] ); - const { updateEditorSettings } = useDispatch( 'core/editor' ); + const { updateEditorSettings } = useDispatch( editorStore ); if ( ! availableTemplates?.length ) { return null; }