EP173. “把插件模板改成 Block Theme 占位 Block”
🔒 登录后可标记已读这是一篇纯文字讲义(没有配套视频),补一个之前没考虑到的兼容问题:这整个数据库章节的插件示例是照着传统主题的假设写的(用 template_include 过滤器把 /pet-adoption 整个页面模板替换掉),如果站点用的是Block Theme(现代化主题),页面的头部/底部就不会是 Fictional University 主题该有的样子,而是 WordPress 默认的头尾——因为 Block Theme 压根不认 template_include 这一套。解法是把插件原本「替换整个页面模板」的做法,改成「注册一个可以在编辑器里插入到任意页面的占位 Block」,让页面本身留给 Block Theme 的编辑器搭建,宠物列表只是页面里的一个 Block 而已。
涉及文件
wp-content/plugins/new-database-table/our-blocks/petslist.js(新建)wp-content/plugins/new-database-table/our-blocks/petslist.php(新建,原inc/template-pets.php内容搬过来改造)wp-content/plugins/new-database-table/inc/template-pets.php(删除)wp-content/plugins/new-database-table/new-database-table.php(修改)
代码实现
our-blocks/petslist.js(新建,跟主题章节学过的占位 Block 写法一致):
wp.blocks.registerBlockType("ourdatabaseplugin/petslist", {
title: "Fictional University Pets List",
edit: function () {
return wp.element.createElement("div", { className: "our-placeholder-block" }, "Pets List Placeholder")
},
save: function () {
return null
}
})
our-blocks/petslist.php(新建,内容是原 inc/template-pets.php 去掉页面外壳后剩下的部分):
<?php
require_once( NEWDATABASETABLEPATH . 'inc/GetPets.php' );
$getPets = new GetPets();
?>
<p>This page took <strong><?php echo timer_stop();?></strong> seconds to prepare. Found <strong><?php echo number_format($getPets->count); ?></strong> results (showing the first <?php echo count($getPets->pets) ?>).</p>
<table class="pet-adoption-table">
<!-- ...表格结构不变,见 EP165/EP171-172... -->
</table>
<?php
if (current_user_can('administrator')) { ?>
<form action="<?php echo esc_url(admin_url('admin-post.php')) ?>" class="create-pet-form" method="POST">
<!-- ...新增宠物表单不变... -->
</form>
<?php }
?>
new-database-table.php:加一行 define,删掉模板替换逻辑,新增占位 Block 注册类:
require_once plugin_dir_path(__FILE__) . 'inc/generatePet.php';
define( 'NEWDATABASETABLEPATH', plugin_dir_path( __FILE__ ));
class PetAdoptionTablePlugin {
function __construct() {
global $wpdb;
$this->charset = $wpdb->get_charset_collate();
$this->tablename = $wpdb->prefix . "pets";
add_action('activate_new-database-table/new-database-table.php', array($this, 'onActivate'));
add_action('admin_post_createpet', array($this, 'createPet'));
add_action('admin_post_nopriv_createpet', array($this, 'createPet'));
add_action('admin_post_deletepet', array($this, 'deletePet'));
add_action('admin_post_nopriv_deletepet', array($this, 'deletePet'));
add_action('wp_enqueue_scripts', array($this, 'loadAssets'));
// template_include 这个 add_filter 整行删除
}
// ...deletePet() / createPet() / onActivate() 等方法不变...
}
$petAdoptionTablePlugin = new PetAdoptionTablePlugin();
class OurPluginPlaceholderBlock {
function __construct($name) {
$this->name = $name;
add_action('init', [$this, 'onInit']);
}
function ourRenderCallback($attributes, $content) {
ob_start();
require plugin_dir_path(__FILE__) . 'our-blocks/' . $this->name . '.php';
return ob_get_clean();
}
function onInit() {
wp_register_script($this->name, plugin_dir_url(__FILE__) . "/our-blocks/{$this->name}.js", array('wp-blocks', 'wp-editor'));
register_block_type("ourdatabaseplugin/{$this->name}", array(
'editor_script' => $this->name,
'render_callback' => [$this, 'ourRenderCallback']
));
}
}
new OurPluginPlaceholderBlock("petslist");
关键改动点:
inc/template-pets.php整个删除,内容搬到新建的our-blocks/petslist.php,但要做减法:删掉get_header()/get_footer()(Block Theme 下页面外壳交给编辑器搭建的页面模板处理,插件的 Block 只负责自己那一小块内容)、删掉外层page-banner那个<div>、删掉最外层container包裹的<div>(表格本身保留,只是不再需要这层包装 div)define('NEWDATABASETABLEPATH', plugin_dir_path(__FILE__)):在主插件文件顶部定义一个全局常量,存住插件根目录的绝对路径——因为our-blocks/petslist.php现在需要引入inc/GetPets.php,而这个文件不再位于原来的inc/文件夹里,用这个常量能不管调用来源在哪里都能正确拼出inc/GetPets.php的路径petslist.php顶部的require_once从相对路径改成用这个常量:require_once(NEWDATABASETABLEPATH . 'inc/GetPets.php'),而不是原来模板文件里用的plugin_dir_path(__FILE__) . 'GetPets.php'(因为当前文件所在目录已经变了)- 删掉
template_include这个add_filter:既然不再需要替换整个页面模板,这行代码整个可以移除,插件唯一要做的就是让新 Block 类型可用 OurPluginPlaceholderBlock类:这段代码基本就是这门课在主题/Block Theme 章节学过的占位 Block 写法照搬过来,唯一区别是这里改成从「当前插件目录」而不是「当前主题目录」找文件onInit():用wp_register_script()注册编辑器要用的 JS(our-blocks/petslist.js),register_block_type()注册这个 Block,render_callback指向ourRenderCallback()ourRenderCallback($attributes, $content):用ob_start()/ob_get_clean()的套路(这门课反复用过的技巧),把our-blocks/petslist.php的输出收集成字符串返回——require的文件路径是拼出来的:'our-blocks/' . $this->name . '.php'new OurPluginPlaceholderBlock("petslist"):实例化时传入的字符串"petslist"同时决定了要去our-blocks/目录找的 JS 和 PHP 文件名——这个名字必须跟our-blocks/目录下实际的文件名完全一致,如果文件叫petlist.php(少一个 s)却传了"petslist",就会找不到文件
- 在 WordPress 后台的操作步骤(不是代码):创建一个标题为「Pet Adoption」的页面,在正文区域插入新出现的「Fictional University Pets List」这个 Block,保存后前台就能看到跟 Block Theme 头尾风格一致的宠物列表页面
- 如果想让这个 Block 在编辑器里的预览也是真正的动态内容(而不是像这里一样只显示占位文字),可以参考这门课「Are You Paying Attention」和「Featured Professor」这两个 Block 类型插件章节学到的做法(
useSelect/自定义 REST 端点等)
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
define($常量名, $值) | PHP 内建语法 | 定义一个全局常量,跨文件调用同一个值时避免重复计算/硬编码 |
register_block_type($名字, array('editor_script' => ..., 'render_callback' => ...)) | WP 内建 function | 注册一个用 PHP 渲染实际内容、JS 只负责编辑器占位显示的 Block 类型 |
常见坑
- 用 Block Theme 时插件依然用
template_include过滤器整个替换页面模板——页面的头部/底部会变成 WordPress 默认外观,跟主题风格不一致 our-blocks/目录下的文件名跟实例化OurPluginPlaceholderBlock时传入的字符串对不上——找不到对应的 PHP/JS 文件,Block 无法正常工作- 把
inc/template-pets.php的内容搬到新文件后忘记同步调整require_once的路径——因为文件所在目录变了,原来基于plugin_dir_path(__FILE__)拼出来的相对路径不再指向正确位置
[截图:Site Editor 编辑页面时,在正文区域插入"Fictional University Pets List"占位 Block 后的编辑器画面]
[截图:改用占位 Block 后的前台 Pet Adoption 页面,头部/底部已恢复成 Fictional University 主题该有的样子]
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 27, EP173