escaping

Advanced Custom Fieldsの便利さを享受しながら、クローズド化の罠を回避する

Advanced Custom Fields(以下ACF)が世に出てから4年は経つでしょうか。いくつかスマートげなプラグインも出たものの、いまだにシェアは圧倒的。今ひとつよくわからん機能があっても、管理・入力補助にすぐれ、結局クラインアントワークでは欠かせないんですよね。

しかし出力に独特の癖があるACF。この先、プラグインの乗り換えを検討する時が来るかもしれません。カスタムフィールドはWPで今後も利用されていくでしょうが、ACFに依存するテーブルデータや出力関数があるせいでプラグインやテーマを互換性がないなんて、オープンプラットフォームを使っている意味がないと言っても過言じゃない。そこで独自関数やテーブルを利用しないで済ませる方策を考えていきます。

カスタムフィールドの値はできるだけIDを持たせるようにする

ファイルやページなどをカスタムフィールドに登録する場合は、URLやオブジェクトを指定するとファイルやページに変更があったときに支障が出ます。そもそも、wordpressのデフォルト関数などでは保持される値はそのほとんどがIDか単純な文字列です。直感的に分かりやすいとメンテナンス性も上がりますし、汎用性を考えてもファイルや関連記事などの返り値はなるべくIDにしておく方がいいでしょう。

sc 2016-06-14 17.08.55

チェックボックスなど複数の値を持つvalueを出力する

WPでは同じキーを持つカスタムフィールドを複数登録できますが、ACFはチェックボックスやセレクトボックス、関連記事などのフィールドは複数の値を配列のままストアされます。プラグインが配布された当初から指摘されていたように、ACFのシリアライズされた値の保持方法はmeta queryや検索との相性がよくありません。しかしqueryに載せるならwp3.0以降はカスタムタクソノミーが設定できますし、その方がパフォーマンスもいいですので、シリアライズされることの一番の問題は抽出方法ということになるかと思います。(余談ですが、WP自体はカスタムフィールドに文字列以外が入ることも想定した設計になっていますし、配列を持たせることで判定と出力がシンプルにできるので、一概にダメな設計ではないように思います。)

さてさて、この複数値を出力する方法としては、ほとんどのサイトが独自関数get_field(またはthe_field)を使うように案内しています。

// 従来のACFの配列を出力するコード
$fields = get_field('field');
if($fields): foreach($fields as $val): 
   echo $val; 
endforeach; endif

…でもなんのことはない、値が配列になっているだけなので、以下のようにすれば出力ます。これによってテンプレートはユニバーサルな状態に保っておくことができます。

get_post_metaを使って配列を出力する

$fields = get_post_meta( $post->ID, 'field', true );
if ( $fields ): foreach( $fields as $key => $val ):
 echo $val;
endforeach; endif;

 

Repeater fieldを独自関数を使わずにアウトプットする

初めて有料で購入したWPのプラグイン拡張だった様な気がします。25$。これは買ってください。
sc 2016-06-14 8.33.26

相当数の人が使用していると思われるリピーターフィールドですが、これも出力方法に癖があります。公式に案内されているのは、次のような感じです。ゴリゴリのプラグイン依存ですね。

// 従来のrepeater fieldを出力するループ関数
if( have_rows('field') ): while( have_rows('field') ): the_row();

  $subfield = get_sub_field('subfield'); 
  // do something with subfield

endwhile; endif;

これは以下のようにPHPとget_post_metaで表現することが出来ます。こうすればデータベースに値があれば、 ACFなしで動作します。何を求めているコードなのかPHP的に一目瞭然なのが精神衛生上いいですね。

get_post_metaとforループで配列を出力する

$n = get_post_meta( $post->ID, 'field', true);
if ($n): for ($i = 0; $i < $n; $i++ ):
  $subfield = get_post_meta( $post->ID, 'field_'.$i. '_subfield', true );
  // do something with subfield

endfor; endif;

実地に合わせるとこんな感じに落ち着きます。

$n = get_post_meta( $post->ID, 'item', true);
if ($n): for ($i = 0; $i < $n; $i++ ):
  $image = get_post_meta( $post->ID, 'item_'.$i. '_image', true );
  if ( $image ) {
    echo '<div class="image">'.wp_get_attachment_image ( $image, 'medium' ).'</div>'."n";
  } 
  $text = get_post_meta( $post->ID, 'item_'.$i. '_text', true ); 
  if ( $text ) {
    echo '<div class="text">'.wpautop( $text ).'</div>'."n";
  }
