WEBLOG
WordPress > MVC構築
WordPressは、Symfony系と異なり、php が書ければ(極論ほとんど書けなくても)誰でも実装できる手軽さがありますが、反面、複雑なシステムを組む場合はコードの見通しがとても悪くなります。
弊社では、WordPressもMVCモデルで構築することで、複雑な仕様でも見通しのよいコードに仕上げています。
構築コンセプトは「メンテナンスに強い」です。
そもそもMVCとは、「Model(モデル)」「View(ビュー)」「Controller(コントローラ)」の三つの役割に分離して実装し、それらが連携して処理を進める方式。
語弊をおそれずに以下それぞれ。
DBから値(各フィールドの値)を取得してControllerで使いやすくなるよう事前準備。
DBから指定行(レコード)をとってきて、Viewに渡す。
Controller から受け取った値を表示する。
※ WordPressではテーマファイル群がこれにあたります。
※ Symfony系なら入力欄などから Controller 経由でDB操作しますが、WordPressではほとんどありません。
具他的には下記のようなコードを記述します。
/**--------------------------------------------------------------
*
* XxModel
*
--------------------------------------------------------------*/
class XxModel extends OoAttr
{
public function getAttr($post_id)
{
/* post */
$post = (object) [];
$post->post_id = $post_id;
$post->post_title = get_the_title($post_id);
$post->permalink = get_permalink($post_id);
// dete
$post->post_date = get_the_date('Y/n/j(D)', $post_id);
// content
$post->post_content = parent::post_content($post_id);
// acf
$post->acf_texts = $this->acf('acf_texts', $post_id)->textarea()->get();
$post->acf_pic = $this->acf('acf_pic', $post_id)->image('medium')->get();
$post->acf_radio = $this->acf('acf_radio', $post_id)->radio('both')->get();
$post->acf_group = (object) [];
$post->acf_group->texts = $this->acf('acf_group', $post_id)->group('texts')->textarea()->get();
return $post;
}
}
上記は、OoAttrを継承しているのですが、詳細は割愛し先ずは全体像を。
投稿タイプ一つに対して、1モデル作成し、必要な値をオブジェクトで取得できるようにしています。
acf() はカスタムフィールドのセッターで、途中処理して、 get() で取得しています。
命名は絶対遵守で、アッパーキャメル「投稿タイプ名Model 」にしています。
Laravel の Controller eloquent のような記述法です。
これは、カスタム投稿タイプアーカイブテンプレートのControllerサンプルです。
/**--------------------------------------------------------------
*
* xx_archive_controller
*
* @model XxModel
*
--------------------------------------------------------------*/
/* setting */
// $the_posts_per_page = 20;
/* model */
include_once TEMPLATEPATH . '/model/XxModel.php';
$XxModel = new XxModel();
/* archive */
$arr = [];
$args = [
'post_type' => 'xx',
'posts_per_page' => $the_posts_per_page
];
$the_query = new WP_Query( $args );
if ($the_query->have_posts()) {
while ($the_query->have_posts()) {
$the_query->the_post();
$arr[] = $XxModel->getAttr($the_query->post->ID);
}
}
$wp_archive_posts = $arr;
/* title */
$archive_name = 'xx一覧';
$archive_name .= is_paged() ? ' [ ' . get_query_var('paged') . '/' . $the_query->max_num_pages . ' ]' : '';
if (is_year()) {
$wp_archive_title = get_query_var('year') . '年の' . $archive_name;
} elseif (is_tax()) {
$temp_term = get_term_by('id', $query_term['term_id'], $XxModel::the_taxonomy);
$wp_archive_title = $temp_term->name . 'の' . $archive_name;
} else {
$wp_archive_title = '' . $archive_name;
}
Controller は、各テンプレート(View)に対して、1ファイル用意するようにしています。
命名規則は絶対で、投稿タイプ名_テンプレート種_controller.php としています。
get_posts(関数)などは使用せず、サイト内共通でWP_Query(class)を使用します。
特にqueryを操作する必要がない場合は、$the_query = $wp_query;
のように記載します。
WordPressのアーカイブテンプレートのサンプルです。
どのページにも共通で命名規則に則ったファイルを読み込みます。
テンプレートの記述は、php、blade、twig で可能な限り統一しマークアップエンジニア間のコードのnバラつきを減らしています。
<?php
/*--------------------------------------------------------------------------
archive-xx
---------------------------------------------------------------------------*/
/* base */
$PAGENAME = '*';
$DIRNAME = 'ディレクトリ';
define('DIRCODE', 'xx');
define('PAGECODE', 'archive');
/* contoroller */
include_once TEMPLATEPATH . '/controller/' . DIRCODE . '_' . PAGECODE . '_controller.php';
/* head & header */
include_once TEMPLATEPATH . '/header.php';
/*---------------------------------------------------------------------------*/
?>
<div class="title_wrap">
<div class="title">
<h1 class="title_text"><?= $wp_archive_title?></h1>
<p class="title_text_sub">DIR</p>
</div>
</div>
<div class="contents_wrap">
<div class="<?= DIRCODE ?>_<?= PAGECODE ?>_contents contents">
<section class="area">
<div class="hgroup">
<h2 class="heading02"><?= $wp_archive_title ?></h2>
</div>
<div class="box">
<div class="part">
<div class="cont texts">
<?php foreach($wp_archive_posts as $post) : ?>
<?php if($post->acf_radio === 'aaa') : ?>
<p><a href="<?= $post->permalink ?>"><?= $post->post_title ?>(<?= $post->post_date ?>)</a></p>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
</div>
</section>
</div>
</div>
<?php include_once TEMPLATEPATH . '/footer.php'; ?>
「テンプレートファイルに全て書ききってしまえばいいのに・・」と思われるかもしれません。
しかし、システムが複雑な場合でも簡単な場合でも同じ記述をすることで、コーディングとシステムにおいてスタッフ間の役割分担が明確になり、管理もしやくなっています(=メンテナンスに強いサイト)。