【WordPress】投稿ページに追記欄を追加するプラグインを作ってみたyo

WordPressプラグイン記事2件目です。Reoです。

前回の記事「【WordPress】カスタム投稿タイプを自作プラグインで追加してみよう!」では、自作プラグインでカスタム投稿タイプを追加する方法を紹介しました。

 

今回は、投稿ページに追記欄を追加するプラグインを作ってみようと思います。

こういうのんですね。

 

うるおいらんどではここに追記を書くとこんな感じで表示されるようにしています。

 

プラグインを作成する

さて、まずはプラグインのフォルダを作成します。

wp-content > plugins 内に additional-post-pluginというフォルダを作成。

その中に additional-post-plugin.php というファイルを追加して、以下を記述。

<?php
/*
Plugin Name: Additional Post Plugin
Description: 投稿ページに追記欄を作成する
Version: 1.0
Author: Reo
*/

define( 'ADDPP_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );

//ファイルの読み込み
require_once( ADDPP_PLUGIN_DIR . '/class.additional-post.php' );

同じフォルダ内にclass.additional-post.phpを追加します。
class.addtional-post.phpに以下を記述します。

<?php
/**
 * 
 * Additional Post Common Settings.
 * 
 */
if ( !class_exists('Additional_Post') ) {
    exit;
}

$AdditionalPost = new Additional_Post;

class Additional_Post {

    // インスタンス生成時に呼ばれる
    function __construct() {

    }

}

これでとりあえずプラグインの準備ができました。

ダッシュボードからプラグインを有効化できるか確認しておきましょう。

 

有効化できれば準備はおkです。

残りは全て class.additional-post.php 内のクラスAdditional_Post 内に記述していきます。

カスタムフィールドを追加する

投稿ページに追記欄を追加するには「カスタムフィールド」を使います。

Additional_Postに以下を追記します。

class Additional_Post {

    private const label = '追記';
    private const id = 'additional';

    // インスタンス生成時に呼ばれる
    public function __construct() {
        add_action( 'admin_menu', array($this, 'add_custom_field') );
    }

    /**
     * カスタムフィールドを追加する 追記欄
     */
    public function add_custom_field() {
        add_meta_box( 
            self::id,                              // 表示されるボックスのHTMLでのID名,
            self::label,                           // ラベル
            array( $this, 'insert_custom_field'),  // 表示する内容の関数
            'post',                                // 表示させたい投稿タイプ
            'normal'                               // 表示方法 normal / side / advanced
        );
    }

    /**
     * 入力欄
     */
    public function insert_custom_field() {
        echo "追加したカスタムフィールドが表示される場所だよ";
    }

}

 

add_meta_boxを使って通常の投稿ページにカスタムフィールドを設置しています。

add_meta_boxは管理画面でのみ呼び出されるようにadd_actionで登録しています。

 

add_meta_boxについてざっくりと。

第1引数

id名です。

 

第2引数

ラベル名です。

idとラベル名はクラス内で定数で制限しましたが全然直打ちでいいと思います。

第3引数

実際に表示する内容を記述した関数名を書きます。プラグインなのでここは配列にして$this指定をしています。

第4引数

表示させたい投稿タイプを指定します。現在postを指定しているので通常の投稿欄でのみ表示されます。

複数の投稿タイプで表示させたい場合は、配列で設定すればおkです。

add_meta_box( 
    self::id,                              // 表示されるボックスのHTMLでのID名,
    self::label,                           // ラベル
    array( $this, 'insert_custom_field'),  // 表示する内容の関数
    array('post','page','news'),           // 表示させたい投稿タイプ
    'advanced'                             // 表示方法 normal / side / advanced
);

この場合は通常投稿・固定ページ・カスタム投稿のニュースで追記欄を表示します。

第5引数

表示方法です。

normalとadvancedの場合は投稿の下にボックスが追加されます。

sideの場合はサイドに配置されます。

normalとadvancedの違いってなんだろうって調べてみました。

[ WordPress ] 独自のカスタムフィールドを設定する | WebScripter.jp によると、

normal:$priorityのhigh、lowを指定した場合、既存のメタボックスも含めて配置される順序が決定される。

advanced:原則既存のメタボックスの後ろに追加されるが、$priorityで優先順位を指定した場合、advancedが指定されたメタボックスの中で順序が決定される。
[ WordPress ] 独自のカスタムフィールドを設定する | WebScripter.jp

だそうです。

初期値はadvancedです。

 

今回指定していませんが、第6引数に優先度、第7引数にコールバックがあります。

詳しくは、リファレンスで。

 

入力欄を実装する

入力欄を実装します。

// 保存したいデータラベル
private const title = 'additional_title';
private const content = 'additional_content';
private const time = 'additional_time';

/**
 * 入力欄
 */
public function insert_custom_field() {
    global $post;

    $title = self::title;
    $content = self::content;

    // 現在の値
    $title_value = get_post_meta( $post->ID, $title, true );
    $content_value = get_post_meta( $post->ID, $content, true );

    echo "タイトル: <br><input type='text' name='{$title}' value='{$title_value}' size='50'><br>";
    echo "内容: <br><textarea type='text/html' name='{$content}' cols='70' rows='10'>{$content_value}</textarea><br>";
}

を追加します。

global $postで現在編集している投稿のデータを取得して、そこから$post->IDで投稿IDを取得しています。

やっていることは、投稿に紐づけられている保存したデータを$title_valueと$content_valueにいれて、それをテキストエリアに表示しています。

 

これで、入力欄はできました。

内容を保存しよう

現時点では追記内容を書いても消えてしまいます。

なので書いた内容を保存できるようにしていきます。

    /**
     * 保存処理
     */
    public function save_custom_field( $post_id ) {

        $labels = array( self::title, self::content );

        foreach ($labels as $label) {
            if(!empty($_POST[$label])){
                update_post_meta($post_id, $label, $_POST[$label] ); //値を保存
            }else{
                delete_post_meta($post_id, $label); //値を削除
            }
        }
        // 追記時間を保存
        update_post_meta( $post_id, self::time, date("Y/m/d") );
    }

この関数を、投稿が保存された時に呼び出すようにフックをかけます。

// インスタンス生成時に呼ばれる
public function __construct() {
    add_action( 'admin_menu', array($this, 'add_custom_field') );

    // 投稿が保存された時に呼ばれる
    add_action( 'save_post', array( $this, 'save_custom_field') );
}

update_post_metaで値を保存しています。空だった場合は削除しています。

 

ついでに追記をした時間も保存しています。

これで保存できました。ヤッター∩(〃・ω・〃)∩

 

nonceを設定しよう

さて、ここまでで一応カスタムフィールドの追加も保存もできたのですが、もう少しセキュアなものにしましょう。

nonceとは

nonce(ノンス)は、ある種の誤使用や悪意のある操作から URL やフォームを守るための「一度だけ使われる数値」です。WordPress の nonce は実際には数値ではなく、数字と英字で作られたハッシュです。また、本当に一度だけ使われるのではなく、無効になるまでの「有効期間」を持っています。その期間では、同じユーザーの同じコンテキストに対して、同じ nonce が生成されます。つまり、ある操作に対する nonce は、nonce の有効期間が切れるまで同じユーザーについて同じ値を保ちます。

上記のように本来の nonce と違いはありますが、WordPress のセキュリティトークンもほとんど同じ用途を満たすので “nonce” と呼ばれます。(WordPress の nonce は)CSRF を含む何種類かの攻撃から保護する助けになりますが、完全に一度しか使えない訳ではないので反射攻撃(replay attack)から守ることはできません。

https://wpdocs.osdn.jp/WordPress_Nonce

CSRFからの攻撃から保護するものです。

 

実際にadd_meta_boxのリファレンスでのコードにもnonceが用いられています。

なのでこれをそのままマネッコして実装しましょう。

 

insert_custom_fieldにnonceの設定を追記

/**
 * 入力欄
 */
public function insert_custom_field() {
    global $post;

    // nonceフィールドを追加して後でチェックする
    wp_nonce_field( wp_create_nonce(__FILE__), 'nonce_custom_field' );

    $title = self::title;
    $content = self::content;

    // 現在の値
    $title_value = get_post_meta( $post->ID, $title, true );
    $content_value = get_post_meta( $post->ID, $content, true );

    echo "タイトル: <br><input type='text' name='{$title}' value='{$title_value}' size='50'><br>";
    echo "内容: <br><textarea type='text/html' name='{$content}' cols='70' rows='10'>{$content_value}</textarea><br>";
}

wp_nonce_fieldの使い方はリファレンスにて。説明できるほど理解できてない感じで申し訳ないです。

 

save時にチェックをします。
save_custom_fieldにて

    /**
     * 保存処理
     */
    public function save_custom_field( $post_id ) {

        /*
        * save_postアクションは他の時にも起動する場合があるので、
        * 先ほど作った編集フォームのから適切な認証とともに送られてきたデータかどうかを検証する必要がある。
        */

        // nonceがセットされているかどうか確認
        if ( ! isset( $_POST['nonce_custom_field'] ) ) {
            return;
        }

        // nonceが正しいかどうか検証
        if ( ! wp_verify_nonce( $_POST['nonce_custom_field'], wp_create_nonce(__FILE__) ) ) {
            return;
        }

        // 自動保存の場合はなにもしない
        // if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        //     return;
        // }

        // ユーザー権限の確認
        if ( isset( $_POST['post_type'] ) && 'page' == $_POST['post_type'] ) {
            if ( ! current_user_can( 'edit_page', $post_id ) ) {
                return;
            }
        } else {
            if ( ! current_user_can( 'edit_post', $post_id ) ) {
                return;
            }
        }

        /* 安全が確認できたのでデータを保存する */

        $labels = array( self::title, self::content );

        foreach ($labels as $label) {
            if(!empty($_POST[$label])){
                update_post_meta($post_id, $label, $_POST[$label] ); //値を保存
            }else{
                delete_post_meta($post_id, $label); //値を削除
            }
        }
        // 追記時間を保存
        update_post_meta( $post_id, self::time, date("Y/m/d") );
    }

ラインを引いたところを追加します。

自動保存時は別に呼んじゃっていいかなと思ったのでコメントアウト。

なんども言いますが、詳しくはadd_meta_boxのリファレンスで!

 

これで追記欄を作成することができました!やったね!

ショートコードを設定しよう

さて、あとはこれを実際に表示するだけです。

実際にこのまま利用する場合は、テーマ内の表示したい場所に

<?php if (get_post_meta($post->ID, 'additional_content', true)): ?>
    <div class="additional" id="addition">
        <span class="additional-time"><?php echo get_post_meta($post->ID, 'additional_time', true); ?>追記</span>
        <span class="additional-title"><?php echo get_post_meta($post->ID, 'additional_title', true); ?></span>
        <div class="additional-content">
            <?php echo get_post_meta($post->ID, 'additional_content', true); ?>
        </div>
    </div>
<?php endif; ?>

こんな感じに追記します。

とってもわかりづらいし、ごちゃごちゃします。保存したデータの名前を間違えやすいです。

 

なのでショートコードを書くと表示できるようにしましょう。

[[additional]]

このぐらいで表示できるようにしちゃいます。

__constructでショートコードを追加します。

// インスタンス生成時に呼ばれる
public function __construct() {
    add_action( 'admin_menu', array($this, 'add_custom_field') );

    // 投稿が保存された時に呼ばれる
    add_action( 'save_post', array( $this, 'save_custom_field') );

    // ショートコードを追加
    add_shortcode( 'additional', array( $this, 'display_shortcode' ));
}

第一引数のadditionalが実際にショートコードの[[additional]]の名前になります。

第二引数で、このショートコードが使われた時の関数を指定していますので、その関数を実装します。

/**
 * ショートコード実行時
 */
function display_shortcode() {
    global $post;

    $labels = array(
        'タイトル'  => self::title,
        '内容'     => self::content,
        '追記時間'  => self::time
    );
    $field_id = self::id;

    $html_text = "<div class='{$field_id}'>";

    // 出力
    foreach ( $labels as $label_name => $label ) {
        $value = get_post_meta($post->ID, $label, true);
        $html_text .= "<div class='{$field_id}-{$label}'><span class='{$field_id}-name'>{$label_name}:</span>{$value}</div>";
    }

    $html_text .= "</div>";

    return $html_text;
}

出力タグはお好みで。

あとはテンプレート内で、


<?php echo do_shortcode('[additional]'); ?>

とかけばおkです。

 

ショートコードなので一応投稿画面で書くと、コンテンツの途中に挟むこともできます。

実際の表示

こんな感じです。

 

ちなみにこのショートコードでechoすると、記事本文に埋め込んだ時に表示される場所がおかしくなります。なのでreturnを使ってください。

 

全体コード

お疲れ様でした。ようやく終わりです。

 

今回はWordPressプラグインの作り方からの説明を、前回ほど詳しくしなかったのでもっと記事が短くなると思っていたんですが、思ったよりめっちゃ長くなりました。

読んでくれた方もお疲れ様です。

 

週末まではちょっとしんどそうな案件が入ったので、WordPressプラグイン作成記事はしばらくお預けにします。

ブログ強化月間中なので、もう少し軽めの記事は書く予定です。

それではでは〜。

 

 

コメントは認証制です。詳しくは下記の注意をお読みください。お気軽にコメントお願いします!

Write a Comment

コメント時の注意

「Twitter」「Facebook」「Google+」「WordPress」のいずれかのアカウントをお持ちの方は各アカウントと連携することでコメントできます。 コメントしたことはSNSに流れませんので、アカウントをお持ちの方はこちらの方法でコメントを投稿して下さると嬉しいです。 アカウントをお持ちでない方はメールアドレスで投稿することができます。 初回コメント時は承認後に表示されます。

Related Memo...

WordPressで現在のカテゴリから親カテゴリ/祖先カテゴリのスラッグを取得

//現在のカテゴリを取得
$categories = get_the_category($post->ID);
$category_slugs = array();
foreach($categories as $category){
    $cat = $category;
    array_push($category_slugs,$cat->slug);
    //親のカテゴリがなくなるまで回す
    while ($cat->parent) {
        $cat_parent_id = $cat->parent;
        $cat = get_category($cat_parent_id);
        array_push($category_slugs,$cat->slug);
    }
}

わりと頑張ってPHP書いてる。

WordPress

【WordPress】プラグイン化したカスタム投稿をテーマ内で使うとき

通常テーマ内でカスタム投稿を表示させる時に

$args = array( "posts_per_page" => 5,
        "post_type" => 'news'
    );
$the_query = new WP_Query( $args );
if($posts):

と書けば表示されるのに、プラグイン化していたので表示されなかった話。

 

functions.phpでカスタム投稿を追加している場合は必要ないが、newsというカスタム投稿をプラグイン化していたので、以下の記述が必要でした。

    public function __construct() {
        add_action( 'pre_get_posts', array($this, 'add_my_post_types_to_query') );
    }

    // queryにnewsをセットする
    function add_my_post_types_to_query( $query ) {
        if ( is_home() && $query->is_main_query() )
            $query->set( 'post_type', array( 'post', 'page', 'news' ) );
        return $query;
    }

WordPressプラグインの作り方は、また後日ちゃんとした記事にしたいと思ってます。今回はとりあえず忘れそうなのでメモだけで失礼。

WordPress

【WordPress】メディアライブラリ の画像IDを取得する

WordPressのメディアライブラリ にアップロードされた画像IDを取得する方法です。

例えば6件取得してギャラリーで表示するとき。

$ids = get_posts( 
    array(
        'post_type'      => 'attachment', 
        'post_mime_type' => 'image', 
        'post_status'    => 'inherit', 
        'posts_per_page' => 6,
        'fields'         => 'ids',
    ) 
);

$ids_str = '';
foreach ( $ids as $id ) {
    $ids_str .= $id . ',';
}

$ids_str = rtrim($ids_str, ',');

// ショートコードでギャラリーを表示
echo do_shortcode( '[gallery ids="' . $ids .'"]' );

意外と便利なのでは!

 

WordPress
more