endfor; endif;

カテゴリのカスタムフィールドをwp term meta対応にする

カテゴリに画像や注釈を付与するという要件は、CMSではよくある話です。カテゴリのカスタムフィールド設定は、なかなか満足できるプラグインがなくACFを使わざるをえず、ACFの独自データテーブルに依存するのを避けられませんでした。しかしwp4.4から公式にカテゴリやタグなどのタームはデフォルトでメタフィールド(wp term meta)が設置可能になりました。当初すぐにACFもサポートするものだと思っていましたが、半年待っても音沙汰なく、今後対応するかどうかも一切不明。wp term metaに対応すると、ユーザー囲い込みの一端が解けることを嫌ってるんじゃないかとか邪推したくなります。公式の機能からかけ離れていくのもどうかと思うんですけどね。

で、ACFのフォーラムで素晴らしい発案(How to use WP Term Meta, the easy way!)があったので私もそれを採用することにしました。ACF側でタームメタが更新された時に、自動的にwp term metaを上書きするだけです。逆方向はどうするんだとか、疑問はあるかもしれませんが、基本的には、wp term metaにストアさえされていれば、get_fieldを使わずに公式のget_term_metaで出力できまので大抵のテーマでは間に合うでしょう。これでいざACFとの離婚協議が始まっても、優位にたてるというわけです。

以下をfunctions.phpに書き込みます。

Advanced Custom Fieldsのタームメタ変更に合わせてwp_term_metaを上書き

add_filter( 'acf/update_value', 'acf_update_term_meta', 11, 3 );
function acf_update_term_meta($value, $post_id, $field) {
    $term_id = intval(filter_var($post_id, FILTER_SANITIZE_NUMBER_INT));
    if($term_id > 0) update_term_meta($term_id, $field['name'], $value);
    return $value;
}

たとえばカテゴリに画像IDを登録したとして、それをテンプレートから出力する際は、以下様になります。wp_term_metaを呼び出す、つまりwpのデフォルト関数を使うだけ。シンプルですね。

$term_img = get_term_meta( $term_id, 'category_image', true );
if( $term_img ) {
  echo wp_get_attachment_image ( $term_img, 'thumbnail' );
}

 

welcart sort product

アーカイブページのループに在庫や価格でのソート・絞り込みを反映させる。

在庫がないのに商品が表示されているのは楽●の空売りみたいで鬱陶しい。商品数が多ければなおのこと。ところが、通常のqueryにwelcartの在庫を 反映させることはできません。一旦ループから離脱して再ループさせれば擬似的に実現できるが、ページ送りやレイアウト崩れの可能性を考えるとテンプレート ごとに細かな対応が必要で面倒臭い。

で、困った時のウェルカスタムさんで探したところ「queryに在庫情報を組み込む現実的な解決法」が掲載されていた。ここによく纏められているように、在庫状態ではなく在庫数で判別しているので縛りがあること、また、複数SKUを持つ商品の場合の処理など、ウェルカートのSKUがシリアライズされているので、価格でのソートなども含めてクエリでの絞り込みの実現は難しそうだ。

ということで、現状はカスタムフィールドにデータを持たせるのが唯一の解決策と思われたので、最終的に以下のようにカスタマイズすることにしました。

各商品記事のカスタムフィールドに必要な情報を書き込む処理

ソートすることを目的にするなら、独立したカスタムフィールドにクエリから参照しやすように数値で登録されていることがベストでしょう。

まずは、以下のようにsave_postにフックしてにソート用のカスタムフィールドを書き込むことにしました。ついでに usces_action_reg_orderdataという受注確定後に処理されるフックがあったので、それにも引っ掛けることにする。 usces_have_skus()はループ内で複数回使うとだめだったりと、扱いが難しいので、get_skusでpostIDからskuのデータ をすべて取得、直接在庫の有無を呼び出す方法を採用、skuを複数展開されていても大丈夫なように、ステータスを一旦配列に入れてから最小の値だけ取り出 すことにします。これで、在庫がなくなったら反映されるという基本要件を満たしてくれます。ちなみに最後のcurrent_screenへのフックはというと、商品マスターの「最新の情報に更新」ボタンを押すとすべての商品データのカスタムフィールドを設定してくれる、という我ながらなんという親切設計!!

