grottopress/wordpress-suv

实现 SUV 架构的脚手架

v1.1.0 2023-06-29 16:10 UTC

This package is auto-updated.

Last update: 2024-09-29 19:01:30 UTC


README

SUV 是我们在 GrottoPress 构建WordPress主题和插件的专用架构。本包是实现 SUV 的脚手架。

SUV 的缩写为 Setups-Utilities-Views。它强调以面向对象的方式编写WordPress插件和主题,并提供了更干净、更有组织的代码库。

SUV 广泛使用对象组合,并充分利用了WordPress核心事件驱动架构的表达能力。

设置:包括所有与WordPress直接交互的对象,通常通过动作和过滤器钩子。

工具:工具是包含完成其目标所需的方法的对象。

视图:视图是主题/插件或WordPress要加载的模板和部分。

要求

代码风格

代码至少应遵守 PSR-1PSR-2PSR-4

强烈建议在PHP 7中使用严格类型,并为函数/方法参数和返回值指定类型。

尽可能

  • 追求不可变对象
  • 偏好声明式语法
  • 不要继承具体类
  • 避免静态方法
  • 摒弃花哨的设计模式

用法

注意:从现在开始,app 指的是您的主题或插件。

目录结构

按照以下方式设置您自己的应用程序目录结构

.
├── app/
│   ├── MyApp/
│   │   ├── Setups/
│   │   ├── Utilities/
│   │   └── Utilities.php
│   ├── helpers.php
│   └── MyApp.php
├── assets/
│   ├── css/
│   └── js/
├── dist/
│   ├── css/
│   └── js/
├── lang/
├── node_modules/
├── partials/
├── templates/
├── tests/
├── vendor/
├── .editorconfig
├── .gitignore
├── CHANGELOG.md
├── codeception.yml
├── composer.json
├── composer.lock
├── <app-bootsrap>.php (functions.php or my-plugin.php)
├── LICENSE
├── package.json
├── package-lock.json
├── postcss.config.js
├── README.md
├── tailwind.config.js
├── tsconfig.json
└── webpack.mix.js

并非所有目录/文件都适用于您的情况。删除您不需要的,并按需添加所需的文件。只需记住总体概念即可。

自动加载

您的 composer.json 自动加载配置

{


  "autoload": {
    "psr-4": {
      "Vendor\\": "app/"
    },
    "files": [
      "app/helpers.php"
    ]
  }


}

需要 SUV

从应用程序的根目录运行

composer require grottopress/wordpress-suv

示例 WordPress 插件

让我们用 SUV 编写一个示例 WordPress 插件,好吗?

// @ wp-content/plugins/my-plugin/app/MyPlugin.php

<?php
declare (strict_types = 1);

namespace Vendor;

use Vendor\MyPlugin\Setups;
use Vendor\MyPlugin\Utilities;
use GrottoPress\WordPress\SUV\AbstractPlugin;

final class MyPlugin extends AbstractPlugin
{
    /**
     * @var Utilities
     */
    private $utilities;

    protected function __construct()
    {
        $this->setups['Footer'] = new Setups\Footer($this);
        // ...
    }

    protected function getUtilities(): Utilities
    {
        return $this->utilities = $this->utilities ?: new Utilities($this);
    }
}
// @ wp-content/plugins/my-plugin/app/MyPlugin/Setups/Footer.php

<?php
declare (strict_types = 1);

namespace Vendor\MyPlugin\Setups;

use GrottoPress\WordPress\SUV\Setups\AbstractSetup;

final class Footer extends AbstractSetup
{
    public function run()
    {
        \add_action('wp_footer', [$this, 'renderText']);
    }

    /**
     * @action wp_footer
     */
    public function renderText()
    {
        echo '<div class="useless-text">'.
            $this->app->utilities->text->render().
        '</div>';
    }
}

您可以将工具类放入 app/MyPlugin/Utilities/。工具类不直接与WordPress交互,但包含设置类和视图可以使用的功能,以实现其目标。

