Швидке створення прототипів: прототип до коду, частина 1
Що стосується швидких прототипів і WordPress, ми зробили дві речі:
На даний момент ми виконали достатньо роботи, щоб почати рефакторинг нашого коду. Тобто ми почнемо перетворювати прототип на код. Але це те, що потрібно буде зробити в два етапи.
По-перше, ми збираємося просто представити класи, які представляють діаграми з попередньої публікації та інкапсулюють відповідальність кожного проекту.
Після цього ми розглянемо організацію коду в просторах імен і пакетах. Перш ніж ми зможемо це зробити, нам потрібно переконатися, що код є об’єктно-орієнтованим і залишається функціональним. Ось що станеться в цій публікації.
Прототип до коду
Якщо ви читали попередні дописи, зауважте, що я планую слідкувати за організацією, яку я описав у минулому дописі. Вам, звичайно, не потрібно дотримуватися цього конкретного дизайну.
Кілька слів про контроль джерел
Якщо ви користуєтеся керуванням джерелом, тут я рекомендую створити відгалуження головної гілки (якщо ви використовуєте Git), щоб ви могли виконувати свою роботу, не завдаючи шкоди стабільній версії коду.
Це трохи виходить за рамки цієї серії, тому, якщо ви не використовуєте контроль джерел, не хвилюйтеся. Якщо так, то я вирішу використовувати для цієї гілки назву development. Я об’єднаю його назад у master , коли переконаюся, що він функціональний.
Написання коду
Відповідно до вчорашньої роботи, я збираюся створити два класи:
- клас мета коробки,
- клас відображення метабокса.
Як ви побачите в наступному коді, буде повторне використання коду з того, що ми вже бачили.
Код
По- перше, наш метабокс :
<?php
/**
* Registers the Meta Box with WordPress.
*
* @author Tom McFarlin
* @since 0.2.0
*/
/**
* Registers the Meta Box with WordPress. Defines the ID, title, display function,
* and the post type on which it will live.
*
* @author Tom McFarlin
* @since 0.2.0
*/
class Meta_Box {
/**
* A reference to the class that will display the contents in the meta box.
*
* @access private
* @var Meta_Box_Display
*/
private $meta_box_display;
/**
* Instantiates the class by setting its property equal to a reference to its display.
*/
public function __construct() {
$this->meta_box_display = new Meta_Box_Display();
}
/**
* The function responsible for hooking into the WordPress API.
*/
public function init() {
add_meta_box(
'three-recent-posts',
'Three Recent Posts',
array( $this->meta_box_display, 'display' ),
'post',
'side'
);
}
}
І далі наш дисплей :
<?php
/**
* Defines the display for the meta box.
*
* @author Tom McFarlin
* @since 0.2.0
*/
/**
* Defines the display for the meta box that will render the content in the
* context of its meta box.
*
* @author Tom McFarlin
* @since 0.2.0
*/
class Meta_Box_Display {
/**
* A reference to the class that will display the contents in the meta box.
*
* @access private
* @var Post_Messenger
*/
private $messenger;
/**
* Instantiates the object by setting a property equal to that of the class
* responsible for rendering the messages from the post query.
*/
public function __construct() {
$this->messenger = new Post_Messenger( $this );
}
/**
* If there are posts to display, renders them in the metabox. Otherwise, displays
* a note that there are no posts to display.
*/
public function display( $message) {
$this->messenger->get_message();
}
}
Це те, що в коді метабокса, у коді метабокса ми явно створюємо екземпляр відображення, щоб ми могли викликати його метод відображення, коли потрібно.
Іншою альтернативою було б створити екземпляри двох об’єктів окремо, а потім вставити дисплей у метабокс за допомогою ін’єкції конструктора чи щось подібне. Це потрібно було б зробити в сторонньому класі.
Переваги цього походять від дещо більшого роз’єднання двох класів. Можливо, ми розглянемо, як це зробити, у наступній публікації.
Після цього нам потрібно продовжити та визначити клас, який відповідає за відображення повідомлень у контексті Meta Box Display. Це те, що ми назвемо Post Messenger :
<?php
/**
* Display content for the meta box when requested.
*
* @author Tom McFarlin
* @since 0.2.0
*/
/**
* Retrieves information from the class responsible for querying the database and
* renders it in the context of our meta box when called via the Meta Box Display.
*
* @author Tom McFarlin
* @since 0.2.0
*/
class Post_Messenger {
/**
* A reference to the query resonsible for retrieving post information from
* the database.
*
* @access private
* @var WP_Query
*/
private $query;
/**
* A reference to the message that's displayed in the view of the
* meta box.
*
* @access private
*/
private $message;
/**
* Instantiates the class by setting a reference to the query.
*/
public function __construct() {
$this->query = new Post_Query();
}
/**
* Retrieves the content to be displayed in the meta box.
*/
public function get_message() {
$this->get_description();
if ($this->query->has_posts()) {
$this->get_post_message();
} else {
$this->get_no_posts_message();
}
}
/**
* Displays the description of the content of the meta box.
*
* @access private
*/
private function get_post_message() {
include_once 'post-list.php';
}
/**
* Displays the description of the content of the meta box.
*
* @access private
*/
private function get_description() {
include_once 'message-description.php';
}
/**
* Displays a message of there are no recent posts.
*
* @access private
*/
private function get_no_posts_message() {
include_once 'no-post-list.php';
}
}
Зауважте, що Post Messenger також посилається на Post Query. Це клас, де відбувається зв’язок із базою даних. Я також включив кілька допоміжних функцій, щоб зробити код перегляду трохи простішим, як ми зараз побачимо.
<?php
/**
* Queries the database for three most recent posts.
*
* @author Tom McFarlin
* @since 0.2.0
*/
/**
* Queries the database for three most recent posts. Returns the query to the
* caller so that it can be interrogates for posts or not.
*
* @author Tom McFarlin
* @since 0.2.0
*/
class Post_Query {
/**
* A reference to the WP_Query this class wraps.
*
* @access private
* @var WP_Query
*/
private $query;
/**
* Instantiates the class by preparing instance data and executing the
* query so the display can render the contents.
*/
public function __construct() {
$this->query = null;
$this->get_posts();
}
/**
* Executes the query for returning the post recent posts ordered by date.
*
* @access private
*/
private function get_posts() {
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'desc',
);
$this->query = new WP_Query( $args );
return $this->query;
}
/**
* A helper function to determine if the query has any posts.
*/
public function has_posts() {
return! $this->query->have_posts();
}
/**
* A helper function for retrieving the next post in the list of
* posts
*/
public function the_post() {
return $this->query->the_post();
}
}
І це все для основних класів. Звичайно, про погляди ще треба говорити.
Перегляди
Представлення відповідають за відтворення HTML у контексті мета-поля. Мені не подобається писати HTML у контексті PHP (також мені не подобається змішувати PHP із контекстом HTML, але це неминуче в цьому проекті).
Є кілька чудових проектів шаблонів, щоб полегшити це, але я відволікаюся. У будь- якому разі ви помітите, що у файлі post-list.php є посилання на допоміжні функції в класі Post Query. Це зроблено для того, щоб переконатися, що я не розкриваю занадто багато властивостей і не порушую Закон Деметри.
Давайте спочатку подивимося на цей файл, оскільки він найскладніший :
<ol>
<?php while ($this->query->has_posts()) { ?>
<?php $this->query->the_post(); ?>
<li>
<a href="<?php get_the_permalink(); ?>" target="_blank">
<?php echo get_the_title(); ?>
</a>
</li>
<?php } ?>
</ol>
Це схоже на стандартний код WordPress, але пам’ятайте, що оскільки цей файл викликається в Post Messenger, він посилатиметься на запит як на запит, обернутий цим класом.
Останні два файли досить зрозумілі. Один з них містить опис :
<p>
<span class="description">
Displays up to the three most recent posts.
</span><!-- .description -->
</p>
Інший надає повідомлення, коли немає публікацій :
<p>There are no recent posts.</p>
Окрім цього, базова функція виконана.
Завантаження плагіна
Останнє, що нам потрібно зробити, це запустити плагін. Для цього ми змінюємо код у головному файлі плагіна так, щоб він виглядав так :
<?php
/**
* Three Recent Posts
*
* @package TRP
* @author Tom McFarlin
* @copyright 2017 Tom McFarlin
* @license MIT
*
* @wordpress-plugin
* Plugin Name: Three Recent Posts
* Plugin URI: https://tommcfarlin.com/three-recent-posts/
* Description: Displays the three mot recent posts in your post editor screen.
* Version: 0.2.0
* Author: Tom McFarlin
* Author URI: https://tommcfarlin.com
* Text Domain: three-recent-posts
* License: GPL
* License URI: http://www.gnu.org/licenses/gpl-3.0.txt
*/
include 'class-meta-box.php';
include 'class-meta-box-display.php';
include 'class-post-messenger.php';
include 'class-post-query.php';
add_action( 'add_meta_boxes', 'trp_start' );
/**
* Starts the plugin.
*/
function trp_start() {
$meta_box = new Meta_Box();
$meta_box->init();
}
Це підключиться до WordPress, створить екземпляр нашого плагіна, а потім запустить його. Коли ви запускаєте його у своїй інсталяції WordPress, він має виглядати точно так, як у першій версії.
Єдина відмінність полягає в тому, що ми тепер маємо речі, організовані в класи, а не окремі функції.
Примітки
По-перше, тут є можливості для рефакторингу, які б ще більше зменшили відокремлення (наприклад, різні типи впровадження залежностей тощо), але мета цієї серії не полягає в тому, щоб охопити це.
Замість цього потрібно взяти ідею побачити плагіни, написані багатьма процедурними функціями, а потім розбити їх на більш концептуальні класи, які інкапсулюють їхні обов’язки.
По-друге, якщо ви переглянете вихідний код у репозиторії для цієї версії проекту, ви побачите, що я також представив composer.json. Це зроблено для того, щоб я міг скористатися PHP CodeSniffer і стандартами кодування WordPress під час написання коду.
В останній частині серії ми розглянемо простір імен і реорганізуємо файли. Якщо дозволить час, ми включимо автозавантажувач, щоб нам не доводилося вручну додавати файли у верхній частині файлу плагіна.
Нарешті, я об’єднав цей код у головний і позначив його як 0.2.1 (оскільки мені довелося зробити невелике виправлення), оскільки над ним ще багато роботи.
Повідомлення серії
- Швидке створення прототипів за допомогою WordPress: від концепції до плагіна
- Швидке створення прототипів за допомогою WordPress: аналіз концепції
- Швидке створення прототипів: прототип до коду, частина 1
- Швидке створення прототипів: прототип до коду, частина 2
- Швидке створення прототипів: представлення автозавантаження