WP_DEBUG

Notes about WordPress Gutenberg themes development.

  • GitHub

.htaccess (1) ACF (7) admin (1) ajax (2) api (1) API interactivity (1) block (20) block_style (2) colors (2) constante (1) context (1) conventions (2) cron (1) css (5) custom post type (1) data (1) debug (2) define (1) file_API (1) functions.php (6) git (4) hook (7) i18n (2) js (2) layout (1) loop (1) media (1) media library (1) menu (2) navigation (1) patterns (1) performance (2) post (1) query (3) readmore (1) responsive (1) rest api (1) scss (1) security (7) spacing (1) sql (1) svg (1) taxonomy (1) theme (1) theme.json (11) typo (2) URL (1) wp-config.php (6) wp cli (3) wp function (7)

  • note: Gutenberg components source code

    # block
    Read more

    To check the block.json for eg or import component in edit.js :

    https://github.com/WordPress/gutenberg/tree/trunk/packages/components

    https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src

  • Several blocks in one folder / plugin

    # block
    Read more
    $ npx @wordpress/create-block@latest blocks --template @wordpress/create-block-interactive-template
    $ cd blocks/src/
    $ mkdir "blockname"
    $ mv * in "blockname" 

    Duplicate the “whatever blockname” in the src folder to add new blocks.

    In functions.php:

    foreach ( glob( get_stylesheet_directory() . '/blocks/build/*' ) as $block_directory ) {
    		register_block_type( $block_directory );
    }
  • Block: server side rendering

    # block
    November 25, 2024
    Read more

    A convenient way to display the block in the editor :

    import ServerSideRender from '@wordpress/server-side-render';
    
    export default function Edit( { attributes, setAttributes } ) {
    
    return (
    
         <ServerSideRender
              block="dev/some-block"
              attributes={attributes}
         />
    
    );
    
    }

    Without module : <wp.blockEditor.ServerSideRender block="custom/menu-display" attributes={attributes} />

    Source: https://developer.wordpress.org/block-editor/reference-guides/packages/packages-server-side-render/

  • block: context

    # block, context
    Read more

    Used to create a context of data, for example between parent / children blocks.

    Example, making the post id accessible, in block.json:

    {
    	"$schema": "https://schemas.wp.org/trunk/block.json",
        ...
        "usesContext": [ "postId" ]
    }

    In render.php :

    $post_id = $block->context['postId'];

    In edit.json :

    export default function Edit( { attributes, setAttributes, context } ) {
    
    // context.postId
    
    }
  • block: core data

    # block, data
    Read more

    How to fetch data from a block : in edit.js

    import { useSelect } from '@wordpress/data';
    
    const SomeComponent = ( { attributes, setAttributes } ) => {
    
        const taxonomies = useSelect( select => select( 'core' ).getTaxonomies(), [] );
    
    
    ...
    
    
    }

    Sources :

    • https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/
    • https://developer.wordpress.org/news/2024/03/28/how-to-work-effectively-with-the-useselect-hook/
    • https://developer.wordpress.org/block-editor/reference-guides/data/data-core/
  • render.php : available variables

    # block
    Read more
    • $content
    • $attributes (defined in block.json)
    • $block

  • API interactivity

    # API interactivity, block
    March 20, 2025
    Read more

    In block.json : { supports: { interactivity: true }, viewScriptModule: file:./view.js }

    1/ create directive

    data-wp-interactive="namespace"

    data-wp-context='{"foo": "bar"}' → local state

    data-wp-class--{class-name} the class presence will be tied to a value

    data-wp-bind--{attribute-name}

    data-wp-on--{event-name}

    2/ create a store

    • state
    • actions
    • callback
    • getElement()
    • getContext()

    Example

    view.js :

    import { store, getContext } from '@wordpress/interactivity';
    
    store( 'wpdsfr', {
    	actions: {
    		toggle: () => {
    			const context = getContext();
    			context.isOpen = ! context.isOpen;
    		},
    	}
    } );

    render.php

    <section
    	data-wp-interactive="wpdsfr"
    	data-wp-context='{ "isOpen": false}'
    	<?php echo get_block_wrapper_attributes(); ?>>
    
    	<h3	data-wp-on--click="actions.toggle">
    		item title
    	</h3>
    
    	<div data-wp-class--is-open="context.isOpen">
    		<?php echo $content; ?>
    	</div>
    </section>

    Sources:

    • https://make.wordpress.org/core/2024/03/04/interactivity-api-dev-note/
    • https://developer.wordpress.org/news/2024/04/11/a-first-look-at-the-interactivity-api/
    • https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/api-reference/#list-of-directives (*)
    • https://www.youtube.com/watch?v=49_XlQJYztA&list=LL&index=1
    • https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/core-concepts/undestanding-global-state-local-context-and-derived-state/
  • block: custom icon

    # block
    August 14, 2024
    Read more

    in index.js :

    registerBlockType(
    	metadata,
    	{
    		icon: {
    			src: <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" enable-background="new 0 0 512 512">
    				<g>
    					<g>
    						<path d="...
    					</g>
    				</g>
    			</svg>
    		},
    		edit: Edit,
    		save: Save
    	}
    )

    Source: https://rudrastyh.com/gutenberg/custom-svg-icons.html

  • block: innerBlocks

    # block
    March 23, 2025
    Read more

    Option 1: InnerBlocks component

    index.js:

    import { InnerBlocks } from '@wordpress/block-editor';
    
    registerBlockType( metadata.name, {
    	edit: Edit,
    	save: props => { return <InnerBlocks.Content /> }
    ):

    render.php:

    <?php echo $content; ?>

    in edit.js:

    return (  <InnerBlocks { ...blockProps } /> )

    Option 2: useInnerBlocksProps hook

    This allow more control on the editor site. In edit.js:

    import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
    
    export default function Edit( { attributes, setAttributes } ) {
    
    	const MC_TEMPLATE = [
    		[ 'core/image', {} ],
    		[ 'core/paragraph', { content: 'Text content' } ]
    	];
    	const blockProps = useBlockProps( { className: 'sim-slide sim-slide-single-editor' } );
    	const innerBlocksProps = useInnerBlocksProps(
            blockProps,
    		{ template: MC_TEMPLATE },
    	);
    
    	return (
    		<div { ...innerBlocksProps } />
    	);
    
    }

    Source:

    • https://learn.wordpress.org/lesson/work-with-the-innerblocks-component/
    • https://make.wordpress.org/core/2021/12/28/take-more-control-over-inner-block-areas-as-a-block-developer/
    • https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/nested-blocks-inner-blocks/
  • block: RichText edition

    # block
    August 13, 2024
    Read more

    With an attribute in block.json as attributes: { foo: { type: string, default: bar } }

    In edit.js :

    import { useBlockProps, RichText } from '@wordpress/block-editor';
    
    export default function Edit( { attributes, setAttributes } ) {
    	const blockProps = useBlockProps();
    
    	return (
    		<RichText
    			{ ...useBlockProps() }
    			tagName="p"
    			onChange={ val => setAttributes( { foo: val } ) }
    			value={ attributes.content }
    			placeholder="Enter some text here..."
    		/>
    	);
    }

    In render.php

    echo attributes['foo'];

    Sources:

    • https://learn.wordpress.org/lesson/make-the-block-interactive/
    • https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/heading/block.json
  • block: setting sidebar options

    # block
    August 13, 2024
    Read more

    in block.json:

    { ...
      "attributes": {
        "foo": {
          "type": "string",
          "default": "bar"
        }
      }
    }

    in render.php, the data is accessible simply with echo $attributes['foo'];

    In edit.js

    import { TextControl, Panel, PanelBody } from '@wordpress/components';
    import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
    
    export default function Edit( { attributes, setAttributes } ) {
    	const blockProps = useBlockProps();
    
    	return (
    		<p { ...blockProps }>
    			<InspectorControls key="setting">
    				<Panel>
    					<PanelBody title="Champs" initialOpen={true}>
    						<TextControl className="blocks-base-control__input"
    							label={"Foo"}
    							value={attributes.foo}
    							onChange={(val) => setAttributes({foo: val})}
    						/>
    					</PanelBody>
    				</Panel>
    			</InspectorControls>
    			{ attributes.heading }
    		</p>
    	);
    }

    Adding toggle button, for an attribute defined as { foo: { type: "boolean", default: true } }

     <ToggleControl
        label="Toggle Content"
        checked={ showContent }
        onChange={ (newValue) => setAttributes( { foo: newValue } )  }
    />

    A range button :

    <InspectorControls>
        <PanelBody>
            <RangeControl
                label="Columns"
                value={ columnCount }
                onChange={ onChangeColumnCount }
                min={ 2 }
                max={ 6 }
             />
       </PanelBody>
    </InspectorControls>

    NB: To extend useBlockProps hooks, just send new data as parameter:

    { ...useBlockProps( { style: columnStyles } ) }

    Sources:

    • https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/heading/block.json
    • https://learn.wordpress.org/lesson/create-custom-inspector-panel-controls/
    • Color Panel : https://learn.wordpress.org/lesson/add-configuration-options-for-the-style-variations/
  • Create a new block

    # block
    November 14, 2024
    Read more

    npx @wordpress/create-block@latest blockname --template @wordpress/create-block-interactive-template

    Some other options :

    npx @wordpress/create-block@latest blockname --variant dynamic
    npx @wordpress/create-block@latest blockname --variant dynamic --template es5 → no node module, great for simple block, remove –variant for a static one.

    To register the block : register_block_type( ${path of directory containing the block.json} );

    In case of several block, optional but perfomance improving : wp_register_block_metadata_collection( $path, $manifest );

    To generate a manifest : wp-scripts build-blocks-manifest

    Sources:

    • https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/
    • https://make.wordpress.org/core/2024/10/17/new-block-type-registration-apis-to-improve-performance-in-wordpress-6-7/
  • API binding

    # block
    August 14, 2024
    Read more

    Populate dynamically blocks (button, image, paragraph and heading), by setting the source, from meta field or php logic.

    meta field

    <!-- wp:paragraph {
    	"metadata":{
    		"bindings":{
    			"content":{
    				"source":"core/post-meta",
    				"args":{
    					"key":"book-genre"
    				}
    			}
    		}
    	}
    } -->
    <p></p>
    <!-- /wp:paragraph -->
    register_meta(
        'post',
        'book-genre',
        array(
            'show_in_rest' => true,
            'single'       => true,
            'type'         => 'string',
            'default'      => 'Default text field',
        )
    );

    php logic

    $source_name = 'namespace/name';
    $source_properties = array(
    	'label'	=> 'Name',
    	'get_value_callback' => 'fn',
    	'uses_context' => ['postId']
    );
    
    register_block_bindings_source(
    	string $source_name,
    	array $source_properties
    );
    
    projectslug_bindings_callback(
    	array $source_args, 
    	WP_Block $block_instance, 
    	string $attribute_name
    );

    Source: https://make.wordpress.org/core/2024/03/06/new-feature-the-block-bindings-api/

  • Block variations

    # block, js
    Read more

    Block styles: create specific look variations with CSS

    Block variations: preset a block configuration.

    Example:

    wp.blocks.registerBlockVariation(
    	'core/quote',
    	{
    		name: 'dev-name',
    		title: 'Title',
    		icon: 'format-status',
    		isDefault: true,
    		attributes: {
    			templateLock: 'all',
    			className: 'dev-classname'
    		},
    		innerBlocks: [
    			[
    				'core/image',
    				{
    					className: 'wp-block-image alignleft'
    				}
    			],
    			[
    				'core/paragraph',
    				{
    					className: 'dev-paragraph'
    				}
    			]
    		]
    	}
    );

    Source:

    • https://fullsiteediting.com/lessons/block-variations/
    • https://developer.wordpress.org/block-editor/reference-guides/block-api/block-variations/
    • https://developer.wordpress.org/news/2023/08/29/an-introduction-to-block-variations/
  • Override blocks style

    # block, block_style, css
    March 12, 2024
    Read more

    To override block styles for rules that can’t be changed through theme.json (complexe rules or non core blocks) , one can use dev__blocks__enqueue_styles function:

    add_action( 'init', 'dev__blocks__enqueue_styles' );
    
    function dev__blocks__enqueue_styles() {
    	foreach ( glob( get_stylesheet_directory() . '/assets/css/blocks-overriding/*', GLOB_ONLYDIR ) as $directory) {
    		$namespace = substr( strrchr( $directory, '/' ), 1 );
    		foreach ( glob( $directory . '/*.css' ) as $file) {
    			$filename = pathinfo( $file, PATHINFO_FILENAME );
    			wp_enqueue_block_style(
    				$namespace . '/' . $filename,
    				array(
    					'handle'	=> 'dw-override--' . $namespace . '-' . $filename,
    					'src'		=> get_stylesheet_directory_uri() . '/assets/css/blocks-overriding/' . $namespace . '/' . $filename . '.css',
    					'path'		=> get_stylesheet_directory() . '/assets/css/blocks-overriding/' . $namespace . '/' . $filename . '.css',
    					'ver'		=> filemtime( get_stylesheet_directory() . '/assets/css/blocks-overriding/' . $namespace . '/' . $filename . '.css' )
    				)
    			);
    		}
    	}
    }

    Source : https://developer.wordpress.org/reference/functions/wp_enqueue_block_style/

  • Dynamically generate a block

    # block
    August 23, 2023
    Read more
    $block = array(
    	'blockName'	=> 'dev/blockname',
    	'attrs' => array(
    		'name'	=> 'dev/blockname',
    		'data'	=> array(
    			'ACF__field' => get_field( 'ACF__field' )
    		)
    	),
    );
    $html_output = render_block($block);

    To know what data send as parameter for the $block object, one can use the render_block filter

    add_filter( 'render_block', 'dev__paragraph_add_block', 10, 2 );
    function dev__paragraph_add_block( $block_content, $block ){
    
    	if ( 'dw/icon' === $block['blockName'] ){
    		echo '<pre>';
    		var_dump($block);
    		echo '</pre>';
    	}
    
    	return $block_content;
    
    }

    Source : https://www.itsupportguides.com/knowledge-base/wordpress/using-wordpress-render_block-php-function/

  • block supports properties

    # ACF, block
    August 23, 2023
    Read more

    To use the supports properties, first enable them in the block.json.

    {
    	"$schema": "https://schemas.wp.org/trunk/block.json",
    	"apiVersion": 3,
    	
     ...
    
    	"supports": {
    		"color": {
    			"text": true,
    			"background": true
    		}
    	},
    	"acf": {
    		"mode": "preview",
    		"renderTemplate": "./render.php"
    	}
    }

    Then in render.php :

    <?php
    
    $classes = array();
    
    if ( ! empty( $block['textColor'] ) ) {
    //	$classes = array_merge( $classes, explode( ' ', $block['className'] ) );
    	$classes[] = 'has-text-color';
    	$classes[] = 'has-' . $block['textColor'] . '-color';
    }
    
    echo '<div class="' . esc_attr( join( ' ', $classes ) ) . '"></div>';

    Or simply use the function get_block_wrapper_attributes( string[] $extra_attributes = array() ): string for e.g. to get the classes :

    preg_match( '/class="(.*?)"/', get_block_wrapper_attributes(), $matches);
    classes = $matches[1];

    Sources:

    • https://www.billerickson.net/color-palette-with-acf-custom-blocks/
    • https://www.billerickson.net/building-acf-blocks-with-block-json/#custom-prefixes-in-block-name
    • https://www.modernwpdev.co/acf-blocks/acf-block-controls/
  • Block rendering filter

    # block, hook, wp function
    March 15, 2024
    Read more
    add_filter( 'render_block', 'dev__paragraph_add_block', 10, 2 );
    
    function dev__paragraph_add_block( $block_content, $block ){
    
    	if ( 'core/paragraph' === $block['blockName'] ){
    		$block_content = new WP_HTML_Tag_Processor( $block_content );
            $block_content->next_tag(); /* first tag should always be ul or ol */
            $block_content->add_class( 'wp-block-paragraph' );
            $block_content->get_updated_html();
    	}
    
    	return $block_content;
    
    }
  • InnerBlock

    # ACF, block
    August 22, 2023
    Read more

    Interesting attributes : allowedBlocks, template, InnerBlocks.

    Example of a devblock/render.php

    <?php
    
    $classes_container = array( 'block__container' );
    $classes_innerblock = array( 'block__innerblock' );
    
    if ( !empty( $block['className'] ) ){
    	$classes_root = array_merge( $classes_root, explode( ' ', $block['className'] ) );
    }
    
    $allowed_blocks = array( 'namespace/blockname' );
    
    $template = array(
    	array(
    		'namespace/blockname',
    		array(
    			'className'		=> 'some-class'
    		)
    	)
    );
    
    ?>
    
    <div class="<?php echo join( ' ', $classes_container ); ?>">
    	<InnerBlocks
    		class="<?php echo join( ' ', $classes_innerblock ); ?>"
    		allowedBlocks="<?php echo esc_attr( wp_json_encode( $allowed_blocks ) ); ?>"
    		template="<?php echo esc_attr( wp_json_encode( $template ) ); ?>" />
    
    </div>
    
  • Creating a block with ACF

    # ACF, block
    March 20, 2025
    Read more

    Prototype:register_block_type( string|WP_Block_Type $block_type, array $args = array() ): WP_Block_Type|false

    add_action( 'init', 'dev__register_blocks', 5 );
    
    function dev__register_blocks() {
    	register_block_type( __DIR__ . '/some_block_dir' );
    }

    The block.json file :

    {
        "$schema": "https://schemas.wp.org/trunk/block.json",
        "apiVersion": 3,
        "name": "namespace/blockname",
        "title": "Notice",
        "category": "text",
        "parent": [ "core/group" ],
        "icon": "star",
        "description": "Shows warning, error or success notices...",
        "keywords": [ "alert", "message" ],
        "version": "1.0.3",
        "textdomain": "my-plugin",
        "editorScript": "file:./index.js",
        "script": "file:./script.js",
        "viewScript": [ "file:./view.js", "example-shared-view-script" ],
        "editorStyle": "file:./index.css",
        "style": [ "file:./style.css", "example-shared-style" ],
        "render": "file:./render.php",
    	"supports": {
    		"className": true,
    		"customClassName": true,
    		"jsx": true			// to use innerBlocks,
    		"inserter": true	// will be accessible only programatically
    	},
    
    	// ACF options: 
    	"acf": {
    		"mode": "preview",
    		"renderTemplate": "render.php"
    	},
    
    	"example": { "attributes": { "mode": "preview" } }
    
    
    }
    

    Sources:

    • https://developer.wordpress.org/reference/functions/register_block_type/
    • https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/
    • https://www.advancedcustomfields.com/resources/acf-blocks-with-block-json/#acf-configuration-key
    • https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/
WP_DEBUG

WP_DEBUG

  • GitHub