Snippets – WordPress Developer Blog https://developer.wordpress.org/news A site for plugin and theme developers, freelancers, and agency developers Fri, 20 Dec 2024 22:18:36 +0000 en-US hourly 1 https://wordpress.org/?v=6.8-alpha-59827 https://s.w.org/favicon.ico?2 Snippets – WordPress Developer Blog https://developer.wordpress.org/news 32 32 208500394 Snippet: How to register a block variation but hide it from the inserter https://developer.wordpress.org/news/snippets/snippet-how-to-register-a-block-variation-but-hide-it-from-the-inserter/ https://developer.wordpress.org/news/snippets/snippet-how-to-register-a-block-variation-but-hide-it-from-the-inserter/#respond Wed, 18 Dec 2024 15:26:33 +0000 https://developer.wordpress.org/news/?post_type=snippets&p=4857 When defining a custom block, the inserter property in block.json can be used to control if the block is available to be inserted by the user or if it can only be added programmatically.

In some cases, a custom block is overkill, and a block variation is a better solution. For example, a user in the outreach channel wanted to add an attribute to a block that was only used in a template and, based on the existence of that attribute, add some custom functionality.

This is a perfect scenario to use a block variation. The issue was that they couldn’t hide the variation from the inserter.

After some digging, it is possible to hide the block by setting the scope property to block in registerBlockVariation. The following code registers the paragraph-red block variation for the Paragraph block, but it’s not available to users in the Editor.

import { registerBlockVariation } from '@wordpress/blocks';

registerBlockVariation( 'core/paragraph', {
	name: 'paragraph-red',
	title: 'Red Paragraph',
	attributes: {
		textColor: 'vivid-red',
	},
	isActive: [ 'textColor' ],
	scope: [ 'block' ],
} );

This value is used for blocks like the Columns and Query blocks to filter specific block variations. These variations are passed to the experimental BlockVariationPickercomponent which handles displaying the variations and allows users to choose one of them. For variations of other blocks, the scope property is a great workaround to hide them from the inserter.

Relevant links

Props to @ndiego and @greenshady for reviewing this snippet

]]>
https://developer.wordpress.org/news/snippets/snippet-how-to-register-a-block-variation-but-hide-it-from-the-inserter/feed/ 0 4857
Snippet: How to filter the output of a block binding https://developer.wordpress.org/news/snippets/how-to-filter-the-output-of-a-block-binding/ https://developer.wordpress.org/news/snippets/how-to-filter-the-output-of-a-block-binding/#comments Tue, 17 Dec 2024 20:18:35 +0000 https://developer.wordpress.org/news/?post_type=snippets&p=4850 WordPress Block Bindings API provides a powerful way to connect block content with dynamic data sources. While bindings themselves are useful, sometimes you need to modify their output. Using the block_bindings_source_value filter, you can transform the data before it’s displayed on the front end.

Consider a scenario where you have a custom post type called book and need to store the price for each book as post meta. The price will be stored in US dollars, but you want to give users the ability to view prices in different currencies. By adding a query parameter to the URL (like ?currency=EUR), users can dynamically switch between US dollars, Euros, and British pounds. Let’s walk through how to implement this using block bindings.

First, register the post meta using register_post_meta() to make it available to blocks in the Editor:

add_action( 'init', function() {
    register_post_meta(
        'book',
        'book_price',
        array(
            'show_in_rest'      => true,
            'single'            => true,
            'type'              => 'string',
            'label'             => __( 'Book Price', 'text-domain' ),
            'description'       => __( 'Book price in USD', 'text-domain' ),
            'sanitize_callback' => 'wp_strip_all_tags',
        )
    );
} );

Next, you can use the block_bindings_source_value filter to intercept the price value when it’s displayed and convert it based on a query parameter. For instance, a URL with ?currency=GBP will automatically display the price in British pounds. The binding can be added to any block that supports content, like a Paragraph block, using the core/post-meta source.

add_filter( 'block_bindings_source_value', function( $value, $source, $args ) {
    // Only process if the source and key are correct.
    if ( 'core/post-meta' !== $source || 'book_price' !== $args['key'] ) {
        return $value;
    }

    // Get currency from query parameter (e.g., ?currency=EUR).
    $currency = isset( $_GET['currency'] ) ? sanitize_text_field( wp_unslash( $_GET['currency'] ) ) : 'USD';
    
    // Base price in USD.
    $price = floatval( $value );
    
    // Conversion rates (you might want to use a real API for live rates).
    $conversion_rates = array(
        'EUR' => 0.92, // 1 USD = 0.92 EUR
        'GBP' => 0.79, // 1 USD = 0.79 GBP
        'USD' => 1.00,
    );
    
    // Convert price.
    $converted_price = $price * ( isset( $conversion_rates[ $currency ] ) ? $conversion_rates[ $currency ] : 1 );
    
    // Format price with currency symbol.
    $currency_symbols = array(
        'EUR' => '€',
        'GBP' => '£',
        'USD' => '$',
    );
    
    $symbol = isset( $currency_symbols[ $currency ] ) ? $currency_symbols[ $currency ] : '$';
    
    // Format the price with 2 decimal places.
    return sprintf( '%s%.2f', $symbol, $converted_price );
}, 10, 3 );

