一个钩子,掌控区块分类的多种用法

你大概注意到了,WordPress 区块按分类组织。但你知道吗?这些分类并非不可改变,你可以调整它们,让它们更符合自己的需求。

你可以重命名分类、调整顺序,也可以添加全新的分类,包括为自定义区块建立分类。你大概还能想到一些我们尚未考虑的用法。

所有这些,只需要一个钩子:block_categories_all。(block_categories_all)

这个钩子是一项用途广泛的工具,允许开发者自定义区块分类的组织方式。本文将介绍如何使用它,并编写函数添加、重排和重命名单个或多个区块分类。

开始之前要注意:每个示例函数都接受一个参数,预期为现有区块分类数组。本文将它命名为 $categories。

目录

添加分类

如果你构建自定义区块,可能希望把它们放在自定义分类中。自定义分类还可能有其他用途,例如组织具有自定义样式的部分。无论出于什么原因,下面介绍三种做法。

创建新分类

可以使用 array_merge,在现有分类数组的末尾添加名为 Custom Blocks 的新分类。

add_filter( 'block_categories_all', 'add_block_category', 10, 2 );

function add_block_category( $categories ) {
    $custom_category = array(
        array(
            'slug'  => 'custom-blocks',
            'title' => __( 'Custom Blocks', 'your-text-domain' ),
            'icon'  => null,
        ),
    );

    return array_merge( $categories, $custom_category );
}

首先创建接受一个参数的函数;请记住,它接收现有分类列表 $categories。在函数内部创建变量 $custom_category,给它赋予包含以下键值对的数组:

  • slug:分类的唯一标识符。
  • title:分类显示的名称。
  • icon:Dashicon 或自定义 SVG。

注意:据作者所知,目前没有地方使用或显示该图标,因此本例将它设置为 null。

然后用 array_merge 将 $custom_category 与现有分类列表合并。传入变量的顺序决定新分类位于 $categories 之前还是之后。

在区块插入器中添加自定义区块分类后的示例。
在区块插入器中添加自定义区块分类后的示例。

指定新分类的位置

下面使用 array_splice,把名为 Custom Blocks 的新分类插入 $categories 的第二个位置,也就是索引 1。

add_filter( 'block_categories_all', 'add_order_block_category', 10, 2 );

function add_order_block_category( $categories ) {
    $custom_category = array(
        'slug'     => 'custom-blocks',
        'title'    => __( 'Custom Blocks', 'your-text-domain' ),
        'icon'     => null,
        'position' => 1,
    );

    // Extract position from the custom category array.
    $position = $custom_category['position'];

    // Remove position from the custom category array.
    unset( $custom_category['position'] );

    // Insert the custom category at the desired position.
    array_splice( $categories, $position, 0, array( $custom_category ) );

    return $categories;
}

与前例类似,先创建函数和新分类数组。不过这次增加一个 position 键,用它的值指定新分类在 $categories 中的位置。

然后提取位置,将其存入变量,供 array_splice 使用。使用之前,先用 unset 从分类数组中移除 position,因为分类本身不需要它。

最后使用接受四个参数的 array_splice:

  • Array:要修改的数组。
  • Offset:希望插入的位置。
  • Length:偏移位置之后要删除的项目数量。
  • Replacement:要添加到指定位置的元素数组。

调用时传入 $categories、新分类数组指定的位置、删除长度(这里为 0,因为不删除任何内容),最后传入新分类数组。

在区块插入器中添加自定义区块分类,并把它放在 Text 分类下方的示例。
在区块插入器中添加自定义区块分类,并把它放在 Text 分类下方的示例。

一次添加并定位多个新分类

现在同时添加多个分类并安排位置。下面将两个自定义分类分别插入 $categories 的第二和第四个位置。

add_filter( 'block_categories_all', 'add_order_multiple_block_categories', 10, 2 );

function add_order_multiple_block_categories( $categories ) {
    $custom_categories = array(
        array(
            'slug'     => 'custom-category-1',
            'title'    => __( 'Custom Category 1', 'your-text-domain' ),
            'icon'     => null,
            'position' => 1,
        ),
        array(
            'slug'     => 'custom-category-2',
            'title'    => __( 'Custom Category 2', 'your-text-domain' ),
            'icon'     => null,
            'position' => 3,
        ),
    );

    $added_categories = array();

    // Prepare an associative array with positions as keys.
    foreach ( $custom_categories as $custom_category ) {
        $position = $custom_category['position'];
        unset( $custom_category['position'] );
        $added_categories[ $position ] = $custom_category;
    }

    // Sort the categories to insert by their positions/key.
    ksort( $added_categories );

    // Insert the sorted categories into the existing categories array.
    foreach ( $added_categories as $position => $custom_category ) {
        array_splice( $categories, $position, 0, array( $custom_category ) );
    }

    return $categories;
}

