grottopress / wordpress-suv
实现 SUV 架构的脚手架
Requires
- php: >=7.0
- grottopress/getter: ^1.0
README
SUV 是我们在 GrottoPress 构建WordPress主题和插件的专用架构。本包是实现 SUV 的脚手架。
SUV 的缩写为 Setups-Utilities-Views。它强调以面向对象的方式编写WordPress插件和主题,并提供了更干净、更有组织的代码库。
SUV 广泛使用对象组合,并充分利用了WordPress核心事件驱动架构的表达能力。
设置:包括所有与WordPress直接交互的对象,通常通过动作和过滤器钩子。
工具:工具是包含完成其目标所需的方法的对象。
视图:视图是主题/插件或WordPress要加载的模板和部分。
要求
- PHP >= 7.0
- Composer
代码风格
强烈建议在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.php
、index.php
、single.php
等),并从 app/partials
目录加载部分模板(例如:header.php
、footer.php
、sidebar.php
)。
查看详细信息 »
开发
使用 composer run test
运行测试。
贡献
- 进行Fork操作
- 切换到
master
分支:git checkout master
- 创建您的功能分支:
git checkout -b my-new-feature
- 进行更改,并根据需要更新变更日志和文档。
- 提交您的更改:
git commit
- 推送到分支:
git push origin my-new-feature
- 针对
GrottoPress:master
分支提交一个新的 Pull Request。