オープン/クローズおよび非表示/表示のメタボックスのステータスをポストごとに保存する方法は?


9

私の本当の問題は少し複雑なので、ここでそれを抽象化し、単純に保つようにします。

WordPressベースのカスタムアプリを開発しています。カスタム投稿タイプを登録しました。「人」と呼びましょう。ここでは、...人に関する情報を保存しています。

CPTは投稿タイトルと投稿コンテンツのデフォルトフィールドのみをサポートしますが、個人情報を保存するためのメタボックスがいくつかあります(私のアプリをアドレス帳と考えてください)。

したがって、個人情報を保存するメタボックス、ソーシャルネットワーク情報を保存するメタボックス、仕事関連の情報を保存するメタボックスがあります。つまり、その人が私にとって顧客である場合、サプライヤーである場合、クレジットまたはデビットがある場合...

ここでは簡略化しましたが、メタボックスの数は一貫しています。たとえば12としましょう。

私の問題は、情報を保存したい人がランダムな連絡先であり、個人情報のみを保存したい人、他の人は友達、個人情報とソーシャルネットワーク情報を保存したい人、その他は顧客またはサプライヤーであり、仕事関連の情報を保存したい。

投稿を編集するときに非表示にする(画面オプションメニューを使用)か、不要なメタボックスを閉じる場合、必要な場所で別の投稿を開くときに、再度表示するか開く必要があります。これは、メタボックスの位置/ステータス/順序がユーザーメタデータとしてユーザーごとに保存されるためです。

いくつかの投稿で2つのメタボックスが必要であると想像すると、10個と5個のメタボックスが必要です。それらすべてを表示/開いたままにすると、編集画面のアクセス性が低くなり(スクロールバーが無限に見える)、時々私が探す情報は煩わしいです。情報のないメタボックスの束の後のページの終わりに...

質問:

特定の投稿タイプのメタボックスの位置/ステータス/注文を投稿ごとに保存できますか?


PS:私は一部のjs / jQueryが問題を解決できることを知っていますが、可能であれば、JavaScriptソリューションを回避します。

回答:


8

主な問題:

ここでの主な問題は、closed-hidden-ordering- ajax呼び出しで、ペイロードと共に送信される投稿IDがないことです。2つのフォームデータの例を次に示します。

1) action:closed-postboxes
closed:formatdiv,tagsdiv-post_tag,trackbacksdiv,authordiv
hidden:slugdiv
closedpostboxesnonce:8723ee108f
page:post

2) action:meta-box-order
_ajax_nonce:b6b48d2d16
page_columns:2
page:post
order[side]:submitdiv,formatdiv,categorydiv,tagsdiv-post_tag,postimagediv
order[normal]:postexcerpt,postcustom,trackbacksdiv,commentsdiv,authordiv
order[advanced]:

これを回避するには、別のカスタムajax呼び出しを使用します。

もちろん、save_postフックにフックして、投稿が保存されるたびにデータを変更することもできます。しかし、それは通常のUIエクスペリエンスではないため、ここでは考慮しません。

以下で説明するように、PHPで利用できる別のエレガントでないソリューションがあります。

JavaScript以外のソリューション:

問題は、データをどこに保存するかです。ユーザーメタデータとして、投稿ますか、それともカスタムテーブル内ですか?

ここでは、ユーザーメタデータとして保存し、ポストメタボックスのクローズを例に取ります。

ときにclosedpostboxes_postメタ値が更新され、我々はにそれを保存するclosedpostboxes_post_{post_id}だけでなくメタ値。

次に、のフェッチをハイジャックして、closedpostboxes_postユーザーIDと投稿IDに基づく対応するメタ値でオーバーライドします。

a)closed-postboxesajaxアクション中の更新:

を介して投稿IDを取得し wp_get_referer()、便利なurl_to_postid()関数を使用できます。数か月前に@s_ha_dumから回答を読んだ後、私はこの「おかしい」関数を最初に知りました;-)残念ながら、関数は?post=123GET変数を認識しません が、それをp=123回避するために変更するだけで少しトリックを実行できます。

