admin管理员组

文章数量:1122832

Using an example given here: enter link description here I've successfully been able to restrict the block types available globally or by post type (eg: page). But what I really would like to do is restrict the the block types by page template. I have tried using if ( is_page_template('page-home.php') ) {...} but with no joy. It will be apparant from the code below, but I am using ACF custom blocks. The blocks themselves are working fine. So currently I have the following in my functions.php file:

function my_allowed_block_types( $allowed_blocks, $post ) {
// works on all content
$allowed_blocks = array(
    'core/image',
    'core/paragraph',
    'core/heading',
    'core/list'
);
// works for all pages but too general for what I want to do
if( $post->post_type === 'page' ) {
    $allowed_blocks= array( 
        'acf/homepage'
    );
}
// Intended to restrict to just one block on my homepage template but does not
if ( is_page_template('page-home.php') ) {
    $allowed_blocks= array( 
        'acf/homepage'
    );
}

Using an example given here: enter link description here I've successfully been able to restrict the block types available globally or by post type (eg: page). But what I really would like to do is restrict the the block types by page template. I have tried using if ( is_page_template('page-home.php') ) {...} but with no joy. It will be apparant from the code below, but I am using ACF custom blocks. The blocks themselves are working fine. So currently I have the following in my functions.php file:

function my_allowed_block_types( $allowed_blocks, $post ) {
// works on all content
$allowed_blocks = array(
    'core/image',
    'core/paragraph',
    'core/heading',
    'core/list'
);
// works for all pages but too general for what I want to do
if( $post->post_type === 'page' ) {
    $allowed_blocks= array( 
        'acf/homepage'
    );
}
// Intended to restrict to just one block on my homepage template but does not
if ( is_page_template('page-home.php') ) {
    $allowed_blocks= array( 
        'acf/homepage'
    );
}
Share Improve this question edited Feb 13, 2020 at 7:50 UntitledGraphic asked Feb 13, 2020 at 7:11 UntitledGraphicUntitledGraphic 1831 gold badge2 silver badges9 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 1

Expanding on some of the prior art here. You need to handle the template switch from the js/editor side of things. Here is a a quick snippet I used to solve this issue.

Key Idea: Check for template match, remove all blocks not in whitelist, force unregister. It is important to remove all the non-allowed blocks from the editor prior to unregistering to prevent a bunch of errors. The debounce here could be pushed even higher.

import domReady from '@wordpress/dom-ready';
import { dispatch, subscribe, select } from '@wordpress/data';
import { getBlockTypes, unregisterBlockType } from '@wordpress/blocks'
import { debounce } from 'lodash';

/**
 * Template Updating.
 */
domReady(() => {
  // Get current block list func.
  const getBlockList = () => select('core/block-editor').getBlocks();

  subscribe(
    debounce(() => {
      // Get Blocks.
      const currentBlockList = getBlockList();

      // Get Template.
      const template = select('core/editor').getEditedPostAttribute(
        'template',
      );

      // Set allowed.
      const allowedBlocks = [
        'core/paragraph',
      ];
      
      // Check whatever template.
      if (template === 'template-chapters.php') {
        // Compare current blocks with allowed
        if (currentBlockList.length > 0) {

          // Array of allowed blocks.
          const tmp = currentBlockList.filter(block => {
            return -1 !== allowedBlocks.indexOf(block.name);
          });


          if (tmp.length !== currentBlockList.length && currentBlockList.length > 1) {
            // Remove all offending blocks.
            dispatch('core/block-editor').resetBlocks(tmp);
            return;
          }
        }

        // Proceed to unregister.
        getBlockTypes().forEach( function ( blockType ) {
            if ( allowedBlocks.indexOf( blockType.name ) === -1 ) {
              unregisterBlockType( blockType.name );
            }
        } );
      }
    }, 100)
  );
});

It's theoretically possible but would require reloading the page again because the page template can be changed after the content is initially loaded for editing; unlike a post-type.

(Maybe try to use UpdateSettings to do this although documentation is scarce.

Hey so it is possible to do this, I wrote an article about it. You need to do it on the javascript side using the Gutenberg's data module api.

Here's the code that'll get this up and running for you.

/** main.js **/
import BlockRestrictor from './BlockRestrictor'

/*
 * Add a mapping of block names and what templates they are
 * restricted to.
 */
const blockTemplateRestrictions = {
    'core/code': [
        'template-super-cool.php',
    ],
}

wp.domReady(() => {
    const restrictor = new BlockRestrictor(blockTemplateRestrictions)
    const templateWhitelister = new TemplateWhitelister(blockTemplateRestrictions)

    restrictor.run()
    templateWhitelister.run()
})
const { data } = window.wp
const { select, dispatch, subscribe } = data
const { getEditedPostAttribute } = select('core/editor')
const { isTyping } = select('core/block-editor')
const { getBlockType } = select('core/blocks')
const { addBlockTypes, removeBlockTypes } = dispatch('core/blocks')

class BlockRestrictor {
    /**
     * Currently selected template.
     * @type {string}
     */
    currentTemplate = ''

    /**
     * Map block names to the actual block object.
     *
     * @type {object}
     */
    unregisteredBlocks = {}

    constructor(blockTemplateRestrictions) {
        this.blockTemplateRestrictions = blockTemplateRestrictions
    }

    /**
     * Initiates listening to the redux store for when a restricted block is either
     * added or removed.
     */
    run() {
        this.currentTemplate = getEditedPostAttribute('template') || 'default'

        this.restrictBlocksToTemplate()

        /**
         * subscribe fires whenever the redux store in gutenberg updates
         */
        subscribe(() => {
            /**
             * ensure we don't run our logic when the user is typing.
             */
            if (isTyping() === true) {
                return false
            }

            const newTemplate = getEditedPostAttribute('template') || 'default'

            if (this.currentTemplate !== newTemplate) {
                this.currentTemplate = newTemplate
                this.restrictBlocksToTemplate()
            }
        })
    }

    /**
     * Helps decide which blocks we actually want to add or remove from
     * the store.
     */
    templateBlockRegistry() {
        let blocksToAdd = []
        let blocksToRemove = []

        Object.keys(this.blockTemplateRestrictions).forEach((blockName) => {
            if (this.blockTemplateRestrictions[blockName].includes(this.currentTemplate)) {
                blocksToAdd.push(blockName)
            } else {
                blocksToRemove.push(blockName)
            }
        })

        return {
            blocksToAdd,
            blocksToRemove,
        }
    }

    /**
     * Either removes or adds blocks to the store based on what the current
     * template is.
     */
    restrictBlocksToTemplate() {
        const { blocksToAdd, blocksToRemove } = this.templateBlockRegistry()

        if (blocksToRemove.length) {
            blocksToRemove.forEach((blockName) => {
                const blockExists = getBlockType(blockName)
                const isRegistered = typeof this.unregisteredBlocks[blockName] === 'undefined'
                if (blockExists && isRegistered) {
                    this.unregisteredBlocks[blockName] = getBlockType(blockName)
                }
            })
            removeBlockTypes(Object.keys(this.unregisteredBlocks))
        }

        if (blocksToAdd.length) {
            let registeredBlocks = []
            blocksToAdd.forEach(blockName => {
                const blockExists = typeof getBlockType(blockName) === 'undefined'
                const isUnregistered = typeof this.unregisteredBlocks[blockName] !== 'undefined'

                if (blockExists && isUnregistered) {
                    registeredBlocks.push(this.unregisteredBlocks[blockName])
                    delete this.unregisteredBlocks[blockName]
                }
            })
            addBlockTypes(registeredBlocks)
        }
    }

}

export default BlockRestrictor

Here's a link to the article going into detail on how to restrict blocks based on page templates. How to Restrict Blocks to Specific Page Templates in the WordPress Gutenberg Editor

本文标签: functionsHow to specify which Gutenberg blocks are available in the editor for a page template