WordPress
カスタマイズ事例

WORDPRESS CUSTOMIZATION

Custom Field Suiteを使ったカスタムフィールドを持つページの「プレビュー」を表示する

固定ページや投稿、カスタム投稿タイプなどにカスタムフィールドを持たせることがよくあります。
入力の手間が省け、htmlの知識がない人でも簡単に高機能なWebレイアウトを作ることができとても便利です。
ところが、カスタムフィールド管理のプラグインでCustom Field Suiteを使うと、「プレビュー」(「更新」せずに表示を確認できる機能)ができない、という問題があります。

そこで今回は、Custom Field Suiteを使ったカスタムフィールドを持つページの「プレビュー」を表示する方法のご紹介。

まずプラグインを作り、有効にします。
(作り方の基礎が知りたければWordPressのプラグインを作成する(初級)を参考にしてください。)

<?php
/*
Plugin Name: Custom field suite preview bug fix
Author: kaiza
Plugin URI: 
Description: Custom field suite preview bug fix
Version: 0.1.0
Author URI: 
*/

$cfs_fix = new Custom_Field_Suite_Preview();
class Custom_Field_Suite_Preview {

function __construct(){
    add_action('plugins_loaded', array($this, 'plugins_loaded'));
}

public function plugins_loaded(){
    add_action('cfs_init', array($this, 'cfs_init'), 0);
    add_action('wp_insert_post', array($this, 'wp_insert_post'));
    add_filter('get_post_metadata', array($this, 'get_post_metadata'), 10, 4 );
    add_shortcode('cfs_get', function($p){
        extract(shortcode_atts(array(
            'key' => false,
            'id' => 0,
            'format' => array(),
        ), $p));
        return self::get($key, $id, $format);
    });
}

public function get($key, $id = 0, $format = array()){
    global $cfs;
    if (intval($this->get_preview_id($id))) {
        return $cfs->get($key, $this->get_preview_id($id), $format);
    } elseif ($id = $this->get_preview_id(get_the_ID())) {
        return $cfs->get($key, $id, $format);
    } else {
        return $cfs->get($key, get_the_ID(), $format);
    }
}

public function cfs_init(){
    if (isset($_POST['wp-preview']) && $_POST['wp-preview'] === 'dopreview') {
        global $cfs;
        remove_action('cfs_init', array($cfs->form, 'init'));
    }
}

public function get_preview_id( $post_id ){
    global $post;
    $preview_id = 0;
    if (isset($post->ID) && intval($post->ID) === intval($post_id) && is_preview()
            && $preview = wp_get_post_autosave($post->ID)) {
        $preview_id = $preview->ID;
    }
    return $preview_id;
}

public function get_post_metadata( $return, $post_id, $meta_key, $single ) {
    if ($preview_id = $this->get_preview_id($post_id)) {
        if ($post_id !== $preview_id) {
            $return = get_post_meta($preview_id, $meta_key, $single);
        }
    }
    return $return;
}

public function wp_insert_post($post_ID){
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return;
    }
    if (defined('DOING_AJAX') && DOING_AJAX) {
        return;
    }
    if (wp_is_post_revision($post_ID)) {
        global $wpdb;
        global $cfs;
        $wpdb->query($wpdb->prepare(
            "DELETE FROM $wpdb->postmeta WHERE post_id = %d",
            $post_ID
        ));
        $cfs->form->session = new cfs_session();
        $session = $cfs->form->session->get();
        $field_groups = array();
        if (isset($session['field_groups'])) {
            $field_groups = $session['field_groups'];
        }
        foreach ($field_groups as $key => $val) {
            $field_groups[$key] = (int) $val;
        }
        $options = array(
            'format' => 'input',
            'field_groups' => $field_groups
        );
        //ユーザーさんからいただいた改善案にもとづき、修正しています。
        if(!empty($_POST['cfs']['input'])) {
            $cfs->save($_POST['cfs']['input'], array('ID' => $post_ID), $options); 
        }
        //元のコード $cfs->save($_POST['cfs']['input'], array('ID' => $post_ID), $options);

        $post_metas = array('meta');
        foreach ( $post_metas as $post_meta ) {
            foreach ( $_POST[$post_meta] as $meta_id => $meta_arr ) {
                add_metadata('post', $post_ID, $meta_arr['key'], $meta_arr['value']);
            }
        }
    }
}
}

これで、「プレビュー」が押されたときに、Custom Field Suiteで作ったカスタムフィールドの値を自動セーブします。
 
今度は表示側(page.phpなど)です。
自動セーブされた値を取得するために、Custom Field Suiteの関数は使わず、WordPress標準のget_post_meta関数を使ってカスタムフィールドを読み込むようにします。

<? php 
//画像の読み込み
$image1 = get_post_meta($post->ID, 'image1', true);
$image1 = content_url().'/uploads/'.get_post_meta($image1, '_wp_attached_file', true);

//テキストの読み込み
$text1 = get_post_meta($post->ID, 'text1', true);

//繰り返しフィールドの読み込み
$repeat1_fields = get_post_meta($post->ID, 'repeat1', false);
$count_total = count($repeat1_fields );
$count_total = $count_total/2; //同じ値が2つ登録されるので1つだけ取り出すための調整式
$repeat_fields = array();
for($i = 0; $i < $count_total; $i++){
    $repeat_fields[$i]['repeat1']=$repeat1_fields[$i];
}

//ユーザーさんからいただいた改善案では、次のような書き方もでき、
//これだと即時の更新ができるそうです。
if(is_preview()) {
    $id = get_preview_id(get_the_ID());
} else {
    $id = $post->ID;
}
$program_cfs = CFS()->get(false,$id);
$image1 = $program_cfs['image1'];
$text1 = $program_cfs['text1'];

//ただし、繰り返しフィールドの読み込みがこれでできるのか調べていないので、一応、当方のコードも上述のまま残しておきます。

?>


テキスト表示
<?php echo $text1; ?>

画像表示
<img src="<?php echo $image1; ?>" >

繰り返しフィールドの表示
foreach ($repeat_fields as $repeat_field) {
    echo $repeat_field['repeat1'].'<br>';
}

これでプレビュー表示されます。
 
 
※ ただし、これをしても、2回に1回しか変更した内容が反映されたページは表示されません。
2回に1回は変更前の“今公開されているページ”がプレビューとして現れます。
なぜそうなるかまでは突き止められませんでした。
ちなみに私たちが普段使っているカスタムフィールド管理用プラグイン Advanced Custom Fieldsでも同じ現象が起きます。。

あしからず。

【100ウェブ新着情報メルマガ】

WordPressカスタマイズ事例やウェブ制作ノウハウの新着情報、お役立ち情報を
リアルタイムにメルマガ配信!