/*
* WELCART PRODUCT SORT
* Plugin URI: //web.contempo.jp/weblog/tips/p5438
* Author: Mizuho Ogino 
* Version: 1.0
* License: //www.gnu.org/licenses/gpl.html GPL v2 or later
*/

add_action( 'save_post', 'usces_update_postmeta_for_sorting', 10 );
function usces_update_postmeta_for_sorting( $post_id ){ // 各カスタムフィールドの更新
    if ( !get_post_meta( $post_id, '_itemCode', true ) ) return;
    global $usces;
    $_itemStock = $_itemPrice = array();
    $skus = $usces->get_skus( $post_id );
    if ( $skus ): foreach ( $skus as $sku ): 
        $_itemStock[] = (int)$sku['stock'];
        if ((int)$sku['stock'] == 4 ) continue; // 廃盤を回避
        $_itemPrice[] = (int)$sku['price']; 
    endforeach; endif;
    if ( $_itemStock ) {
        update_post_meta( $post_id, '_itemStock', min( $_itemStock ) ); // 0:在庫あり 1:在庫僅少 2:売り切れ 3:入荷待ち 4:廃盤 の中で一番低いステータス
    }
    if ( $_itemPrice ) {
        update_post_meta( $post_id, '_itemPriceMin', min( $_itemPrice ) ); // SKU中の一番安い設定価格
        update_post_meta( $post_id, '_itemPriceMax', max( $_itemPrice ) ); // SKU中の一番高い設定価格
    }

    global $wpdb;
    $sold = 0;
    $datestr = substr(get_date_from_gmt(gmdate('Y-m-d H:i:s', time())), 0, 10);
    $yearstr = substr($datestr, 0, 4);
    $monthstr = substr($datestr, 5, 2);
    $daystr = substr($datestr, 8, 2);
    $order_table_name = $wpdb->prefix . "usces_order";
    $order_date = date('Y-m-d H:i:s', mktime(0, 0, 0, (int)$monthstr, ((int)$daystr-30), (int)$yearstr)); // 30日分のDBを検索
    $query = "SELECT order_cart FROM {$order_table_name} WHERE order_date >= '{$order_date}'";
    $dbres = $wpdb->get_col($query);
    if( $dbres ): foreach( (array)$dbres as $carts ):
        $rows = unserialize($carts);
        foreach( (array)$rows as $carts ){
            if ( $post_id == $carts['post_id'] ) $sold = $sold + $carts['quantity'];
        }
    endforeach; endif;
    update_post_meta( $post_id, '_itemPopular', $sold ); // 売上数を登録

    return $post_id;
}

add_action( 'usces_action_reg_orderdata', 'usces_action_reg_orderdata_update_postmeta' );
function usces_action_reg_orderdata_update_postmeta( $args ){ // 在庫に変動があればカスタムフィールドを更新
    extract( $args );
    foreach( $cart as $cartrow ){
        $post_id = $cartrow['post_id'];
        usces_update_postmeta_for_sorting( $post_id );
    }
}

add_action( 'current_screen', 'usces_add_actions_to_admin_current_screen' );
function usces_add_actions_to_admin_current_screen( $current_screen ){ // 「最新の情報に更新」ボタンですべてのカスタムフィールドを更新
    if( isset($_GET['page']) && 'usces_itemedit' == $_GET['page'] && isset($_REQUEST['refresh']) ){
        $get_posts = get_posts( array( 'meta_key' => '_itemCode', 'post_type' => 'post', 'numberposts' => -1 ) );
        if( $get_posts ): foreach ( $get_posts as $val ) : 
            usces_update_postmeta_for_sorting( $val->ID );
        endforeach; endif; 
    }
}

welcartにはget_bestseller_idsという関数があったので、当初は「人気順」もダイレクトにベストセラーの順位を登録するように設計してみました。しかしショップサイトの問題点として、「価格」や「在庫」が絶対的な情報であるのに対して、商品の「人気順」が相対的な数値ということがあります。つまり1点売り上げがあるとすべての順位に変動が生じてしまうので、一々すべての商品のカスタムフィールドを更新しなくてはならなくなり、延いてはユーザーサイドの表示速度に影響が出る可能性もあります。wp_cronなどを用いて定期更新にする手も考えましたが、それでも二段階更新になることには変わりないので、人気順の代わりにbestseller_idsも参照している1ヶ月の「売上数」をカウントしてカスタムフィールドに登録することにしました。これならば、売上があった際に該当商品を変更するだけで済みます。(とはいえ、在庫数の変動や記事の更新時にカウントされているので、しばらく売上がない商品は更新されないので完全とは言えない。厳密さを求める向きは手動反映かcronの設置をどうぞ。)

