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)

  • update_field

    # ACF
    Read more

    Prototype: update_field($selector, $value, [$post_id]);

    Note: to update a date field, the data has to be formatted first (even in case of copying the data from a date field).

    $date_from = get_field( 'old_field', $old_post_id );
    $date = DateTime::createFromFormat( 'd/m/Y', $date_from);
    $date = $date->format( 'Ymd' );
    
    update_field('new_field', $date, $new_post_id);

    Source : https://www.advancedcustomfields.com/resources/update_field/

  • Custom css variables

    # css, theme.json
    August 4, 2023
    Read more
    {
        "version": 2,
        "settings": {
            "custom": {
                "line-height": {
                    "body": 1.7,
                    "heading": 1.3
                }
            }
        }
    }

    will be accessible in css --wp--custom--line-height--body

    Note: the custom property can be add into a block, thus enabling overriding.

    Sources :

    • https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/#css-custom-properties-presets-custom
    • https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/#custom
  • 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;
    
    }
  • breakpoints

    # css, responsive
    March 12, 2024
    Read more
    // Most used breakpoints
    
    $break-xhuge:		1920px;
    $break-huge:		1440px;
    $break-wide:		1280px;
    $break-xlarge:		1080px;
    $break-large:		960px;	// admin sidebar auto folds
    $break-medium:		782px;	// adminbar goes big
    $break-small:		600px;
    $break-mobile:		480px;
    $break-zoomed-in:	280px;

    Source : https://github.com/WordPress/gutenberg/blob/trunk/packages/base-styles/_breakpoints.scss

  • Spacing

    # conventions, readmore, spacing, theme
    August 3, 2023
    Read more
    {
    	"$schema": "https://schemas.wp.org/trunk/theme.json",
    	"version": 2,
    	"settings": {
    		"spacing": {
    			"spacingScale": {
    				"operator": "+",
    				"increment": 0.25,
    				"steps": 7,
    				"mediumStep": 1,
    				"unit": "rem"
    			}
    		}
    	}
    }

    Ressources : https://developer.wordpress.org/news/2023/03/everything-you-need-to-know-about-spacing-in-block-themes/#customizing-the-spacing-scale

  • Colors conventions

    # colors, conventions, theme.json
    August 23, 2023
    Read more

    Couleurs primaires

    Construites à partir des deux / trois grandes couleurs de la marque, elles sont utilisées pour marquer l’identité dans des composants qui véhiculent l’image de la marque ou sur lesquels il est nécessaire d’attirer l’attention de l’utilisateur, tels que les éléments cliquables ou les états actifs.

    Couleurs système

    Couleurs utilisées exclusivement pour représenter des états et des statuts.

    Couleurs neutres

    Couleurs de base utilisées dans les typographies, fonds, contours et séparateurs dans la majorité des composants. Elles sont notamment utilisées dans les éléments non cliquables et pour représenter les états inactifs.

    Couleurs illustratives

    Couleurs complémentaires de la charte.

    –variations

    lightness

    from 0 (white) to 1000 (black)

    state

    –hover
    –active

    Examples:

    // couleurs primaires
    primary : primary--525
      primary--100
      primary--200
      ...
    secondary
    tertiary
    
    
    // couleurs neutres
    neutral
      neutral--100  : #fff
      ...
      neutral--1000 : #000
    
    
    // couleurs système
    info
    success
    warning
    error
    
    text           : neutral--100
    text-inverted  : neutral--1000
    
    background     : neutral--950
    
    // already outdated
    accent ? highlight ?
    base     ? -> background
    contrast ? -> main text color

    Source :

    • https://github.com/WordPress/gutenberg/issues/29568
    • https://richtabor.com/standardizing-theme-json-colors/
    • https://www.systeme-de-design.gouv.fr/a-propos/articles/refonte-du-systeme-de-couleur/
    • https://www.systeme-de-design.gouv.fr/elements-d-interface/fondamentaux-de-l-identite-de-l-etat/couleurs-palette/
    • https://spectrum.adobe.com/page/color-system/
    • https://bootcamp.uxdesign.cc/simple-design-tokens-with-css-custom-properties-7ab69b71d8ad
  • 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/
  • Input / output

    # security
    July 15, 2023
    Read more

    Never trust user’s inputs, even from admin or database.

    Validation checks an input over a list of requirements.

    in_array( mixed $needle, array $haystack, bool $strict = false ): bool
    ctype_alnum( mixed $text ): bool
    strlen( string $string ): int
    ...

    https://developer.wordpress.org/apis/security/data-validation/

    Sanitizing cleans a input, removing / transforming all unwanted piece of data.

    // For text inputs:
    sanitize_text_field( string $str ): string 
    
    // Use specific sanitazing functions like for e.g.:
    sanitize_email( string $email ): string

    https://developer.wordpress.org/apis/security/sanitizing/

    Escaping ouputs is the process of securing output data by stripping out unwanted data. It is best to do the output escaping as late as possible, ideally as data is being outputted.

    esc_html( string $text ): string // will remove HTML tags
    esc_url( string $url, string[] $protocols = null, string $_context = 'display' ): string
    esc_attr( string $text ): string
    esc_js( string $text ): string
    
    // escaping with localization
    esc_html_e( 'Hello World', 'text_domain' );
    // can become ->
    echo esc_html( __( 'Hello World', 'text_domain' ) );

    https://developer.wordpress.org/apis/security/escaping/

    Source: https://developer.wordpress.org/apis/security/common-vulnerabilities/

  • Force SSL admin connection

    # security, wp-config.php
    July 18, 2023
    Read more
    define( ‘FORCE_SSL_ADMIN’, true );
  • Disallow file editing

    # security, wp-config.php
    Read more
    define( 'DISALLOW_FILE_EDIT', true );
  • Get and set the environment state

    # debug, wp-config.php
    July 21, 2023
    Read more

    With wp_get_environment_type(): string one can get the current state of the project. It returns production by default, otherwise local, development or staging can be used.

    It can be set in the wp-config.php file as :

    define( 'WP_ENVIRONMENT_TYPE', 'development' );

    Sources :

    • https://developer.wordpress.org/reference/functions/wp_get_environment_type/
    • https://make.wordpress.org/core/2020/07/24/new-wp_get_environment_type-function-in-wordpress-5-5/
  • REST API /users/

    # functions.php, security
    July 13, 2023
    Read more

    To enumerate users :

    curl -L http://$1/wp-json/wp/v2/users

    To prevent this :

    add_filter( 'rest_endpoints', function( $endpoints ) {
    
        if ( isset( $endpoints['/wp/v2/users'] ) ) {
            unset( $endpoints['/wp/v2/users'] );
        }
    
    	if ( isset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] ) ) {
            unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
        }
    
    	return $endpoints;
    
    });
  • Variables from WP to JS files

    # functions.php, js
    July 15, 2023
    Read more

    Server side :

    add_action('wp_enqueue_scripts', 'load_scripts');
    
    function load_scripts (){
    
    	$data = array(
    		'siteURL' => site_url()
    	);
    	$data_inline = 'const wpData = ' . json_encode( $data );
    
    	$handle = 'jsfile';
    
    	wp_enqueue_script(
    		$handle,
    		get_stylesheet_directory_uri() . '/assets/js/script.js',
    		array(),
    		filemtime( get_stylesheet_directory() . '/assets/js/script.js' ),
    		true
    	);
    
    	wp_add_inline_script( $handle, $data_inline );
    
    }

    Client side :

    const siteURL = wpData.siteURL;
  • Using ajax

    # ajax
    June 1, 2024
    Read more

    Server side :

    function fn(){
    
    	header( 'Content-Type: application/json; charset=utf-8' );
    	echo json_encode( 'some response' );
    
    	// don't forget this one below :
    	exit();
    
    }
    
    add_action( 'wp_ajax_actionname', 'fn' );
    // add below for unlogged user add
    add_action( 'wp_ajax_nopriv_actionname', 'fn' );

    Client side :

    const url = siteURL + '/wp-admin/admin-ajax.php?action=actionname';
    
    fetch(url)
    	.then(response => response.json())
    	.then(result => console.log(result));
  • Context in translation

    # i18n
    July 5, 2023
    Read more

    Prototype:

    _x( string $text, string $context, string $domain = 'default' ): string

    Quite a few times, there will be collisions with similar translatable text found in more than two places, but with different translated context.

    By including the context in the pot file, translators can translate the two strings differently.

    Example:

    _x( 'T', 'Tuesday', 'text-domain');
    _x( 'T', 'Thursday', 'text-domain');

    source : https://developer.wordpress.org/reference/functions/_x/

  • wp i18n

    # i18n, wp cli
    November 25, 2024
    Read more

    Note: check for updatedl10n.php and wp i18n make-php command → https://make.wordpress.org/core/2024/02/27/i18n-improvements-6-5-performant-translations/

    Used to generate translations from __('string to translate', 'text-domain') functions.

    MO files: MO, or Machine Object is a binary data file that contains object data referenced by a program. It is typically used to translate program code, and may be loaded or imported into the GNU gettext program.

    PO files: PO files are the files which contain the actual translations. Each language will have its own PO file, for example, for French there would be a fr.po file, for german there would be a de.po, for American English there might be en-US.po.

    POT file: POT files are the template files for PO files. They will have all the translation strings left empty. A POT file is essentially an empty PO file without the translations, with just the original strings.

    wp i18n make-pot . languages/<file-name>.pot --domain=<domain-name>
    
    wp i18n update-po languages/<file-name>.pot languages/fr_FR.po
    
    wp i18n make-mo languages/<file-name>.po languages/
    
    wp i18n make-php languages/

    It is possible to specify a specific Domain Path in style.css: Defaults to /languages.

    The Text Domain has to be specified in the style.css file.

    The function load_theme_textdomain( $text_domain, $path ); needs to be called with the after_setup_theme hook.

    Sources:

    • https://make.wordpress.org/polyglots/handbook/glossary/
    • https://developer.wordpress.org/cli/commands/i18n/
    • https://developer.wordpress.org/themes/advanced-topics/internationalization/
  • wp cli install

    # wp cli
    July 22, 2024
    Read more

    To install wp cli

    curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
    
    chmod +x wp-cli.phar
    sudo mv wp-cli.phar /usr/local/bin/wp
    
    # test
    wp --info

    source : https://make.wordpress.org/cli/handbook/guides/installing/

  • Block styles variations

    # block_style, functions.php, theme.json
    April 8, 2024
    Read more

    To add a new block style :

    <?php
    
    function dsfr_register_block_styles(){
    
    	register_block_style(
    		'core/paragraph',
    		array(
    			'name' => 'highlight',
    			'label' => 'Mise en avant',
    		)
    	);
    
    }
    
    add_action( 'init', 'dsfr_register_block_styles' );

    The core styles are editable in the theme.json, but not the custom ones.

    {
        "styles": {
            "blocks": {
    	    "core/image": {
    	        "variations": {
    		    "rounded" : {
    		        "border": {
    			    "radius": ".5rem"
    		        }
    		    }
    		}
    	}
    }

    https://fullsiteediting.com/lessons/modifying-block-style-variations-via-theme-json/

  • css in theme.json

    # css, theme.json
    Read more

    For e.g. on sub item of navigation blocks:

    {
    	"styles": {
    		"blocks": {
    			"core/navigation": {
    				"css": "& a > .wp-block-navigation-item__label { opacity: .5 }"
    			}
    		}
    	}
    }
  • Layout

    # layout, theme.json
    July 3, 2023
    Read more

    To set the –wp–style–root–padding

    {
    	"settings": {
    		"useRootPaddingAwareAlignments": true
    	},
    	"styles": {
    		"spacing": {
    			"padding": {
    				"top": "1rem",
    				"right": "1rem",
    				"bottom": "1rem",
    				"left": "1rem"
    			}
    		}
    	}
    }

    To set the layout :

    {
    	"settings": {
    		"layout": {
    			"contentSize": "840px",
    			"wideSize": "1100px"
    		}
    	}
    }
  • Sources

    March 12, 2024
    Read more

    FSE by Carolina Nymark : https://fullsiteediting.com
    Rich Tabor : https://richtabor.com/
    Aurooba : https://aurooba.com/
    WP Documentations : https://developer.wordpress.org/news/

    https://wholesomecode.net

  • filter theme.json

    # hook, theme.json
    March 15, 2024
    Read more

    There is a way to intervene on the generation of the css based on the theme.json file.

    function update_with_dark_theme( $theme_json ){
    
            $dark_theme = json_decode( file_get_contents( get_template_directory() . '/styles/dark.json' ), true );
            return $theme_json->update_with( $dark_theme );
    
    }
    
    add_filter( 'wp_theme_json_data_user', 'dsfr_update_with_dark_theme' );

    It can be used to switch the theme scheme for e.g.

    function dsfr_reload_styles(){
    
    	if ( isset( $_GET['scheme'] ) && $_GET['scheme'] == 'dark' ){
    
    		add_filter( 'wp_theme_json_data_user', 'dsfr_update_with_dark_theme' );
    
    	}
    
    	wp_enqueue_global_styles();
    	remove_action( 'wp_print_styles', 'print_emoji_styles' );
    
    	header( 'Content-type: text/css' );
    	wp_print_styles();
    
    	exit();
    
    }
    
    add_action( 'wp_ajax_dsfr_reload_styles', 'dsfr_reload_styles' );
    add_action( 'wp_ajax_nopriv_dsfr_reload_styles', 'dsfr_reload_styles' );

    Source : https://fullsiteediting.com/lessons/how-to-filter-theme-json-with-php/

  • Set color palette

    # colors, theme.json
    August 1, 2023
    Read more

    In theme.json, hide default color pickers and set a controled ranged colors.

    {
    	...
    	"settings": {
    		"color": {
    			"custom": false,
    			"defaultPalette": false,
    			"customDuotone": false,
    			"customGradient": false,
    			"palette": [
    				{
    					"slug": "dark",
    					"name": "Dark",
    					"color": "#19191A"
    				},
    				{
    					"slug": "bright",
    					"name": "Bright",
    					"color": "#FFFFFF"
    				}
    			]
    		}
    	}
    	...
    }
  • Minimal start up

    # theme.json
    March 13, 2024
    Read more

    Hierarchy

    assets/
     - fonts/
    templates/
     - index.html  
    parts/
     - header.html
    styles/
     - dark.json
    functions.php
    styles.css
    screenshot.png
    theme.json
    
    
  • Font weights

    # theme.json, typo
    October 31, 2024
    Read more

    To set the font weights :

    {
    	"settings": {
    		"typography": {
    			"fontFamilies": [
    				{
    					"fontFamily": "\"Barlow\", sans-serif",
    					"name": "Barlow",
    					"slug": "barlow",
    					"fontFace" : [
    						{
    							"fontFamily": "Barlow",
    							"fontWeight": "400",
    							"src": "file:./assets/fonts/Barlow-Regular-webfont.woff"
    						},
    						{
    							"fontFamily": "Barlow",
    							"fontWeight": "500",
    							"fontStyle": "normal",
    							"src": "file:./assets/fonts/Barlow-Medium-webfont.woff"
    						},
    						{
    							"fontFamily": "Barlow",
    							"fontWeight": "700",
    							"fontStyle": "normal",
    							"src": "file:./assets/fonts/Barlow-Bold-webfont.woff"
    						}
    					]
    				}
    			]
    		}
    	}
    }
    

    Note : reduce a variable font to the required variations: fonttools varLib.instancer ./MyAwesomeVariableFont.ttf wdth=drop opsz=drop wght=300:700

    https://morgan.cugerone.com/blog/how-to-disable-variable-fonts-variation-features-with-open-source-solution

  • Custom post type

    # custom post type, taxonomy
    August 31, 2023
    Read more

    To enable block editing on custom post type :

    function create_post_type (){
        $args = array(
            ...
            'support'			=> array('title', 'thumbnail'),
            'show_in_rest'		=> true,
            ...
        );
        register_post_type('new-cpt-slug', $args);
    }
    add_action('init', 'create_post_type', 9);

    Custom taxonomies :

    $args = array(
    		...
    		'rewrite'				=> array('slug' => 'profil'),
    		'show_in_rest'			=> true,
    	);
    register_taxonomy( 'custom_tax_slug', ['cpt_slug'], [$args] );

    Sources:

    • https://developer.wordpress.org/reference/functions/register_taxonomy/
    • https://developer.wordpress.org/reference/functions/register_post_type/
WP_DEBUG

WP_DEBUG

  • GitHub