创建函数,并在其中建立名为 $custom_categories 的新分类数组,为每个项目指定位置。再创建空数组 $added_categories,用于下一步存储数据。

遍历 $custom_categories,提取并移除每个分类的 position,以新位置为键,将分类存入 $added_categories。然后使用 ksort,确保数组按键排序。

最后通过 foreach 遍历 $added_categories,把分类插入所需位置。原文文字在这里称使用 array_slice,并称最后通过 array_values 重新索引;但上方实际代码使用 array_splice,且没有单独调用 array_values。请以保留的实际示例代码为准。

添加多个自定义区块分类,并分别放在 Media 分类上方与下方的示例。
添加多个自定义区块分类,并分别放在 Media 分类上方与下方的示例。

重排分类

也可以使用 block_categories_all 调整区块编辑器中已有分类列表的顺序。无论移动单个分类还是重新排列多个分类,下面的方法都能提供更细致的控制。(block_categories_all)

重排单个分类

下面从现有数组中移除 Design 分类,再使用 PHP 的 array_splice 将它重新插入第二个位置。

add_filter( 'block_categories_all', 'reorder_design_category', 10, 2 );

function reorder_design_category( $categories ) {
    $design_category = null;
    $new_position    = 1;

    // Remove the design category from the existing categories.
    foreach ( $categories as $key => $category ) {
        if ( 'design' === $category['slug'] ) {
            $design_category = $category;
            unset( $categories[ $key ] );
            break;
        }
    }

    // If the design category exists, insert it at the new position.
    if ( $design_category ) {
        array_splice( $categories, $new_position, 0, array( $design_category ) );
    }

    // Reindex the array.
    return array_values( $categories );
}

在函数中先设置两个变量:$design_category 初始为 null,用于稍后存储 Design 分类或其他待移动分类;另一个变量指定新位置。原文将其称为 $position,示例实际名称是 $new_position。然后用 foreach 遍历已有分类,寻找匹配的 slug,将分类存入 $design_category,并通过 unset 从原列表中移除它。

检查变量是否存入了分类数据,并使用 array_splice 把分类插入目标位置,做法与之前添加分类相同。最后通过 array_values 重新索引,保证数组顺序正确。

将 Design 分类移动到 Text 分类下方的示例。
将 Design 分类移动到 Text 分类下方的示例。

重排多个分类

下面使用 array_splice 移除并重新插入 Design 和 Text 分类,使它们分别位于第一和第四个位置。

<?php
add_filter( 'block_categories_all', 'reorder_multiple_categories', 10, 2 );

function reorder_multiple_categories( $categories ) {
    $reorder_categories = array(
        'design' => 0,
        'text'   => 3,
    );

    $moved_categories = array();

    // Iterate through the existing categories and add/remove the ones to be reordered.
    foreach ( $categories as $key => $category ) {
        if ( array_key_exists( $category['slug'], $reorder_categories ) ) {
            $moved_categories[ $reorder_categories[ $category['slug'] ] ] = $category;
            unset( $categories[ $key ] );
        }
    }

    // Sort the moved categories by their new positions.
    ksort( $moved_categories );

    // Insert the moved categories at their new positions.
    foreach ( $moved_categories as $position => $category ) {
        array_splice( $categories, $position, 0, array( $category ) );
    }

    // Reindex the array.
    $categories = array_values( $categories );

    return $categories;
}

在函数内建立关联数组 $reorder_categories,以待重排分类的 slug 为键,以新位置为值。再创建空数组 $moved_categories,供下一步保存数据。

检查找到匹配分类后,将它放入 $moved_categories,以指定位置为键。unset 会从 $categories 中移除这个分类。

使用 ksort,按键对分类排序。

用 foreach 遍历 $moved_categories,通过 array_splice 将分类插入正确位置。最后使用 array_values 重新索引,让新 $categories 列表保持正确顺序。

将 Design 移到区块插入器顶部,并将 Text 移到 Media 下方第三个位置的示例。原文图注与前文代码的第四位置说明不同,保留其描述。
将 Design 移到区块插入器顶部,并将 Text 移到 Media 下方第三个位置的示例。原文图注与前文代码的第四位置说明不同,保留其描述。

重命名分类

还可以使用 block_categories_all 重命名区块编辑器中的分类列表。无论修改一个还是全部分类,下面的方法都能让你控制名称。(block_categories_all)

重命名单个分类

例如,你希望把 Text 分类改名为 Text Elements。

add_filter( 'block_categories_all', 'rename_text_category', 10, 2 );

function rename_text_category( $categories ) {
    foreach ( $categories as &$category ) {
        if ( $category['slug'] === 'text' ) {
            $category['title'] = __( 'Text Elements', 'your-text-domain' );
        }
    }

    return $categories;
}