にフックできupdated_user_metaます。これは、のユーザーメタデータclosedpostboxes_postが更新された直後に起動されます。

add_action( 'updated_user_meta',                           
    function ( $meta_id, $object_id, $meta_key, $_meta_value )
    {
        $post_id = url_to_postid( str_replace( 'post=', 'p=', wp_get_referer() ) );
        if( 'closedpostboxes_post' === $meta_key && $post_id > 0 )
            update_user_meta( 
                $object_id, 
                'closedpostboxes_post_' . $post_id, 
                $_meta_value 
            );
    }
, 10, 4 );

b)データの取得:

フックにフックしてget_user_option_closedpostboxes_postclosedpostboxes_postユーザーメタからフェッチされたデータを変更できます。

add_filter( 'get_user_option_closedpostboxes_post',
    function ( $result, $option, $user )
    {
        $post_id = filter_input( INPUT_GET, 'post', FILTER_SANITIZE_NUMBER_INT );
        $newresult = get_user_option( 'closedpostboxes_post_'. $post_id , $user->ID );
        return ( $newresult ) ? $newresult : $result;
    }
, 10, 3 );

また、closedpostboxes_post_{post_id}利用できる投稿ベースがない場合についても考えたいと思うかもしれません。そのため、最後に保存されたからの設定が使用されますclosedpostboxes_post。たぶん、そのデフォルトのケースでは、それをすべて開いたり、すべて閉じたりしたいでしょう。この動作を変更するのは簡単です。

他のカスタム投稿タイプについては、対応するclosedpostboxes_{post_type}フックを使用できます。

同じことが可能であるべき秩序隠ぺいとmetaboxesのmetaboxhidden_{post_type}meta-box-order_{post_data}ユーザーメタ。

PS:週末は長すぎるのでごめんなさい。いつも短いのでおかしいです;-)


素晴らしい+1。長い答えのN / P、短い答えは期待できません。ユーザごとにデータを保存するために第一のアイデア:私は、私はとても気に入って週末にどの:) 2つのことを期待していなかった正直に言うと、投稿ごと:私の考えは、ポストメタに格納することでしたが、その方法ですべてのユーザーは同じステータスになります。'get_user_option_*_post'WPにカスタムデータを認識させるための2番目のアイデア。私があまり好きではないと思うのは、本当に信頼できない varでの使用ですwp_get_refererが、「主な問題」を克服するためのアイデアがあると思います;)$_SERVER
gmazzap

おかげで、データを保存するのに最適なユーザーと投稿の数に依存すると思います。たぶん、このデータにはTTLがあり、たとえば月に1回消去される必要がありますか?はい、私はwp_get_referer()メソッドについてあなたに同意します、それが私がそれを非エレガントなPHPソリューションと呼んだ理由です;-)最初に各ユーザーの現在の投稿IDを保存することを考えましたが、ユーザーが2人以上編集している場合は機能しませんブラウザに投稿します。「主な問題」についてのあなたの考えについて聞いて楽しみにしてください週末を楽しんでください;-)
バージレ

43日後、賛成投票でこれに答えるように言いました。回答ありがとうございます。
gmazzap

6

彼の回答birgireが指摘したように、WordPressはAJAXを使用してメタボックスのステータスを更新し、AJAXリクエストで渡されたデータには投稿IDが含まれていないため、投稿ごとにボックスのステータスを更新することは困難です。

WordPressで使用されているAJAXアクションがであることがわかったら'closed-postboxes'、admin jsフォルダーでこの文字列を検索して、WordPressがAJAXリクエストを作成する方法を見つけました。

私はそれがpostbox.js118行目で起こっているのを見つけました。

それはそのように見えます:

save_state : function(page) {
  var closed = $('.postbox').filter('.closed').map(function() {
      return this.id;
    }).get().join(',');
  var hidden = $('.postbox').filter(':hidden').map(function() {
      return this.id;
    }).get().join(',');
  $.post(ajaxurl, {
    action: 'closed-postboxes',
    closed: closed,
    hidden: hidden,
    closedpostboxesnonce: jQuery('#closedpostboxesnonce').val(),
    page: page
  });
}

