Быстрое прототипирование: от прототипа к коду, часть 1
Что касается быстрых прототипов и WordPress, мы пока сделали две вещи:
На данный момент мы проделали достаточно работы, чтобы начать рефакторинг нашего кода. То есть мы приступим к конвертации прототипа в код. Но это то, что нужно будет сделать в два этапа.
Во-первых, мы просто представим классы, представляющие диаграммы из предыдущего поста и инкапсулирующие ответственность каждого проекта.
После этого мы рассмотрим организацию кода по пространствам имен и пакетам. Прежде чем мы сможем это сделать, нам нужно убедиться, что код является объектно-ориентированным и остается функциональным. Вот что будет в этом посте.
Прототип для кода
Если вы читали предыдущие посты, обратите внимание, что я планирую следовать организации, которую набросал в предыдущем посте. Конечно, вам не обязательно следовать этому конкретному дизайну.
Несколько слов о системе управления версиями
Если вы используете систему управления версиями, здесь я рекомендую создать ветку от основной ветки (если вы используете Git), чтобы вы могли выполнять свою работу, не нарушая стабильную версию кода.
Это немного выходит за рамки данной серии, поэтому, если вы не используете систему управления версиями, не беспокойтесь. Если да, я выбираю разработку в качестве названия этой ветки. Я объединю его обратно с мастером , как только буду уверен, что он работает.
Написание кода
Согласно работе, набросанной вчера, я собираюсь создать два класса:
- класс метабокса,
- класс отображения метабокса.
Будет некоторое повторное использование кода из того, что мы уже видели, как вы увидите в следующем коде.
Код
Во- первых, наш метабокс :
<?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();
}
}
То, что в коде мета-бокса, в коде мета-бокса мы явно создаем экземпляр дисплея, чтобы мы могли вызывать его метод отображения, когда это необходимо.
Другой альтернативой может быть создание экземпляров двух объектов по отдельности, а затем вставка отображения в мета-поле с помощью внедрения конструктора или чего-то подобного. Это должно быть сделано в стороннем классе.
Преимущества этого заключаются в том, что два класса немного больше отделены друг от друга. Возможно, мы рассмотрим, как это сделать, в следующем посте.
После этого нам нужно продолжить и определить класс, отвечающий за отображение сообщений в контексте отображения метабокса. Это то, что мы будем называть почтовым мессенджером :
<?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
- Быстрое прототипирование: знакомство с автозагрузкой