// @ wp-content/plugins/my-plugin/app/MyPlugin/Utilities.php

<?php
declare (strict_types = 1);

namespace Vendor\MyPlugin;

use Vendor\MyPlugin;
use GrottoPress\Getter\GetterTrait;

class Utilities
{
    use GetterTrait;

    /**
     * @var MyPlugin
     */
    private $app;

    /**
     * @var Utilities\Text
     */
    private $text;

    public function __construct(MyPlugin $plugin)
    {
        $this->app = $plugin;
    }

    private function getApp(): MyPlugin
    {
        return $this->app;
    }

    private function getText(): Utilities\Text
    {
        return $this->text = $this->text ?: new Utilities\Text($this);
    }
}
// @ wp-content/plugins/my-plugin/app/MyPlugin/Utilities/Text.php

<?php
declare (strict_types = 1);

namespace Vendor\MyPlugin\Utilities;

use Vendor\MyPlugin\Utilities;
use GrottoPress\Getter\GetterTrait;

class Text
{
    use GetterTrait;

    /**
     * @var Utilities
     */
    private $utilities;

    public function __construct(Utilities $utilities)
    {
        $this->utilities = $utilities;
    }

    /**
     * This is obviously a very trivial example. We could
     * have just printed this directly in the footer setup's
     * `renderText()` method.
     *
     * It is done here only for the purpose of demonstration,
     * if you know what I mean.
     */
    public function render(): string
    {
        return \esc_html__('Useless text', 'my-plugin');
    }
}

由于我们的插件 extends SUV 的 AbstractPlugin,它本质上是一个单例。整个插件(包括所有对象)可以通过调用 Vendor\MyPlugin\MyPlugin::getInstance() 来检索

让我们在 app/helpers.php 中创建一个帮助器来完成这个操作。

// @ wp-content/plugins/my-plugin/app/helpers.php

<?php
declare (strict_types = 1);

use Vendor\MyPlugin;

function MyPlugin(): MyPlugin
{
    return MyPlugin::getInstance();
}

其他插件和主题现在可以访问单例插件实例,并可以删除我们插件中的操作,如下所示

\add_action('init', function () {
    \remove_action('wp_footer', [\MyPlugin()->setups['Footer'], 'renderText']);
});

现在,让我们用插件的自引导来结束我们的插件

// @ wp-content/plugins/my-plugin/my-plugin.php

<?php
/**
 * @wordpress-plugin
 * Plugin Name: My Plugin
 * Plugin URI: https://www.grottopress.com
 * Description: My awesome plugin
 * Version: 0.1.0
 * Author: GrottoPress
 * Author URI: https://www.grottopress.com
 * License: MIT
 * License URI: https://open-source.org.cn/licenses/MIT
 * Text Domain: my-plugin
 * Domain Path: /languages
 */
declare (strict_types = 1);

require __DIR__.'/vendor/autoload.php';

/**
 * Run plugin
 */
\add_action('plugins_loaded', function () {
    \MyPlugin()->run();
}, 0);

构建插件?

我们创建了一个 WordPress 插件脚手架,它使用 SUV。它为您设置了最常见的东西,以便您可以直接编写代码。

您应该 查看它

构建主题?

如果您想使用 SUV 构建主题,您应该查看 Jentil

Jentil 是一个用于快速 WordPress 主题开发的框架,它是使用 SUV 架构构建的。

它拥有众多功能,包括一个加载器,该加载器仅从 app/templates 目录加载模板(例如:page.phpindex.phpsingle.php 等),并从 app/partials 目录加载部分模板(例如:header.phpfooter.phpsidebar.php)。

查看详细信息 »

开发

使用 composer run test 运行测试。

贡献

  1. 进行Fork操作
  2. 切换到 master 分支: git checkout master
  3. 创建您的功能分支: git checkout -b my-new-feature
  4. 进行更改,并根据需要更新变更日志和文档。
  5. 提交您的更改: git commit
  6. 推送到分支: git push origin my-new-feature
  7. 针对 GrottoPress:master 分支提交一个新的 Pull Request