アーカイブページ内での商品一覧のソート処理

ループ全般にフックしてくれるpre_get_postという便利な関数を使用します。$_GET[‘instock’]で在庫の有無を、$_GET[‘sort’]で並び順を変更するという仕様。デフォルトで在庫がないものは通常ループ内で非表示に設定してあります。

つまり、セレクトボックスなどで、カテゴリページのリンクに以下の様に絞り込み用のクエリを設定してやれば、ループが自動的に読み込まれるわけです。例としては以下のようになります。

価格の安い順:
//www.example.com/category/item?sort=price_desc

価格の高い順:
//www.example.com/category/item?sort=price_asc

価格高い順、かつ在庫のない商品もすべて表示:
//www.example.com/category/item?sort=price_asc&instock=false

 

add_action( 'pre_get_posts', 'usces_custom_sort_item', 10, 1 );
function usces_custom_sort_item( $query ) {
    if ( is_admin() || !$query->is_main_query() ) return;
    if ( $query->is_search ) {
        set_query_var('post_type', 'post');
    }
    if ( $query->is_category() || $query->is_tag() ) {
        $args = array();
        $sort = isset($_GET['sort']) && is_string($_GET['sort']) ? $_GET['sort'] : '';
        if ( $sort ){
            if ( $sort == 'price_asc' ) { //価格の安い順 'price_asc'の値は任意に変更可
                $query->set( 'meta_key', '_itemPriceMin' );
                $query->set( 'orderby', array( 'meta_value_num' => 'ASC', 'date' => 'DESC' ) );
            } elseif ( $sort == 'price_desc' ) { //価格の高い順 'price_desc'の値は任意に変更可
                $query->set( 'meta_key', '_itemPriceMax' );
                $query->set( 'orderby', array( 'meta_value_num' => 'DESC', 'date' => 'DESC' ) );
            } elseif ( $sort == 'popular' ) { //人気順(一定期間の売上数の多い順) 'popular'の値は任意に変更可
                $query->set( 'meta_key', '_itemPopular' );
                $query->set( 'orderby', array( 'meta_value_num' => 'DESC', 'date' => 'DESC' ) );
            }
        }
        $instock = isset($_GET['instock']) && is_string($_GET['instock']) ? $_GET['instock'] : '';
        if ( $instock !== 'false' ) { //在庫の有無で抽出 'false'の値は任意に変更可
            $query->set( 
                'meta_query' , array(
                    'relation' => 'OR',
                    array(
                        'key' => '_itemStock',
                        'value' => array( 0, 1 ),
                        'compare' => 'IN',
                    ),
                    array(
                        'key' => '_itemStock',
                        'compare' => 'NOT EXISTS',
                    ),
                    $args
                )
            );
        } elseif ($args ) {
            $query->set( $args );
        }
    }
}

add_filter( 'paginate_links', 'usces_append_query_string', 10 );
add_filter( 'term_link', 'usces_append_query_string', 10 );
function usces_append_query_string( $url ) {// get_term_link // paginate_links のクエリ書き換え
    if ( isset( $_GET['instock'] ) ) $url = add_query_arg( 'instock', $_GET['instock'], $url );
    if ( isset( $_GET['sort'] ) ) $url = add_query_arg( 'sort', $_GET['sort'], $url );
    return $url;
}

言わずもがなですが、在庫がない場合 if ( $instock !== ‘false’ ) のところを if ( $instock === ‘true’ ) とかにしてやれば、trueが設定されている時に「在庫あり」のみを表示(在庫なしは表示しない)というように反転できます。

paginate_linksはその名の通りページネーションやカテゴリのリンク出力にフックしてくれるフィルターで、ページを送ったらソートが解除されると困るので設定してあります。term_linkはカテゴリを選択していってもクエリを継続させます。絞り込み系のサイト構成に向いています。入らなければコメントアウトしましょう。

 

リンクの実際の出力方法など

並べ替えボタンの出力例も書いておきます。

