pwpf/demo

v1.0.1 2021-03-18 13:33 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 - 没有额外的好东西 - 没有巨大的学习曲线。

架构

以下是对架构的鸟瞰图

MVC Architecture

安装

可以直接将模板直接安装到你的插件文件夹中 "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. 编写你的第一个模型 DNA

所有模型都应该扩展 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. 文件夹结构 📁

灵感来了?

Build a Fort

如果您喜欢这种开发方式,请为这个仓库点个星!

特性

  • 该模板基于 插件 API文档规范
  • 所有类、函数和变量都有文档说明,以便您知道需要更改什么。
  • 该项目包含一个 .pot 文件,作为国际化起点的起点。
  • 模型、视图和控制器之间的关注点分离。
  • 通过适当使用路由器,可以保持插件占用较低。

推荐工具

国际化工具

WordPress MVC 插件模板使用一个变量来存储在模板国际化字符串时使用的文本域。为了利用此方法,有一些推荐工具提供正确且可翻译的文件

上述任何工具都应该为您提供适当的工具来国际化插件。

致谢

WordPress MVC 插件模板 是基于由 Roger Rodrigo 分支的 WordPress 插件模板 项目构建的。原始的 WordPress 插件模板 项目始于 2011 年,由 Tom McFarlin 创立,并自那以后收到了许多优秀的贡献。2015 年 3 月,该项目由 Tom 转交给 Devin Vinson。

这个 WordPress MVC 插件模板 是由 Sumit Pore 开发和维护的。