基本的に、WordPressはクラス「postbox」とクラス「closed」のDOMアイテムを調べ、IDのコンマ区切りリストを作成します。クラス 'postbox'の隠されたDOMアイテムについても同じことが行われます。

したがって、私の考えは次のとおりです。適切なクラスがあり、非表示になっている偽のメタボックスを作成し、そのIDを投稿IDを含むように設定して、AJAXリクエストで取得できます。

これは私がやったことです:

add_action( 'dbx_post_sidebar', function() {
    global $post;
    if ( $post->post_type === 'mycpt' ) {
        $id = $post->ID;
        $f = '<span id="fakebox_pid_%d" class="postbox closed" style="display:none;"></span>';
        printf( $f, $id );
    }
});

このようにして、常に閉じて常に非表示のメタボックスを作成しました。そのため、WordPressはそのIDを$_POSTAJAXリクエストでvar として送信します。偽のボックスIDに予測可能な方法で投稿IDが含まれると、投稿を認識できます。

その後、WordPressがAJAXタスクを実行する方法を確認しました。

admin-ajax.php線72で、ワードプレスは、フック'wp_ajax_closed-postboxes'優先順位1と。

したがって、WordPressの前に行動するために、同じアクションを優先度0でフックすることができました。

add_action( 'wp_ajax_closed-postboxes', function() {

    // check if we are in right post type: WordPress passes it in 'page' post var
    $page = filter_input( INPUT_POST, 'page', FILTER_SANITIZE_STRING );
    if ( $page !== 'mycpt' ) return;

    // get post data
    $data = filter_input_array( INPUT_POST, array(
        'closed' => array( 'filter' => FILTER_SANITIZE_STRING ),
        'hidden' => array( 'filter' => FILTER_SANITIZE_STRING )
    ) );

    // search among closed boxes for the "fake" one, and return if not found
    $look_for_fake = array_filter( explode( ',', $data[ 'closed' ] ), function( $id ) {
         return strpos( $id, 'fakebox_pid_' ) === 0;
    } );
    if ( empty( $look_for_fake ) ) return;

    $post_id = str_replace( 'fakebox_pid_', '', $look_for_fake[0] );
    $user_id = get_current_user_id();

    // remove fake id from values
    $closed = implode(',', array_diff( explode(',', $data['closed'] ), $look_for_fake ) );
    $hidden = implode(',', array_diff( explode(',', $data['hidden'] ), $look_for_fake ) );

    // save metabox status on a per-post and per-user basis in a post meta
    update_post_meta( $post_id, "_mycpt_closed_boxes_{user_id}", $closed );
    update_post_meta( $post_id, "_mycpt_hidden_boxes_{user_id}", $hidden );

}, 0 );

ポストメタに保存されたデータを持つことは、フィルターにそれが可能になったget_user_option_closedpostboxes_mycptget_user_option_metaboxhidden_mycpt(の両方のバリエーションget_user_option_{$option}ポストメタからWordPressのロードオプションを強制的にフィルター):

add_filter( 'get_user_option_closedpostboxes_mycpt', function ( $result, $key, $user ) {
    global $post;
    $meta = get_post_meta( $post->ID, "_mycpt_closed_boxes_{$user->ID}", TRUE );
    if ( ! empty( $meta ) ) {
        $result = $meta;
    }
    return $result;
}, 10, 3 );

そして

add_filter( 'get_user_option_metaboxhidden_mycpt', function ( $result, $key, $user ) {
    global $post;
    $meta = get_post_meta( $post->ID, "_mycpt_hidden_boxes_{$user->ID}", TRUE );
    if ( ! empty( $meta ) ) {
        $result = $meta;
    }
    return $result;
}, 10, 3 );

関連情報+1付きの隠しメタボックスを使用するなんて素晴らしいアイデア+1
バージニア'26 / 10/26

@birgireに感謝し、Aに再び感謝します。ユーザーごとと投稿ごとの両方でデータを保存するという考えはすべてあなた次第です:)
gmazzap
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.