<?php
    $current_url = (empty($_SERVER["HTTPS"]) ? "http://" : "https://") . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
    $sort = isset($_GET['sort']) && is_string($_GET['sort']) ? $_GET['sort'] : '';
    foreach ( array( 'date'=>'新着順','price_asc'=>'安い順','price_desc'=>'高い順','popular'=>'人気順' ) as $key => $val ):
        $sort_option[ $key ] = "\t\t\t" .'<a class="sort-order'. ( $sort == $key ? ' selected': '' ).'" value="'.$key.'" href="'.( $key == 'date' ? remove_query_arg( 'sort', $current_url ) : add_query_arg( 'sort', $key, $current_url ) ).'" data-target="'.$key.'">' .$val. '</a>'. "\n";
    endforeach;
    $instock = isset($_GET['instock']) && is_string($_GET['instock']) ? $_GET['instock'] : '';
    foreach ( array( 'true'=>'在庫あり','false'=>'すべて表示' ) as $key => $val ):
        $sort_option[ $key ] = "\t\t\t" .'<a class="sort-order'. ( $sort == $key ? ' selected': '' ).'" value="'.$key.'" href="'.( $key == 'date' ? remove_query_arg( 'sort', $current_url ) : add_query_arg( 'sort', $key, $current_url ) ).'" data-target="'.$key.'">' .$val. '</a>'. "\n";
    endforeach;
?>

<select class="sort-group">
    <option value="date" data-url="<?php echo remove_query_arg( 'sort', $current_url ); ?>"<?php echo ( !$sort ? ' selected': '' ); ?>>新着順</option>
    <option value="price_asc" data-url="<?php echo add_query_arg( 'sort', 'price_asc', $current_url ); ?>"<?php echo ( $sort == 'price_asc' ? ' selected': '' ); ?>>価格の安い順</option>
    <option value="price_desc" data-url="<?php echo add_query_arg( 'sort', 'price_desc', $current_url ); ?>"<?php echo ( $sort == 'price_desc' ? ' selected': '' ); ?>>価格の高い順</option>
    <option value="popular" data-url="<?php echo add_query_arg( 'sort', 'popular', $current_url ); ?>"<?php echo ( $sort == 'popular' ? ' selected': '' ); ?>>人気順</option>
</select>
<select class="instock-group">
    <option value="true" data-url="<?php echo remove_query_arg( 'instock', $current_url ); ?>">在庫あり</option>
    <option value="false" data-url="<?php echo add_query_arg( 'instock', 'true', $current_url ); ?>">すべて表示</option>
</select>
<script type="text/javascript" charset="utf-8">
    jQuery( 'select.sort-group, select.instock-group' ).change(function() {
        window.location = jQuery( this ).find( 'option:selected' ).data( 'url' );
    });
</script>

thumbnail-images

自作テーマや管理画面内でもずっと添付画像をループで呼び出してサムネイル表示をしてきていたので、アイキャッチ画像というものを使ってこなかった。最近プラグインやらテーマやらでアイキャッチ画像を利用しているものにちょこちょこ出くわすのと、一枚のサムネイルのためにいちいちループで呼び出すのもいい加減面倒なのとで、いまさらながら導入していこうと思った。

そもそもアイキャッチを使ってこなかったのは、クライアントにいちいちアイキャッチ画像を設定するんですよ、というのは面倒と言うかミスの元だからだ。なので、記事を保存するときにアイキャッチ画像を設定していないときは自動的に添付画像の最初のものをアイキャッチ画像に設定するようにした関数がこちら。

アイキャッチ画像と言ってもIDがカスタムフィールドに登録されるだけなので、どんなオリジナルテーマでも邪魔にならないし、重たくもならない。なので今後のためにもfunctions.phpに入れるだけ入れて裏で走らせておこうかと思っています。

 

// 自動でアイキャッチ画像を設定する

function save_default_thumbnail( $post_id ) { // アイキャッチ画像を自動で設定する 
 if ( wp_is_post_revision( $post_id ) ) return $post_id; 
 $get_captype = get_post_type_object( get_post_type( $post_id ) );
 if ( $get_captype && $get_captype->capability_type == 'post' && $get_captype->public == true ){ 
 // 投稿タイプのキャパビリティがが「post」(ページは含まない)かつ、パブリック投稿タイプであること
 $post_thumb = get_the_post_thumbnail( $post_id );
 if ( empty($post_thumb) ) { // no featured image
 $attaches = get_posts( 'post_parent='.$post_id.'&numberposts=1&post_type=attachment&post_mime_type=image&orderby=menu_order&order=ASC' );
 if ( $attaches ):
 update_post_meta( $post_id, '_thumbnail_id', $attaches[0]->ID );
 endif;
 }
 }
 return $post_id;
}
add_action( 'save_post', 'save_default_thumbnail' );