Here’s a quick demonstration of how to use this new functionality:

This approach gives you a flexible way to modify block binding output based on user input or other parameters. While this example uses hardcoded conversion rates, you could easily extend it to use a currency conversion API for live rates.

If you are interested in learning more about the Block Bindings API, here are several articles to get you started:

Props to @greenshady, @welcher, and @santosguillamot for reviewing this post.

]]>
https://developer.wordpress.org/news/snippets/how-to-filter-the-output-of-a-block-binding/feed/ 2 4850
Snippet: How to lock WordPress blocks and prevent unlocking https://developer.wordpress.org/news/snippets/how-to-lock-wordpress-blocks-and-prevent-unlocking/ https://developer.wordpress.org/news/snippets/how-to-lock-wordpress-blocks-and-prevent-unlocking/#respond Mon, 09 Dec 2024 18:03:42 +0000 https://developer.wordpress.org/news/?post_type=snippets&p=4823 The Block Locking API in WordPress allows developers to control block editing by restricting movement and removal. This API is ideal for maintaining design consistency in templates and patterns while still allowing users to customize other elements of the content.

Locking blocks

As the image above shows, you can lock blocks directly through the Editor’s user interface (UI). However, you can also lock blocks programmatically using the lock attribute in the block’s markup. For example:

<!-- wp:paragraph {"lock":{"move":true,"remove":true}} -->
    <p>This Paragraph block is locked and cannot be moved or deleted.</p>
<!-- /wp:paragraph -->

In this markup, move: true prevents the block from being moved, and remove: true stops it from being deleted. This method is particularly useful when building templates and patterns in a theme or plugin.

Preventing unlocking

While the Block Locking API is useful for ensuring design consistency, any user can lock and unlock blocks by default, which may not always be desirable. The canLockBlocks setting in the Editor controls this functionality.

You can disable the UI for locking and unlocking globally by setting canLockBlocks to false using the block_editor_settings_all PHP filter:

add_filter( 'block_editor_settings_all', function( $settings, $context ) {
    $settings['canLockBlocks'] = false; // Disable locking/unlocking for all users

    return $settings;
}, 10, 2 );

If you want more control, such as only preventing non-administrators from unlocking blocks while editing posts, you can add conditional logic:

add_filter( 'block_editor_settings_all', function( $settings, $context ) {
    if ( 
        isset( $context->post ) && 
        'post' === $context->post->post_type && 
        ! current_user_can( 'edit_theme_options' ) 
    ) {
        $settings['canLockBlocks'] = false; // Disable locking/unlocking for non-administrators editing posts
    }

    return $settings;
}, 10, 2 );

Here’s an explanation of the conditionals:

  • $context->post: Ensures the filter is running in the context of a specific post. This code is not designed for the Site Editor.
  • 'post' === $context->post->post_type: Limits the restriction to the post post type.
  • ! current_user_can( 'edit_theme_options' ): Checks if the current user does not have the edit_theme_options capability, which only administrators have by default.

Disabling the Code Editor

While setting canLockBlocks to false disables the locking UI, users could still technically open the Code Editor and remove the lock attribute from locked blocks. You can also disable the Code Editor using the codeEditingEnabled setting to prevent this.

add_filter( 'block_editor_settings_all', function( $settings, $context ) {
    if ( 
        isset( $context->post ) && 
        'post' === $context->post->post_type && 
        ! current_user_can( 'edit_theme_options' ) 
    ) {
        $settings['canLockBlocks'] = false; // Disable locking/unlocking for non-administrators editing posts.
        $settings[ 'codeEditingEnabled' ] = false; // Disable access to the Code Editor.    
    }

    return $settings;
}, 10, 2 );

Add the code to your theme’s functions.php file or a custom plugin to use this snippet.

Additional resources

Props to @bph and @welcher for reviewing this snippet and providing feedback.

]]>
https://developer.wordpress.org/news/snippets/how-to-lock-wordpress-blocks-and-prevent-unlocking/feed/ 0 4823
Snippet: How to disable the Font Library https://developer.wordpress.org/news/snippets/how-to-disable-the-font-library/ https://developer.wordpress.org/news/snippets/how-to-disable-the-font-library/#respond Wed, 27 Nov 2024 17:53:36 +0000 https://developer.wordpress.org/news/?post_type=snippets&p=4744 As a theme author, I often want tight control over typography options to offer users a curated set of fonts that work well for the theme. One of the first things I do is disable the Font Library in WordPress, ensuring that only the typesets I specifically chose are available to users. This completely disables the user’s ability to upload or manage custom fonts.

