pwpf / demo
This package is auto-updated.
Last update: 2024-09-18 17:47:58 UTC
README
安装
发布
composer create-project pwpf/demo project_name
cd project_name
./pwpf-generator.sh
composer dump-autoload
git config --local core.hooksPath .githooks/
composer update
或开发版本
composer create-project pwpf/demo --stability=dev project_name_dev
cd project_name_dev
./pwpf-generator.sh
composer dump-autoload
git config --local core.hooksPath .githooks/
composer update
WordPress MVC 插件模板
由于 WordPress 是一个事件驱动系统,在创建 WordPress 插件时遵循 MVC 设计模式比较困难。这个项目旨在帮助插件开发者在其编码中实现 MVC 模式。如果你对 MVC 术语不熟悉,之前也没有使用过 MVC 架构,我强烈建议你学习以下课程:https://www.udemy.com/php-mvc-from-scratch/
为什么?
原始的 WordPress 插件模板 是创建小型插件的绝佳起点。因此,如果你的插件很小,我确实推荐使用该模板。然而,随着插件的发展以及我们不断增加更多功能,确定某个代码片段应该放在哪里或何时/如何分离不同的功能变得有些具有挑战性。当这些事情在长期项目中对开发者来说不清楚时,他们最终会创建出尝试做所有事情的“上帝类”。
这个模板的目标是分离关注点。开发者有机会编写单独的 模型
、视图
和 控制器
。此外,是否加载控制器/模型的问题委托给 路由器
,这样你的控制器和模型就可以只专注于它们应该做的事情。
因为这个项目旨在成为一个模板,它只包含构建 MVC 插件所需的功能 - 没有ORM - 没有额外的好东西 - 没有巨大的学习曲线。
架构
以下是对架构的鸟瞰图
安装
可以直接将模板直接安装到你的插件文件夹中 "as-is"。你可能需要将其重命名以及其中的类以适应你的需求。例如,如果你的插件名为 'example-me',那么
- 将文件从
plugin-name
重命名为example-me
- 将
plugin_name
更改为example_me
- 将
plugin-name
更改为example-me
- 将
Plugin_Name
更改为Example_Me
- 将
PLUGIN_NAME_
更改为EXAMPLE_ME_
现在激活插件是安全的。因为模板没有真正的功能,所以除非你编写代码,否则不会添加菜单项、元框或自定义帖子类型。
入门指南
我们将尝试创建一个打印 10 篇帖子的短代码,这将帮助你了解这个模板的工作原理。本指南假定你已经完成了安装步骤并创建了 Example Me
插件。
1. 编写你的第一个路由器 📡
路由可以在 routes.php
文件中定义。以下是如何为我们的示例定义路由
// Full Class Name with Namespace $router ->registerRouteOfType( RouteType::FRONTEND ) ->withController( 'Example_Me\App\Controllers\Frontend\Print_Posts_Shortcode@registerShortcode' ) ->withModel( 'Example_Me\App\Models\Frontend\Print_Posts_Shortcode' ); // ------------- OR -------------------- // Class Names Without specifying Namespaces explicitly. Boilerplate will automatically figure out the class based on the Route Type. $router ->registerRouteOfType( RouteType::FRONTEND ) ->withController( 'Print_Posts_Shortcode@registerShortcode' ) ->withModel( 'Print_Posts_Shortcode' );
强烈建议你查看
routes.php
。你将了解该文件中所有可用的路由类型和示例。
2. 编写你的第一个控制器 🎮
模板将类名转换为文件名并自动加载该文件。
我们在 routes.php
中将 Example_Me\App\Controllers\Frontend\Print_Posts_Shortcode
传递为控制器。模板将此类名解析为文件 example-me/app/controllers/frontend/class-print-posts-shortcode.php
任何作为路由(即添加到 routes.php
)的一部分的控制器(请参阅:添加到 routes.php
)必须扩展 Base_Controller
类。
- 如果是仪表板(管理)相关的控制器,则应扩展
Plugin_Name\App\Controllers\Admin\Base_Controller
。 - 如果是前端相关的控制器,则应扩展
Plugin_Name\App\Controllers\Frontend\Base_Controller
。
所有扩展 Base_Controller
的控制器都必须有 register_hook_callbacks
方法。这个方法在 Base_Controller
中定义为 abstract
。
register_hook_callbacks
方法注册动作和过滤器的回调。大部分的 add_action
/add_filter
都会放入这个方法中。
register_hook_callbacks
方法不是自动调用的。作为开发者,你需要在你认为合适的地方调用这个方法。例如,如果你觉得钩子/过滤器回调应该在创建类的新的实例时注册,你可以在路由本身中用 @
调用这个方法。这样,我们就不需要在构造函数中污染 add_action
& add_filter
。
这个方法的目的就是设置一个惯例,即首先查找 add_action
/add_filter
的位置是 register_hook_callbacks
方法。
注意:如果你在一个扩展
Base_Controller
的控制器中创建了一个构造函数,那么请确保在该构造函数中调用init
方法。这意味着你的自定义构造函数需要包含以下行$this->init( $model, $view );
以设置控制器对象的Model
&View
。
显示控制器示例代码
以下是我们示例中这个文件的外观<?php // file: example-me/app/controllers/frontend/class-print-posts-shortcode.php namespace Example_Me\App\Controllers\Frontend; if ( ! class_exists( __NAMESPACE__ . '\\' . 'Print_Posts_Shortcode' ) ) { /** * Class that handles `example_me_print_posts` shortcode * * @since 1.0.0 * @package Example_Me * @subpackage Example_Me/Controllers/Frontend */ class Print_Posts_Shortcode extends Base_Controller { /** * Registers the `example_me_print_posts` shortcode * * @return void * @since 1.0.0 */ public function registerShortcode() { add_shortcode( 'example_me_print_posts', array( $this, 'print_posts_callback' ) ); } /** * @ignore Blank Method */ protected function register_hook_callbacks(){} /** * Callback to handle `example_me_print_posts` shortcode * * @return void * @since 1.0.0 */ public function print_posts_callback( $atts ) { return $this->get_view()->render_template( 'frontend/print-posts-shortcode.php', [ 'fetched_posts' => $this->get_model()->get_posts_for_shortcode( 'example_me_print_posts', $atts ) ] ); } } }
3. 编写你的第一个模型 
所有模型都应该扩展 AbstractModel
类。
- 如果是仪表板(管理)相关的模型,那么它应该扩展
Plugin_Name\App\Models\Admin\AbstractAdminModel
。 - 如果是前端相关的模型,那么它应该扩展
Plugin_Name\App\Models\Frontend\AbstractFrontendModel
。
你可以决定是否在你的模型中创建 register_hook_callbacks
方法。在 Base_Model
中它不是一个抽象方法。如果你想编写任何 add_action
/add_filter
,那么理想情况下应该将它们放在这个方法中。(我建议将所有 add_action
& add_filter
调用放在控制器类的 register_hook_callbacks
中。这样你可以一目了然地看到所有 add_action
& add_filter
,但最终决定权在你!你应该做适合你情况的事情。)
再次强调,register_hook_callbacks
不是自动调用的。如果你觉得钩子/过滤器回调应该在创建类的新的实例时注册,那么在模型构造函数中调用这个方法。
@
不在 Router 类的 withModel
方法中受支持,然而,@
在 Router 类的 with_just_model
方法中受支持。如果你对此感到困惑,请参阅 routes.php
。它包含了各种示例。
显示模型示例代码
创建一个文件 example-me/app/models/frontend/class-print-posts-shortcode.php
,因为我们需要创建 Example_Me\App\Models\Frontend\Print_Posts_Shortcode
类。
以下是我们示例中这个文件的外观
<?php // file: `example-me/app/models/frontend/class-print-posts-shortcode.php` namespace Example_Me\App\Models\Frontend; if ( ! class_exists( __NAMESPACE__ . '\\' . 'Print_Posts_Shortcode' ) ) { /** * Class to handle data related operations of `example_me_print_posts` shortcode * * @since 1.0.0 * @package Example_Me * @subpackage Example_Me/Models/Frontend */ class Print_Posts_Shortcode extends Example_Me\App\Models\AbstratModel { /** * Fetches posts from database * * @param string $shortcode Shortcode for which posts should be fetched * @param array $atts Arguments passed to shortcode * @return \WP_Query WP_Query Object */ public function get_posts_for_shortcode( $shortcode, $atts ) { $atts = shortcode_atts( array( 'number_of_posts' => '10', ), $atts, $shortcode ); $args = array( 'post_type' => 'post', 'posts_per_page' => is_int( $atts['number_of_posts'] ) ? $atts['number_of_posts'] : 10, ); return new \WP_Query( $args ); } } }
4. 编写视图 👸
在 app/controllers/AbstractController.php 中,你必须定义你的视图配置
<?php /** */ public function __construct(Model $model, $view = false) { $config = [ 'appName' => 'Plugin_Name' ]; $view = new View($config); parent::__construct($model, $view); }
5. 编写你的第一个模板 👶
模板是生成你编写的模块实际 HTML 的文件。
可以通过在任意 View
类(父类和子类)的对象上调用 render_template
方法来调用模板文件。
模板文件创建在 app/templates/
文件夹中。
显示模板示例代码
所以模板文件在示例中的完整位置是 example-me/app/templates/frontend/print-posts-shortcode.php
它看起来是这样的
// file: `example-me/app/templates/frontend/print-posts-shortcode.php` <?php if ( $fetched_posts->have_posts() ) : ?> <!-- the loop --> <?php while ( $fetched_posts->have_posts() ) : ?> <?php $fetched_posts->the_post(); ?> <h2><?php the_title(); ?></h2> <?php endwhile; ?> <!-- end of the loop --> <?php wp_reset_postdata(); ?> <?php else : ?> <p><?php esc_html_e( 'Sorry, no posts matched your criteria.' ); ?></p> <?php endif; ?>
6. 与设置交互 ⚙️
在开发插件时,我们有时需要一种手动与设置信息交互的方式(旁注 - 如果使用设置 API 创建设置页面,WordPress 会自动保存设置)
在下面的方法中,将 Plugin_Name
替换为您的插件命名空间。
Plugin_Name\App\Models\Settings
提供了一些与设置数据交互的辅助方法。
7. 激活、停用与卸载流程?✨
您的插件的激活、停用与卸载流程分别位于 Plugin_Name\App\Activator::activate()
、Plugin_Name\App\Deactivator::deactivate()
以及 Plugin_Name\App\Uninstaller::uninstall()
方法。
8. 文件夹结构 📁
灵感来了?
如果您喜欢这种开发方式,请为这个仓库点个星!
特性
- 该模板基于 插件 API 和 文档规范。
- 所有类、函数和变量都有文档说明,以便您知道需要更改什么。
- 该项目包含一个
.pot
文件,作为国际化起点的起点。 - 模型、视图和控制器之间的关注点分离。
- 通过适当使用路由器,可以保持插件占用较低。
推荐工具
国际化工具
WordPress MVC 插件模板使用一个变量来存储在模板国际化字符串时使用的文本域。为了利用此方法,有一些推荐工具提供正确且可翻译的文件
上述任何工具都应该为您提供适当的工具来国际化插件。
致谢
WordPress MVC 插件模板
是基于由 Roger Rodrigo 分支的 WordPress 插件模板
项目构建的。原始的 WordPress 插件模板
项目始于 2011 年,由 Tom McFarlin 创立,并自那以后收到了许多优秀的贡献。2015 年 3 月,该项目由 Tom 转交给 Devin Vinson。
这个 WordPress MVC 插件模板
是由 Sumit Pore 开发和维护的。