実際に使う際は、テーマによってカスタムフィールドに入力された画像IDを優先させたり、細かいカスタマイズを行うと良いと思います。
(2016/2.27 一部プラグインとコンフリクトしてる感じだったので、投稿タイプで判別するコードを追加しました。)

Image Uploader for Welcart

Image Uploader for Welcart

Image Uploader for Welcartwordpress.orgから最新版をダウンロードしてください。
「Image uploader for Welcart」はコルネ株式会社さんが提供されているプラグイン「Welcart e-commerce」専用のイメージアップローダーです。お使いのwordpressに「Welcart e-commerce」をインストールしてからご利用ください。最新版同士※1でのご使用を推奨しております。なお、不具合等がありましたら、ここのコメント欄かWP公式のサポートスレッドにてご報告※2ください。

※1 WordPress4.5.4からメディアのアップロード時のサニタイズ仕様が変更になりました。Ver4.5.4+で使用する場合は必ずwelcart1.9+ Image Uploader1.4+をご使用ください。
※2 Welcartのフォーラムでは当プラグインに関する質問はお答えできません。

 

Welcart専用の画像アップローダーを商品情報編集ページに設置する

welcartは画像の名前の持ち方が制限があり、[商品コード–.jpg]としなくてはならない。CSVで管理したり一気に流し込むときにはとても便利なのだけど、ちまちま手作業で更新する小規模ウェブショップだとちょっと面倒。ましてCMSとして納品する場合、ウェブショップの運営者が不慣れだったり、担当者が変更になって引き継ぎが上手くいかなかったり…、と言うのはよくある話。何はともあれ、間違いが起きにくいように「画像あげたいな→ボタンがある→こんな感じかな→よしオッケー♪」という流れにしたい。
つまり…

商品情報編集ページから画像をアップロードできるようにする

アップロードした画像のタイトルをwelcart仕様に自動リネームし商品画像として登録する

編集画面上でドラッグで表示順を並べ替えられるようにする

…でも

welcartのメディアライブラリによる一括アップロード&紐付け機能は維持

ということが実現したいわけです。

 

商品情報編集画面でのアップロード&操作方法

rfw-01

設置すると上図のように、デフォルトの商品画像ボックスが削除され新たに専用のメタボックスが表示されます。(メタボックスはサイド表示を想定していますが、ノーマル表示やタブレットなどの小さい画面などwordpressのメタボックスソートやレスポンシブデザインにも対応しています。)

 

rfw-02

画像をアップロードします。

① 画像追加ボタンを押すとアップローダーが立ち上がります。

② 画像をアップロードします。

③ 「商品画像を選択」ボタンを押します。(複数まとめてどうぞ)

④ 選択された画像がメタボックスに表示されます。

 

rfw-03

⑤ サムネイルをドラッグして並べ替えることで、welcartの画像並びに反映されます。一番上に来る画像がメイン画像として設定されます。

⑥ 画像右上のデリートボタンを押すと商品画像の登録を解除できます。
デリートした画像は、投稿に添付された状態でライブラリに残ります。これがけっこうミソで、在庫でバリエーションがあったり無かったりの時に画像をアップロードしたり削除したりしなくても、すぐに元にもどせるようになります。一時的にカラーやサイズのバリエーションなどの写真だけ隠す、というような使い方をするときに便利です。

⑦ 商品を公開/更新します。画像が自動でリネームされ、welcartに登録(または登録解除)されます。メイン画像はアイキャッチ画像にも自動的に登録されます。
上の図では、3つの画像はそれぞれTEST-PRODUCT(一番目のメイン画像), TEST-PRODUCT–1(サブ画像1), TEST-PRODUCT–2(サブ画像2)と自動でリネームされています。自動で設定されるが好ましくない場合は、以下のコードをfunctions.php等に記載することでオート機能をオフにしてください。なお、オート機能をオフにしていても、アイキャッチ画像が選択されていない時は、自動的にトップの画像が設定されます。