Whether it’s for a client site or a publicly distributed project, you might run into a similar scenario when designing a theme. To disable the Font Library, you can filter block_editor_settings_all and set the fontLibraryEnabled argument to false by adding this code to your theme’s functions.php file:

add_filter( 'block_editor_settings_all', 'devblog_block_editor_settings' );

function devblog_block_editor_settings( $settings ) {
	$settings['fontLibraryEnabled'] = false;

	return $settings;
}

Check out 15 ways to curate the WordPress editing experience for more techniques to customize the Editor.

Props to @psykro and @welcher for feedback and review.

]]>
https://developer.wordpress.org/news/snippets/how-to-disable-the-font-library/feed/ 0 4744
Snippet: How to disable heading levels in the Editor https://developer.wordpress.org/news/snippets/how-to-disable-heading-levels-in-the-editor/ https://developer.wordpress.org/news/snippets/how-to-disable-heading-levels-in-the-editor/#respond Fri, 15 Nov 2024 15:46:50 +0000 https://developer.wordpress.org/news/?post_type=snippets&p=4727 As of WordPress 6.7, core WordPress blocks with a heading level dropdown include support for the levelOptions attribute. This applies to the Heading, Site Title, Site Tagline, Query Title, Post Title, and Comments Title blocks. The levelOptions attribute accepts an array of numbers corresponding to heading levels, where 1 represents H1, 2 represents H2, and so on.

This attribute allows you to specify which heading levels should appear in the dropdown UI, providing a lightweight curation method that does not require block deprecations. Any existing heading levels are preserved in the markup, while `levelOptions` only affects the UI display.

In the following code snippet, H1, H5, and H6 heading levels are disabled in the Heading block for all users except those with the edit_theme_options capability (typically Administrators). This approach helps prevent content creators from unintentionally adding multiple H1 elements or applying specific heading levels not intended for use.

<?php

function devblog_modify_heading_levels_globally( $args, $block_type ) {

    // Check if the current user is an Administrator.
    $is_administrator = current_user_can( 'edit_theme_options' );

    // Only proceed if the current block is a Heading and the user is not an Administrator.
    if ( 'core/heading' !== $block_type || $is_administrator ) {
        return $args;
    }

    // Disable H1, H5, and H6.
    $args['attributes']['levelOptions']['default'] = [ 2, 3, 4 ];

    return $args;
}
add_filter( 'register_block_type_args', 'devblog_modify_heading_levels_globally', 10, 2 );

You can add this code to your theme’s functions.php file or a custom plugin. Once applied, here’s what the end result looks like in the Editor.

Props to @areziaal and @bph for reviewing this snippet and providing feedback.

]]>
https://developer.wordpress.org/news/snippets/how-to-disable-heading-levels-in-the-editor/feed/ 0 4727
Snippet: Conditionally unregister patterns https://developer.wordpress.org/news/snippets/conditionally-unregister-patterns/ https://developer.wordpress.org/news/snippets/conditionally-unregister-patterns/#comments Tue, 22 Oct 2024 14:50:29 +0000 https://developer.wordpress.org/news/?post_type=snippets&p=4596 Have you ever run into a situation where you needed to unregister a block pattern in your theme? There may be many scenarios where you’d do this, but one of my primary reasons is to hide the “Your site doesn’t include support for the [Block Name] block” message from users when a pattern contains an unregistered block.

Use this PHP snippet to unregister patterns when specific blocks are unavailable. Just add the block names you want to test against as keys for the $maybe_unregister array with the pattern slugs as the values.

add_action( 'init', 'devblog_unregister_patterns', 999 );

function devblog_unregister_patterns() {
	$blocks = WP_Block_Type_Registry::get_instance();

	$maybe_unregister = [
		'core/table-of-contents' => [
			'pattern-slug-1'
			'pattern-slug-2'
		],
		'pluginslug/block-name'  => [
			'pattern-slug-3'
		]
	];

	foreach ( $maybe_unregister as $block => $patterns ) {
		if ( ! $blocks->is_registered( $block ) ) {
			foreach ( $patterns as $pattern ) {
				unregister_block_pattern( $pattern );
			}
		}
	}
}

Relevant links

Props to @ndiego and @welcher for review.

]]>
https://developer.wordpress.org/news/snippets/conditionally-unregister-patterns/feed/ 2 4596