web-dev-qa-db-ja.com

管理リストにカスタム投稿タイプとの間の階層関係を表示する

「リクエスト」と「見積もり」という2つのカスタム投稿タイプがあります。どちらも「階層型」フラグがtrueに設定されています。

'request' cptは、1つ以上の 'quote' cptの親になることができます。

これらは2つの異なる投稿タイプであるため、WordPress管理者は両方のための別々の概要リスト(例えばedit.php?post_type = request)を持っています。

私が探しているのは、階層的なページリストがフォーマットされるのと同じ方法でリクエストの概要をフォーマットする方法です。例えば:

  • リクエスト1
    • 引用1
    • 引用2
  • リクエスト2
    • 引用3
    • 引用4

私は管理者側でこれを行う必要があります(私はフロントエンドを使用していないので)。

2
Marc

階層的な投稿タイプでWordPressが機能する方法は、投稿の親は常に同じ投稿タイプの子である必要があるということです。

そのため、管理画面では、edit.phpの投稿タイプはかなりハードコーディングされています。

ただし、WordPressが行うことは、WP_Queryを実行することです。ここで、 'post_type'引数は現在の引数です。

だから、あなたは何ができますか?

まず、2つのcpt管理画面をマージする場合、「quote」の管理画面を非表示にできます。それは非常に簡単です:投稿タイプを登録するとき、単に 'public'引数をfalseに設定してください:

$args = array(
   // all other args here
  'hierarchical' => TRUE
  'public' => FALSE
);
register_post_type( 'quote', $args );

そうすると、見積管理画面は表示されないため、「リクエスト」画面のみが表示されます。

あなたがしなければならないことは、クエリをインターセプトし、'post_type'引数を 'request'と 'quote'の両方を含む配列に設定することです。

そうすることの問題は、グローバルな「post_type」変数がその配列に設定されるが、WordPressは「post_type」がいくつかのエラーで終わる文字列を期待することです。このエラーを回避するには、グローバル'post_type'を強制的に文字列 'request'にするフックを見つける必要があります。

管理投稿テーブルの出力を担当するファイルをざっと見てから:'wp-admin/includes/class-wp-posts-list-table.php'スコープの良いフックはフィルターフック'edit_posts_per_page'であることがわかりました。

したがって、コード:

add_action( 'pre_get_posts', function( $query ) {
  if ( is_admin() ) { // do nothing if not is admin
    $scr = get_current_screen();
    // if in the right admin screen
    if ( $scr->base === 'edit' && $scr->post_type === 'request' ) {
      // force query to get both 'request' and 'quote' cpt
      $query->set( 'post_type', array( 'request', 'quote' ) );
      // force global $post_type to be = 'request' if is an array 
      add_filter( 'edit_posts_per_page', function( $perpage ) {
        global $post_type;
        if ( is_array( $post_type ) && in_array( 'request', $post_type ) ) {
          $post_type = 'request';
        }
        return $perpage; // we don't want to affect $perpage value 
      } );
    }
  }
  return $query;
} );
1
gmazzap