add_filter('iu4w_auto_thumbnail', '__return_false');

 

メディアライブラリからまとめてアップロードする

welcartの形式通りアップロードすればwelcartに反映されます

メディアライブラリの画像アップローダーから商品コード名の画像がアップされた場合、商品情報ページを開いたときに自動的に商品投稿をアップロード先として紐付けされます

SKU–数字.jpg形式のものを重複して上げてしまっても個別にインデクスされますので、形式さえ合っていれば適当なナンバリングで問題ありません。(WP4.5.4からファイルのサニタイズ仕様が変更になっているためWP4.5.4+を仕様する場合は必ずwelcart1.9+ Image Uploader1.4+を使用してください。詳細はwelcart公式の案内をご覧ください。)

rfw-04
画像が反映されているはずですので、並べ替えなどを行って更新して下さい。

 

設置方法&出力方法

プラグインとして読み込んで有効化すれば、自動的に設置されます。

画像の呼び出し方はwelcartの機能のままですのでテーマに手を入れる必要はありません。

 

Change log

  • 1.4.12017/02/24レイアウトを改善するとともに代替テキストやキャプションを入力可能に。wp.media.jsで起きていたTypeErrorをfix。
  • 1.4.02016/10/01welcart1.9以降のsubimage_ruleに対応。
  • 1.3.92016/09/19バグフィクス。
  • 1.3.82016/09/11プラグインの記述をクラス対応に変更。
  • 1.3.72016/05/30テキストドメインをglotpress対応に変更。レスポンシブ時のCSSを修正。
    1.3.72016/05/30テキストドメインをglotpress対応に変更。レスポンシブ時のCSSを修正。
  • 1.3.6.12015/11/24商品多数時の保存・並び替えバグをフィクス。
  • 1.3.62015/11/20UIを変更、それに伴いJS等の処理を修正、画像無し保存時のエラーをデバッグ。
  • 1.3.52015/10/17バグフィクス。
  • 1.3.42015/09/12コンフリクト回避のためコードを変更。
  • 1.3.22015/01/18メディアライブラリから一括でアップロードした画像が重複したpost_titleを持つ場合もプラグインが認識して読み込むように変更。
  • 1.32015/01/07正式版1.3としてプラグインをリリース。極力DBを汚さないようにカスタムフィールドを使う仕様をやめました。更新の混乱を避けるためここで公開していたコードは消去。
  • 1.2.12014/12/11画像をセレクト後「商品画像を選択」ボタンを押さずにウィンドウを閉じた場合でも画像をセレクトしてしまう動作を修正。
  • 1.22014/10/08レスポンシブデザイン化。WP4.0のメディアアップローダの仕様に併せて記述変更、アップローダ内での画像削除に対応。※WP3.9以前は旧バージョン1.2をご使用ください。
  • 1.1.12014/05/24wp_update_postで商品の複製ができる問題に対処。画像アップ後にSKUを変更してもリネームされなかった問題に対処。SKU変更に応じて画像も自動リネームされるように。
  • 1.12014/04/25アップローダーの仕様を変更。よりシンプルにしました。
  • 1.02014/04/23公開。

sc-2014-10-02-16.38

PLUGIN : MY UPLOAD IMAGES

My upload imageswordpress.orgから最新版をダウンロードしてください

 

wordpressの投稿画面にメディアアップローダー付きのメタボックスを設置

カスタムフィールドテンプレートなどの便利なプラグインがあるので、画像だけのメタボックスが必要になることは少ないでしょう。しかしシンプルな設計のギャラリーページなどには多機能すぎることもしばしばあります。My upload imagesは機能をシンプルにして画像の並べ替えとIDの取得にのみ特化したプラグインです。

投稿タイプを指定します

メタボックスを表示する投稿タイプを管理画面の「設定」から選択できます。
screenshot-1-jp

カスタムフィールドに画像IDを登録する

オリジナルテンプレートでポートフォリオのような機能を持たせつつ普通のエントリにも添付画像を使いたい、なんてテーマを作るときはギャラリー用のメディアアップローダーを設置してカスタムフィールドにIDを登録したりできると便利です。「画像の追加・削除」ボタンでアップローダーが起ち上がります。get_post_metaで呼び出してforeachすれば画像のIDを取ることができます。(下記参照)

