内容が古くなっている可能性がありますのでご注意下さい。
以前開発した連載記事のページネーションのプラグインに、連載記事一覧を表示するウィジェットを追加した、Automatic Series Organizerプラグインを開発します。
仕様は極めて単純で、記事の投稿時に

series_idという決められた名前のカスタムフィールドを追加し、値の欄に連載名を記入しておくと、同じseries_idの値を持つ投稿を1つの連載記事としてまとめ、ページネーション

を表示するとともに、連載記事一覧をウィジェット

に表示するというものです。
プログラムの完全なリストは以下の通りです。
<?php
/*
Plugin Name: Automatic Series Organizer
Plugin URI: http://midoriit.com/works/auto-series.html
Description: Automaticallly organize pagination and widgets from series of posts.
Version: 0.3
Author: Midori IT Office, LLC
Author URI: http://midoriit.com/
License: GPLv2 or later
Text Domain: auto-series
Domain Path: /languages/
*/
/*
* Localization
*/
add_action( 'plugins_loaded', 'auto_series_loaded' );
function auto_series_loaded() {
$ret = load_plugin_textdomain( 'auto-series', false,
basename( dirname(__FILE__) ).'/languages/' );
}
/*
* List of Series Widget
*/
add_action( 'widgets_init', function() {
register_widget("Series_Widget");
});
class Series_Widget extends WP_Widget {
// Constructor
function __construct() {
parent::__construct(
'Series_Widget',
__('Series List', 'auto-series'),
array( 'description' => __( 'Show List of Series', 'auto-series' ), )
);
}
// Widget option form
function form($instance) {
$title = esc_attr($instance['title']);
echo '<p><label for="'.$this->get_field_id('title').'">';
echo __( 'Title:', 'auto-series' );
echo '<input class="widefat" id="'.$this->get_field_id('title').'" name="'. $this->get_field_name('title').'" type="text" value="'.$title.'" />';
echo '</label></p>';
}
// Updaate widget option
function update($new_instance, $old_instance) {
$instance['title'] = strip_tags($new_instance['title']);
return $instance;
}
// Output list of series
function widget($args, $instance) {
extract( $args );
echo $before_widget;
if( $instance['title'] ) {
echo $before_title.$instance['title'].$after_title;
} else {
echo $before_title.__( 'Series List', 'auto-series' ).$after_title;
}
$args = array(
'meta_key'=> 'series_id',
'orderby' => 'date',
'order' => 'ASC',
'nopaging' => true );
$series = array();
$posts = new WP_Query( $args );
if( $posts->found_posts > 1) {
echo '<ul>';
while( $posts->have_posts() ) {
$posts->the_post();
$series_id = get_post_meta(get_the_ID(), 'series_id', true);
if( !in_array( $series_id, $series ) ) {
echo '<li><a href="'.get_permalink().'">'.$series_id.'</a></li>';
array_push($series, $series_id);
}
}
echo '</ul>';
}
wp_reset_postdata();
echo $after_widget;
}
}
/*
* CSS for Pagination
*/
add_action( 'wp_print_styles', 'pagination_css' );
function pagination_css() {
$css_file = plugins_url( 'auto-series.css', __FILE__ );
wp_enqueue_style( 'auto-series', $css_file );
}
/*
* Show Pagination
*/
function series_pagination() {
global $post;
$current = $post->ID;
$meta_value = get_post_meta($current, 'series_id', true);
if( $meta_value == '' ) {
return;
}
$args = array(
'meta_key'=> 'series_id',
'meta_value' => $meta_value,
'orderby' => 'date',
'order' => 'ASC',
'nopaging' => true );
$pagination='';
$series = new WP_Query( $args );
if( $series->found_posts > 1) {
$num = 1;
$pagination = '<div class="series_pagination"><span>'.$meta_value.'</span> <span>';
while( $series->have_posts() ) {
$series->the_post();
if( $current == get_the_ID() ) {
if( $num > 9 ) {
$pagination = $pagination.'<a class="current_post wide">'.$num.'</a>';
} else {
$pagination = $pagination.'<a class="current_post">'.$num.'</a>';
}
} else {
$permalink = esc_url( apply_filters( 'the_permalink', get_permalink() ) );
if( $num > 9 ) {
$pagination = $pagination.'<a class="wide" href="'.$permalink.'" title="'.get_the_title().'">'.$num.'</a>';
} else {
$pagination = $pagination.'<a href="'.$permalink.'" title="'.get_the_title().'">'.$num.'</a>';
}
}
$num++;
}
$pagination = $pagination.'</span></div>';
}
wp_reset_postdata();
echo $pagination;
}
?>
まずは、一丁前にローカライゼーションをしています。
add_action( 'plugins_loaded', 'auto_series_loaded' );
function auto_series_loaded() {
$ret = load_plugin_textdomain( 'auto-series', false,
basename( dirname(__FILE__) ).'/languages/' );
}
日本語の言語リソース(auto-series-ja.po)は以下のように定義し、
msgid "Midori IT Office, LLC" msgstr "合同会社緑IT事務所" msgid "Title:" msgstr "タイトル:" msgid "Series List" msgstr "連載記事一覧" msgid "Show List of Series" msgstr "連載記事の一覧を表示します" msgid "Automaticallly organize pagination and widgets from series of posts." msgstr "連載記事のページネーションと連載一覧のウィジェットを自動的に構成します。"
以下のコマンドでバイナリファイル(auto-series-ja.mo)に変換します。
msgfmt -o auto-series-ja.mo auto-series-ja.po
msgfmtコマンドは、GetText for Windowsに含まれています。
次の
add_action( 'widgets_init', function() {
register_widget("Series_Widget");
});
でウィジェットを登録します。ウィジェット本体は次のSeries_Widgetクラスです。ウィジェットのクラスは、WP_Widgetクラスを派生させて作ります。
コンストラクタ
function __construct() {
parent::__construct(
'Series_Widget',
__('Series List', 'auto-series'),
array( 'description' => __( 'Show List of Series', 'auto-series' ), )
);
}
では、ウィジェット管理画面に表示される名前や説明を定義します。
次のform()メソッドは、ウィジェット管理画面でオプション設定をするためのフォームを表示します。
function form($instance) {
$title = esc_attr($instance['title']);
echo '<p><label for="'.$this->get_field_id('title').'">';
echo __( 'Title:', 'auto-series' );
echo '<input class="widefat" id="'.$this->get_field_id('title').'" name="'. $this->get_field_name('title').'" type="text" value="'.$title.'" />';
echo '</label></p>';
}
ここでは、ウィジェットのタイトルを設定できるようにしています。
次のupdate()メソッドで値を更新します。
function update($new_instance, $old_instance) {
$instance['title'] = strip_tags($new_instance['title']);
return $instance;
}
HTMLのタグは取り除いています。
ウィジェットを表示するのはwidget()メソッドです。
function widget($args, $instance) {
extract( $args );
echo $before_widget;
if( $instance['title'] ) {
echo $before_title.$instance['title'].$after_title;
} else {
echo $before_title.__( 'Series List', 'auto-series' ).$after_title;
}
$args = array(
'meta_key'=> 'series_id',
'orderby' => 'date',
'order' => 'ASC',
'nopaging' => true );
$series = array();
$posts = new WP_Query( $args );
if( $posts->found_posts > 1) {
echo '<ul>';
while( $posts->have_posts() ) {
$posts->the_post();
$series_id = get_post_meta(get_the_ID(), 'series_id', true);
if( !in_array( $series_id, $series ) ) {
echo '<li><a href="'.get_permalink().'">'.$series_id.'</a></li>';
array_push($series, $series_id);
}
}
echo '</ul>';
}
wp_reset_postdata();
echo $after_widget;
}
ウィジェットの出力に先立ち$before_widgetを、最後に$after_widgetを出力しています。また、タイトルの前には$before_titleを、後には$after_titleを出力していますが、これらの変数はextract( $args );によって得られます。
WP_Query()でカスタムフィールドseries_idを持つ記事を検索し、series_idの値(つまり連載名)が、出力済み連載名を格納する配列$seriesに含まれていなければ、その記事へのリンク付きで連載名を出力し、連載名を配列$seriesに格納します。
記事の日付で昇順に検索しているため、連載名からリンクする記事は、その連載の最初の記事になります。また、古い連載から順に表示されます。
以降は、ページネーションのためのCSSの処理と、ページネーションを出力するseries_pagination()メソッドの定義です。これらは、以前開発した連載記事のページネーションのプラグインと基本的には同じです。但し、カスタムフィールドの名前がseries_idに変わっています。
今回作成したプラグインはGitHubからダウンロードできます。
https://github.com/midoriit/auto-series