用 foreach 遍历 $categories,寻找 slug 等于 text 的分类。找到后,将它的标题改为 Text Elements。

将 Text 分类重命名为 Text Elements 的示例。
将 Text 分类重命名为 Text Elements 的示例。

重命名多个分类

也可以把 Text 与 Media 分类分别改名为 Text Elements 与 Media and Text Elements。

add_filter( 'block_categories_all', 'rename_multiple_categories', 10, 2 );

function rename_multiple_categories( $categories ) {
    foreach ( $categories as &$category ) {
        if ( $category['slug'] === 'text' ) {
            $category['title'] = __( 'Text Elements', 'your-text-domain' );
        }
        if ( $category['slug'] === 'media' ) {
            $category['title'] = __( 'Media and Text Elements', 'your-text-domain' );
        }
    }

    return $categories;
}

在一个函数中重命名多个分类时,步骤与重命名单个分类相同;按需要增加对分类 slug 的检查即可。

将 Text 重命名为 Text Elements,并将 Media 重命名为 Media and Text Elements 的示例。
将 Text 重命名为 Text Elements,并将 Media 重命名为 Media and Text Elements 的示例。

整合所有操作

最后把这些能力整合起来:控制已有分类的名称与位置,同时添加新分类。

add_filter( 'block_categories_all', 'modify_block_categories', 10, 2 );

function modify_block_categories( $categories ) {
    $new_category_order = array(
        array(
            'slug'     => 'media',
            'title'    => __( 'Media and Text Elements', 'your-text-domain' ),
            'position' => 0,
        ),
        array(
            'slug'     => 'custom-blocks',
            'title'    => __( 'Custom Blocks', 'your-text-domain' ),
            'position' => 1,
        ),
        array(
            'slug'     => 'text',
            'title'    => __( 'Text Elements', 'your-text-domain' ),
            'position' => 2,
        ),
        array(
            'slug'     => 'embed',
            'position' => 3,
        ),
        array(
            'slug'     => 'design',
            'position' => 4,
        ),
    );

    // Create an associative array of block categories with the slug as the key.
    $current_block_categories = array_column( $categories, 'title', 'slug' );

    // Check if the new category order has a title set, otherwise use the default title.
    foreach ( $new_category_order as &$new_category ) {
        $new_category['title'] = $new_category['title'] ?? $current_block_categories[ $new_category['slug'] ] ?? __( 'Untitled', 'your-text-domain' );
    }

    // Create an array of slugs from the new category order.
    $new_category_slugs = array_column( $new_category_order, 'slug' );

    // Filter out the remaining block categories that are not in the new order.
    $remaining_categories = array_filter( $categories, function ( $category ) use ( $new_category_slugs ) {
        return ! in_array( $category['slug'], $new_category_slugs, true );
    } );

    // Merge the new category order with the remaining categories.
    return array_merge( $new_category_order, $remaining_categories );
}

首先定义 $new_category_order 数组,列出需要添加、重排或重命名的分类。每项必须有 slug 来标识;原文称 title 和 position 可按修改需求选填。

用 array_column 从 $categories 创建以 slug 为键的关联数组 $current_block_categories。遍历 $new_category_order,检查每项是否已设置新标题。没有设置时,根据 slug 从现有分类中取得标题;如果 slug 也未找到,使用 Untitled。

原文接着描述:遍历 $new_category_order,检查带新位置的分类,以位置为键放入 $moved_categories。不过,上方整合示例并未实现这一段操作。

原文继续描述用 ksort 按位置排序 $moved_categories,再以 foreach 和 array_slice 插入分类;这些步骤同样不在实际整合示例中。该示例直接以 $new_category_order 的数组顺序决定结果顺序,position 字段未用于排序。

接下来过滤剩余分类,以便重新合并。实际代码通过 array_column 创建 slug 数组 $new_category_slugs(原文文字称其为 $new_category_order),并用 array_filter 保留 slug 不在新顺序中的原分类,存入 $remaining_categories。原文文字对移除条件的描述与此实际保留条件不一致。

最后使用 array_merge,把新的分类顺序与 $remaining_categories 合并,返回完整的修改后分类列表。

整合函数的示例:重命名并重排 Text 和 Media 分类,同时添加 Custom Blocks 分类。
整合函数的示例:重命名并重排 Text 和 Media 分类,同时添加 Custom Blocks 分类。

结语

block_categories_all 让你按项目和用户的需要组织区块分类,支持他们创建内容的方式。(block_categories_all)

这些函数仅仅是起点。你会如何使用它们?是否有其他函数,或更有创意的组合方式?欢迎到原文评论区交流。

感谢 @psykro 和 @marybaum 审阅本文并提供反馈。(@psykro · @marybaum)

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容