ドラッグで手軽に画像を並べ替える

管理者画面のsortable.jsを流用しています。ドラッグでソートできる他、サムネイルの右上の×印をクリックするとカスタムフィールドからIDを削除できます。

レスポンシブに対応

WPの管理画面のレスポンシブデザインに対応して自由な位置にメタボックスを表示できます。

 

設置&出力方法

プラグインとして読み込み、有効化して下さい。「設定」リンク内にある「マイアップロード画像」より投稿タイプを指定して下さい。

テーマ内で使用するには、ループ中でカスタムフィールドの配列を呼び出します。例えば、下のようになります。

シンプルな出力例

<?php
$my_upload_images = get_post_meta( $post->ID, 'my_upload_images', true );
if ( $my_upload_images ): foreach( $my_upload_images as $img_id ):
 $full_src = wp_get_attachment_image_src ($img_id,'fullsize');
 if ( !$full_src ) continue;
 echo 
 '<a href="'.$full_src[0].'">'.wp_get_attachment_image ($img_id,'thumbnail').'</a>'."n";
endforeach; endif; 
?>

画像に付随する色々なデータを扱う場合の出力例

<?php
$my_upload_images = get_post_meta( $post->ID, 'my_upload_images', true );
$slider = '';
if ( $my_upload_images ): 
 foreach( $my_upload_images as $img_id ):
 $full_src = wp_get_attachment_image_src ($img_id,'fullsize');
 if ( !$full_src ) continue;
 $file = get_post( $img_id );
 $img_title = $file->post_title; // title
 $img_caption = $file->post_excerpt; // caption
 $img_desc = $file->post_content; // desctiprion
 $img_alt = get_post_meta( $img_id, '_wp_attachment_image_alt', true ); // alt
 $thumb_src = wp_get_attachment_image_src ($img_id,'thumbnail');
 $slider .= 
 "t".'<li>'."n".
 "tt".'<a href="'.$full_src[0].'"'.( $img_title ? ' title="'.esc_attr( $img_title ).'"' : '' ).'>'."n".
 "ttt".'<img src="'.$thumb_src[0].'" width="'.$thumb_src[1].'" height="'.$thumb_src[2].'"'.( $img_alt ? ' alt="'.esc_attr( $img_alt ).'"' : '' ).'/>'."n".
 ( $img_title ? "ttt".'<div class="title">'.$img_title.'</div>'."n" : '' ).
 ( $img_desc ? "ttt".'<div class="caption">'.wpautop( $img_caption ).'</div>'."n" : '' ).
 "tt".'</a>'."n".
 "t".'</li>'."n";
 endforeach; 
 echo '<ul class="slider">'."n".$slider.'</ul>'."n";
endif; 
?>

*カスタムフィールドの値が複数なのではなく、一つの値の中で配列にしています。(順序を記録しやすいので。)get_post_metaで呼び出すとき3つ目のパラメータをfalseとやらないようにしてください。

(以前こちらで公開していたコードは、情報が古くなっているため、削除いたしました。ソースはプラグインを参照してください。)

Change log

  • 1.3.72015/11/16編集ボタンを追加、コード内の関数名を変更
  • 1.3.62015/10/18デバッグ
  • 1.3.52015/10/11デバッグ
  • 1.3.42015/09/12サムネイルにキャプションを表示
  • 1.3.32015/06/07メタボックスの位置を指定可能に
  • 1.3.22015/05/10アイキャッチ画像の自動作成に対応
  • 1.3.12015/01/15Javascript デバッグ
  • 1.32015/01/10パブリックバージョンリリース。WP4.1に対応。メディアエディタを呼び出すjQueryを変更しました。wordpressのメディアエディターを利用している都合上、複数サイトでの更新管理が煩雑なのでプラグイン化しました。投稿タイプを選べるように設定画面を追加しました。特にコードに触らないならプラグインでどうぞ。
  • 1.2.12014/12/11画像をセレクト後「画像を選択」ボタンを押さずにウィンドウを閉じた場合でも画像をセレクトしてしまう動作を修正。
  • 1.22014/10/10WPのレスポンシブデザインに対応してjavascriptとCSSを変更。
  • 1.12014/10/3WP4.0にあわせてメディアアップローダー内での画像削除に対応。(3.9以下は旧バージョンを使用して下さい。)
  • 1.02014/04/25イニシャルリリース