web-dev-qa-db-ja.com

author.phpとACFおよびCPT

これを書いている間、私はXY問題を避けるために最善を尽くします。

私がやろうとしていること:

私はauthor.phpテンプレートを作成しようとしています:

  • ユーザーのプロファイルページの詳細なカスタムフィールドのデータを表示します
  • 著者の投稿を表示します
    • ユーザーが作成したすべての投稿
    • すべてprojects(CPT)ユーザーがクレジットされている(CPTのACFフィールドを介して割り当てられる)

これを解決しようとした方法:

試行1(author.phpテンプレート)

私の最初の試み、そしてそれは大抵うまくいきました。このアプローチをやめさせたのは、ページネーションです。それについては後で詳しく説明します。 3つのクエリがありました。

  • 最初は、ユーザーが作成したすべての投稿を取得し、
  • 2番目は、ユーザーがクレジットされているすべてのプロジェクトを取得しました。
  • 3番目は、array_unique( array_merge($query1, $query2) )を介してpost__inを使用して、これら2つのクエリからの投稿を日付ごとにまとめて表示しました。

    <?php
    get_header();
    
    global $wp_query;
    if( !isset($whose_ID) ) {
        $whose_ID = $wp_query->queried_object->data->ID;
    }
    
    /*
    |==========================================================================
    | First Query gets all posts by author
    |==========================================================================
    */
    $args = array(
        'author' => $whose_ID,
        'post_type' => 'post'
    );
    $query1 = new WP_Query( $args );
    $first_set = array();
    foreach($query1->posts as $post) {
        $first_set[] = $post->ID;
    }
    wp_reset_postdata();
    
    /*
    |==========================================================================
    | Second Query gets all Projects that are credited to author
    |==========================================================================
    */
    $args2 = array(
        'post_type' => 'projects',
        'meta_key' => 'project_credits_%_user',
        'meta_value' => $whose_ID,
    );
    $query2 = new WP_Query( $args2 );
    $second_set = array();
    foreach($query2->posts as $post) {
        $second_set[] = $post->ID;
    }
    wp_reset_postdata();
    
    /*
    |==========================================================================
    | Then the two queries are merged to create a bag of posts to grab from
    |==========================================================================
    |
    | What sucks about this is the $third_query_allowed. I had to figure out
    | a way to make sure that the query didn't run on an empty array. Bah.
    |
    */
    $third_query_allowed = true;
    if( !empty($first_set) && !empty($second_set) ) {
        $merged_queries = array_unique( array_merge( $first_set, $second_set ) );
    } elseif (!empty($first_set) && empty($second_set) ) {
        $merged_queries = $first_set;
    } elseif ( empty($first_set) && !empty($second_set) ) {
        $merged_queries = $second_set;
    } else {
        $merged_queries = array();
        $third_query_allowed = false;
    }
    
    /*
    |==========================================================================
    | So then this third query does the work of getting all the posts and
    | displaying them on the author page.
    |==========================================================================
    */
    $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
    $args3 = array(
        'post_type' => array( 'post', 'projects' ),
        'post__in' => $merged_queries,
        'orderby' => 'post__in',
        'posts_per_page' => 2,
        'paged' => $paged
    );
    $user_connected_to_post = new WP_Query( $args3 ); ?>
    
    <div id="primary" class="">
        <main id="main" class="site-main" role="main">
    
            <?php
            // ACF Helper
            $search = 'user_'.$whose_ID;
    
            // Header Info
            // All of this Works!!
            $name = get_the_author_meta( 'display_name', $whose_ID );
            $job_title = get_field( 'job_title', $search );
            $user_favorite_color = get_field( 'user_favorite_color', $search );
            $user_featured_image = get_field( 'user_featured_image', $search );
            $user_still_image = get_field( 'user_still_image', $search );
            $user_gif = get_field( 'user_gif', $search );
            $user_mp4 = get_field( 'user_mp4', $search );
    
            if(!empty($user_featured_image) && !empty($user_favorite_color)) {
                $header_styles = "style=\"background:url('".$user_featured_image['url']."') no-repeat scroll center center ".$user_favorite_color."; background-size: 100% auto;\"";
            } elseif(!empty($user_featured_image) && empty($user_favorite_color)) {
                $header_styles = "style=\"background:url('".$user_featured_image['url']."') no-repeat scroll center center #efefef; background-size: 100% auto;\"";
            } elseif(empty($user_featured_image) && !empty($user_favorite_color)) {
                $header_styles = "style=\"background-color:".$user_favorite_color."\"";
            }
            ?>
    
            <div class="container-fluid">
                <div class="author-page-header row">
                    <div class="author-page-bg col-sm-12" <?php echo $header_styles; ?>></div>
    
                    <video class="img-circle the-vid author-page-img" width="250" height="250" loop="loop" muted="" autoplay="autoplay" poster="<?php echo $user_still_image['url']; ?>">>
                        <source type="video/mp4" data-source="<?php echo $user_mp4['url']; ?>">
                    </video>
                    <img class="img-circle the-img author-page-img" alt="" data-source="<?php echo $user_gif['url']; ?>">
                </div>
            </div>
    
            <div class="container">
                <div class="row">
                    <header class="author-page-name lower-divider text-center">
                        <h1><?php echo $name; ?></h1>
                        <h3><?php echo $job_title; ?></h3>
                    </header><!-- .author-name -->
                </div>
    
                <div class="row">
                    <div class="author-page-social">
                        <?php
                        // ACF Bug is keeping this from working at the moment.
                        echo three_sons_social_list( $search, array( 'bellyflop', 'dale-earnhardt' ) ); ?>
                    </div>
                </div>
    
                <div class="row upper-divider">
                    <div class="col-xs-10 col-xs-offset-1 col-sm-8 col-sm-offset-2 author-page-bio">
                        <p><?php echo get_the_author_meta( 'description', $whose_ID ); ?></p>
                    </div>
                </div>
    
                <?php
                /*
                |==========================================================================
                | here's all the author's posts (this works)
                |==========================================================================
                */
                if( $third_query_allowed === true ){
    
                    if ( $user_connected_to_post->have_posts() ) : ?>
    
                        <div class="row masonry-grid">
    
                            <?php while ( $user_connected_to_post->have_posts() ) : $user_connected_to_post->the_post();
    
                                if($post->post_type === "projects") {
                                    get_template_part( 'lib/partials/projects', 'masonry_item' );
                                } else {
                                    // default post listing
                                    get_template_part( 'lib/partials/content', 'masonry_item' );
                                }
    
                            endwhile; ?>
    
                        </div> <!-- .masonry-grid -->
    
                        <?php // THIS IS THE THING THAT DID NOT WORK ?>
                        <div class="nav-previous alignleft"><?php next_posts_link( 'Older posts', $user_connected_to_post->max_num_pages ); ?></div>
                        <div class="nav-next alignright"><?php previous_posts_link( 'Newer posts', $user_connected_to_post->max_num_pages ); ?></div>
    
                    <?php endif;
                    wp_reset_postdata();
                    wp_reset_query();
                } ?>
    
            </div><!-- .container -->
    
        </main><!-- #main -->
    </div><!-- #primary -->
    
    <?php get_footer();
    

404なしではページネーションを機能させることができなかったため、アプローチを変更しました。

試行2

author.phpテンプレートがメインクエリを使用する方法に関するいくつかの提案を読んだ後、pre_get_postsアクションでメインループを変更する関数に移行しました。すべてのクエリを独自の関数に移動し、著者のページに表示したい投稿の配列のみを返しました。 $query->set()を使用して、クエリの1つが無限ループであるという問題に遭遇しました。私のコードにはforeachループもwhileループもなかったので、それはまだ謎です。私は無限ループとロシア人形の機能のためにこの試みを放棄しました。

試行3

最終的に私はこのコードに着きましたが、理論的には動作するはずですが(動作しません)。 3つの直接$wpdbクエリが表示されます。不可解に無限のループで45分間Vagrantボックスを正常に無効にしたので、可能な限り無駄のないメモリ節約クエリを作成することにしました。これが実際に良いかどうかはわかりませんが、私がやったことです。それはポイントではありません。

merged_author_archive()

function merged_author_archive( &$query ) {

    // Only do this weird shit for the author pages.
    if ( $query->is_author ) {

        // Start with a fresh query (Whether this line is here or not makes no difference)
        wp_reset_query();

        global $wpdb;
        // holy shit this is so Gd complex it drives me crazy.
        // since the only thing that gets passed to wordpress on author.php (apparently) to start is the author name, that's what we're going to query.
        $author_Nice_name = $query->query['author_name'];

        // Get the Author ID from the nicename.
        $author_ID = $wpdb->get_results("SELECT id FROM $wpdb->users WHERE user_nicename LIKE '$author_Nice_name'");
        $author_ID = $author_ID[0]->id;

        // so we can get this on author pages.
        set_query_var( 'three_sons_author_id', $author_ID );

        // Get the IDs from posts authored and then save all the ids to $first_set
        $authored_posts = $wpdb->get_results("SELECT id FROM $wpdb->posts WHERE post_author = '$author_ID' AND post_type = 'post'");
        foreach ($authored_posts as $post) {
            $first_set[] = $post->id;
        }

        // Get the IDS from the projects credited
        $credited_projs = $wpdb->get_results("SELECT post_id FROM $wpdb->postmeta WHERE meta_key LIKE 'project_credits_%_user' AND meta_value = '$author_ID'");
        foreach ($credited_projs as $proj) {
            $second_set[] = $proj->post_id;
        }

        // First case: Both queries resulted in an array that wasn't empty.
        if( !empty($first_set) && !empty($second_set) ) {
            $just_these_posts = array_unique( array_merge( $first_set, $second_set ) );
        }
        // Second Case: Posts were not empty, but Projects were
        elseif (!empty($first_set) && empty($second_set) ) {
            $just_these_posts = $first_set;
        }
        // Third Case: Posts were empty, but Projects were not.
        elseif ( empty($first_set) && !empty($second_set) ) {
            $just_these_posts = $second_set;
        }

        // Here's the new $wp_query. We need to define the array of posts, and the post ids to send to the author page. Then we're done here.
        $query->set( 'post_type', array('post', 'projects') );
        $query->set( 'post__in', $just_these_posts );
    }

    // if it's not an author page, remove the action.
    remove_action( 'pre_get_posts', 'three_sons_merged_author_archive' );
}
add_action( 'pre_get_posts', 'three_sons_merged_author_archive' );

...およびその後のauthor.php

get_header();

// getting the author ID from the query. was set in lib/inc/author-functions.php
$whose_ID = get_query_var('three_sons_author_id');

// Header Info
$name = get_the_author_meta( 'display_name', $whose_ID );

// ACF
$search                     = 'user_'.$whose_ID;
$job_title                  = get_field( 'job_title', $search );
$user_favorite_color        = get_field( 'user_favorite_color', $search );
$user_featured_image        = get_field( 'user_featured_image', $search );
$user_still_image           = get_field( 'user_still_image', $search );
$user_gif                   = get_field( 'user_gif', $search );
$user_mp4                   = get_field( 'user_mp4', $search );

if(!empty($user_featured_image) && !empty($user_favorite_color)) {
    $header_styles = "style=\"background:url('".$user_featured_image['url']."') no-repeat scroll center center ".$user_favorite_color."; background-size: 100% auto;\"";
} elseif(!empty($user_featured_image) && empty($user_favorite_color)) {
    $header_styles = "style=\"background:url('".$user_featured_image['url']."') no-repeat scroll center center #efefef; background-size: 100% auto;\"";
} elseif(empty($user_featured_image) && !empty($user_favorite_color)) {
    $header_styles = "style=\"background-color:".$user_favorite_color."\"";
}
?>

<div id="primary" class="">
    <main id="main" class="site-main" role="main">

        <div class="container-fluid">
            <div class="author-page-header row">
                <div class="author-page-bg col-sm-12" <?php echo $header_styles; ?>></div>

                <video class="img-circle the-vid author-page-img" width="250" height="250" loop="loop" muted="" autoplay="autoplay" <? /*poster="<?php echo $user_still_image['url']; ?>" */ ?>>
                    <source type="video/mp4" data-source="<?php echo $user_mp4['url']; ?>">
                </video>
                <img class="img-circle the-img author-page-img" alt="" data-source="<?php echo $user_gif['url']; ?>">
            </div>
        </div>

        <div class="container">
            <div class="row">
                <header class="author-page-name lower-divider text-center">
                    <h1><?php echo $name; ?></h1>
                    <h3><?php echo $job_title; ?></h3>
                </header><!-- .author-name -->
            </div>

            <div class="row">
                <div class="author-page-social">
                    <!-- just for now... -->
                    <p class="text-center">Social Links will go here but they're currently broken for authors.</p>
                    <?php // echo three_sons_social_list( $search, array( 'bellyflop', 'dale-earnhardt' ) ); ?>
                </div>
            </div>

            <div class="row upper-divider">
                <div class="col-xs-10 col-xs-offset-1 col-sm-8 col-sm-offset-2 author-page-bio">
                    <p><?php echo get_the_author_meta( 'description', $whose_ID ); ?></p>
                </div>
            </div>

            <?php
            if ( have_posts() ) : ?>

                <div class="row masonry-grid">

                    <?php while ( have_posts() ) : the_post();

                        if($post->post_type === "projects") {
                            get_template_part( 'lib/partials/projects', 'masonry_item' );
                        } else {
                            // default post listing
                            get_template_part( 'lib/partials/content', 'masonry_item' );
                        }

                    endwhile; ?>

                </div> <!-- .masonry-grid -->

                <div class="nav-previous alignleft"><?php next_posts_link( 'Older posts' ); ?></div>
                <div class="nav-next alignright"><?php previous_posts_link( 'Newer posts' ); ?></div>

            <?php endif; ?>

        </div><!-- .container -->

    </main><!-- #main -->
</div><!-- #primary -->


<?php wp_reset_query();
get_footer();

基本的に、私はこの最新のコードshouldが機能すると信じています。しかし、そうではありません。何かが翻訳されていません。 author.phpvar_dump($wp_query); die;を実行すると、次のように表示されます(無関係なビットまたは機密ビットを削除しました)。

object(WP_Query)#258 (51) {
  ["query"]=>
  array(1) {
    ["author_name"]=>
    string(15) "author-slug"
  }
  ["query_vars"]=>
  array(64) {
    ["author_name"]=>
    string(15) "author-slug"
    ["post__in"]=>
    array(9) {
      [0]=>
      string(1) "1"
      [1]=>
      string(3) "102"
      [2]=>
      string(3) "160"
      [3]=>
      string(3) "196"
      [4]=>
      string(3) "199"
      [5]=>
      string(3) "201"
      [6]=>
      string(3) "206"
      [7]=>
      string(3) "162"
      [8]=>
      string(3) "198"
    }
    ["three_sons_author_id"]=>
    string(1) "3"
    ["post_type"]=>
    array(2) {
      [0]=>
      string(4) "post"
      [1]=>
      string(8) "projects"
    }
    ["order"]=>
    string(4) "DESC"
  }
  ["date_query"]=>
  bool(false)
  ["queried_object"]=>
  object(WP_User)#152 (7) {
    ["data"]=>
    object(stdClass)#151 (10) {
      ["ID"]=>
      string(1) "3"
      ["user_login"]=>
      string(6) "author"
      ["user_nicename"]=>
      string(15) "author-slug"
      ["user_email"]=>
      string(16) "[email protected]"
      ["user_url"]=>
      string(17) "http://example.com"
      ["user_registered"]=>
      string(19) "2016-05-09 19:12:24"
      ["user_status"]=>
      string(1) "0"
      ["display_name"]=>
      string(15) "Author Name"
    }
    ["ID"]=>
    int(3)
    ["caps"]=>
    array(1) {
      ["administrator"]=>
      bool(true)
    }
    ["cap_key"]=>
    string(25) "wp_capabilities"
    ["roles"]=>
    array(1) {
      [0]=>
      string(13) "administrator"
    }
  }
  ["queried_object_id"]=>
  int(3)
  ["request"]=>
  string(489) "SELECT SQL_CALC_FOUND_ROWS  wp_posts.ID FROM wp_posts  WHERE 1=1  AND wp_posts.ID IN (1,102,160,196,199,201,206,162,198) AND (wp_posts.post_author = 3) AND wp_posts.post_type IN ('post', 'projects') AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'acf-disabled' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private')  ORDER BY wp_posts.post_date DESC LIMIT 0, 10"
  ["posts"]=>
  &array(1) {
    [0]=>
    object(WP_Post)#144 (24) {
      ["ID"]=>
      int(1)
      ["post_author"]=>
      string(1) "3"
      ["post_date"]=>
      string(19) "2016-05-03 20:12:01"
      ["post_date_gmt"]=>
      string(19) "2016-05-04 00:12:01"
      ["post_content"]=>
      string(85) "Welcome to WordPress. This is your first post. Edit or delete it, then start writing!"
      ["post_title"]=>
      string(12) "Hello world!"
      ["post_excerpt"]=>
      string(0) ""
      ["post_status"]=>
      string(7) "publish"
      ["comment_status"]=>
      string(6) "closed"
      ["ping_status"]=>
      string(6) "closed"
      ["post_password"]=>
      string(0) ""
      ["post_name"]=>
      string(11) "hello-world"
      ["to_ping"]=>
      string(0) ""
      ["pinged"]=>
      string(0) ""
      ["post_modified"]=>
      string(19) "2016-06-15 14:39:12"
      ["post_modified_gmt"]=>
      string(19) "2016-06-15 18:39:12"
      ["post_content_filtered"]=>
      string(0) ""
      ["post_parent"]=>
      int(0)
      ["guid"]=>
      string(19) "http://3sm.dev/?p=1"
      ["menu_order"]=>
      int(0)
      ["post_type"]=>
      string(4) "post"
      ["post_mime_type"]=>
      string(0) ""
      ["comment_count"]=>
      string(1) "1"
      ["filter"]=>
      string(3) "raw"
    }
  }
  ["post_count"]=>
  int(1)
  ["current_post"]=>
  int(-1)
  ["in_the_loop"]=>
  bool(false)
  ["post"]=>
  object(WP_Post)#144 (24) {
    ["ID"]=>
    int(1)
    ["post_author"]=>
    string(1) "3"
    ["post_date"]=>
    string(19) "2016-05-03 20:12:01"
    ["post_date_gmt"]=>
    string(19) "2016-05-04 00:12:01"
    ["post_content"]=>
    string(85) "Welcome to WordPress. This is your first post. Edit or delete it, then start writing!"
    ["post_title"]=>
    string(12) "Hello world!"
    ["post_excerpt"]=>
    string(0) ""
    ["post_status"]=>
    string(7) "publish"
    ["comment_status"]=>
    string(6) "closed"
    ["ping_status"]=>
    string(6) "closed"
    ["post_password"]=>
    string(0) ""
    ["post_name"]=>
    string(11) "hello-world"
    ["to_ping"]=>
    string(0) ""
    ["pinged"]=>
    string(0) ""
    ["post_modified"]=>
    string(19) "2016-06-15 14:39:12"
    ["post_modified_gmt"]=>
    string(19) "2016-06-15 18:39:12"
    ["post_content_filtered"]=>
    string(0) ""
    ["post_parent"]=>
    int(0)
    ["guid"]=>
    string(19) "http://3sm.dev/?p=1"
    ["menu_order"]=>
    int(0)
    ["post_type"]=>
    string(4) "post"
    ["post_mime_type"]=>
    string(0) ""
    ["comment_count"]=>
    string(1) "1"
    ["filter"]=>
    string(3) "raw"
  }
}

post__in配列には正しい投稿が含まれていますが、何らかの理由でpostsには「Hello World」しか含まれていないことに注意してください。この著者にも少なくとも3つのプロジェクトが関連付けられている必要があります。それらはクエリ内にあり、次のように見えますが、返されません。 postsを作成していないユーザーの場合、ループには何も表示されません。 User ID 1postsおよびprojectsが表示されます。

たぶんこれはrequestと関係があるのでしょうか?

"SELECT SQL_CALC_FOUND_ROWS  wp_posts.ID FROM wp_posts  WHERE 1=1  AND wp_posts.ID IN (1,102,160,196,199,201,206,162,198) AND (wp_posts.post_author = 3) AND wp_posts.post_type IN ('post', 'projects') AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'acf-disabled' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private')  ORDER BY wp_posts.post_date DESC LIMIT 0, 10"

私はそれが複雑で、尋ねることが多いことを知っていますが、次のステップでの助け、またはコードのエラーは大歓迎です。ありがとう!


@PieterGoosenの返信後の更新:

PHP <5.4(ugh-クライアントサーバー!)をサポートするために、彼のコードにいくつかの変更を加える必要がありました。唯一の大きな変更は、2番目のクエリにget_posts()の代わりにWP_Queryを使用することです。なぜなら、get_posts()posts_whereにワイルドカードがあるために必要なmeta_keyアクションにフックしないためです高度なカスタムフィールドリピーターフィールドによる):

function posts_where_credited( $where ) {
    $where = str_replace("meta_key = 'project_credits_%_user", "meta_key LIKE 'project_credits_%_user", $where);
    return $where;
}
add_filter( 'posts_where' , 'posts_where_credited' );

したがって、ここにpre_get_posts関数があります。

function author_pre_get_posts ( $q ) {
    // Remove action
    remove_action( 'pre_get_posts', __FUNCTION__ );

    // Only target the main query, front end only on author archive pages
    if (    !is_admin()
         && $q->is_main_query()
         && $q->is_author()
    ) {
        wp_reset_query();
        wp_reset_postdata();

        // Now we can run our custom queries to get post ID's
        $author_name = sanitize_title_for_query( $q->query['author_name'] );

        // This section is also used by WP_Query to get user id
        $author = get_user_by( 
            'slug', 
            $author_name 
        );
        $author_id = absint( $author->ID );

        // Get the posts
        $args_1 = array(
            'author'                 => $author_id, // Get from referenced query
            'fields'                 => 'ids', // Only get the Post's IDs, faster, lighter, better, stronger
            'posts_per_page'         => -1, // Get all posts
            'cache_results'          => false, // Do not update post cache
            'update_post_meta_cache' => false, // Do not update post meta cache
            'update_post_term_cache' => false, // Do not cache post terms
        );
        $post_type_post_ids = get_posts( $args_1 );

        // Get the projects
        $args_2 = array(
            'post_type'              => 'projects',
            'fields'                 => 'ids', // Only get the Post's IDs, faster, lighter, better, stronger
            'posts_per_page'         => -1, // Get all posts
            'cache_results'          => false, // Do not update post cache
            'update_post_meta_cache' => false, // Do not update post meta cache
            'update_post_term_cache' => false, // Do not cache post terms
            'meta_query' => array(
                array(
                    'key'           => 'project_credits_%_user',
                    'value'         => $author_id,
                )
            )
        );
        $post_type_projects_ids = new WP_Query( $args_2 );
        // retrieve *JUST* the IDs
        $post_type_projects_ids = $post_type_projects_ids->posts;

        // It is now just a matter of merging the two arrays of ids
        $combined = array_unique( 
            array_merge( 
                $post_type_post_ids, 
                $post_type_projects_ids 
            ) 
        );

        // We need to make 100% sure we have id's, otherwise post__in will return all posts
        if ( !$combined ) {
            return;
        }

        var_dump($combined);

        // Lets build the query
        $q->set( 'post_type', array('post', 'projects') );
        $q->set( 'post__in', $combined );
    }
}
add_action( 'pre_get_posts', 'author_pre_get_posts' );

var_dump($combined)postsおよびprojectsのIDを提供し、同様にこれらの投稿やプロジェクトを表示します...ただし、ユーザーID 1のみです。他の著者のauthor.phpページの場合、表示されている唯一のオブジェクトは、post_typepostの投稿です-projectsはすべての作成者/ユーザーに対して表示されませんを除くユーザーID 1のユーザー。

そのため、修正する必要があるのはこれだけです。修正方法はわかりません。

4
ethfun

改良されたアプローチ

元の答えの問題は、投稿者IDをpost__inパラメータに渡していますが、著者ページにあるにもかかわらず、メインクエリはその投稿者に属さない投稿をすべて削除することです。 author_nameフィルタを介して空の文字列をpre_get_postsに渡すことができますが、それはクエリオブジェクトを継承して壊します。

これは新しいアプローチを要求します、そしてこれは私たちがすることです:

  • メインクエリを通常どおり実行します。つまり、現在表示されている作成者によって作成されたデフォルトの投稿タイプpostからのすべての投稿を返します。これは自動的に問題2の面倒を見るでしょう。カスタムフィールドを表示することを伴う問題1は元のアプローチで処理されます。

    オリジナルのメインクエリにカスタム投稿タイプを追加する必要がある場合は、ここでpre_get_postsを使用できますが、私の理解していることからすると、通常の投稿のみが必要であるため、これは必要ありません。

  • 表示されている著者が言及されている投稿タイプprojetcsからの投稿のみが必要な2番目の問題をソートするには、pre_get_posts経由で投稿を追加するよりも生成されるSQLクエリを変更します。

    このために、posts_whereフィルタを利用します。作成者が言及されているすべての投稿のIDをprojectsから返すためにカスタムクエリを実行し、それらのIDを取得し、SQLクエリのWHERE節を変更して投稿も取得するようにします。

    meta_query用に生成されたSQLも変更するために、カスタムクエリをトリガするためにまだカスタムトリガを使います。

そのため、コードについては、最初のアプローチで投稿したすべてのコードを削除し、それを新しいフィルタで置き換えることができます。 (繰り返しになりますが、PHP 5.4

add_filter( 'posts_where', 'posts_where_credited', 10, 2 ); 
function posts_where_credited( $where, \WP_Query $q )
{
    // Lets first check our trigger and change the SQL if needed
    if ( true === $q->get( 'wpse_trigger' ) )
        $where = str_replace(
            "meta_key = 'project_credits_%_user",
            "meta_key LIKE 'project_credits_%_user",
            $where
        );

    // Make sure that we target the main query, front end on author pages
    if (    !is_admin()
         && $q->is_main_query()
         && $q->is_author()
    ) {
        // Get the current author
        $author_name = sanitize_title_for_query( $q->get( 'author_name' ) );
        // Just to make sure we actually have a valid uathor name, if not, bail
        if ( !$author_name )
            return $where;

        $author = get_user_by( 
            'slug',
            $author_name
        );
        $author_id = absint( $author->ID );

        // Get the posts in which the author is mentioned from our post type
        $args = [
            'wpse_trigger'           => true, // Our custom trigger
            'post_type'              => 'projects',
            'posts_per_page'         => -1,
            'fields'                 => 'ids',
            'suppress_filters'       => false,
            'cache_results'          => false,
            'update_post_term_cache' => false,
            'update_post_meta_cache' => false,
            'meta_query'             => [
                [
                    'key'   => 'project_credits_%_user',
                    'value' => $author_id
                ]
            ]
        ];
        $post_ids = get_posts( $args );
        // Make sure we have id's, else bail
        if ( !$post_ids )
            return $where;

        $post_ids = implode( ',', array_map( 'absint', $post_ids ) );

        // We have id's, lets adjust the SQL WHERE clauses
        global $wpdb;

        $where .= " OR ( $wpdb->posts.ID IN ( $post_ids ) ) ";
    }
    return $where;
}

元のアプローチ

あなたはあなたのアプローチに非常に近く、ただあちらこちらにグリッチがあります。これらすべてを打破することができます

ユーザーのプロフィールページに高度なカスタムフィールドのデータを表示します。

これは簡単です。残念ながら私はACFを使ったことがないので、データがどのように保存されているのかわかりません。ただし、要するに、表示されている著者アーカイブページの現在のIDだけが必要です。そのIDはすでに利用可能です(照会されたオブジェクトを使用する場合は+1)。

あるいは、問い合わせされたオブジェクトを取得するためのはるかに信頼性の高い方法は、$GLOBALS['wp_the_query']に格納されているメインの問い合わせオブジェクトを利用することです。 $GLOBALS['wp_the_query']$GLOBALS['wp_query']のような不安定な関数によって変更される可能性があるのでquery_postsよりはるかに信頼性があります。つまり、著者のアーカイブページでは、次のように使用できます。

if( !isset($whose_ID) ) {
    $whose_ID = absint( $GLOBALS['wp_the_query']->queried_object_id );
}

その後、get_field()関数で$whose_IDを使用してACFデータを返すことができます。あなたのコードから、それはキーがuser接頭辞を持っているように思われるので、

$search = 'user_' . $whose_ID;

するべきです。

ユーザーの投稿した投稿をすべて表示します

それはここにあなたのすべてのアプローチが小さいことか2つを欠いているか、またはいくらかの改良が必要なだけです。あなたの最初のアプローチと最後のアプローチは一つに統合されているはずです。ここで覚えておく必要があることの1つは、WP_Queryは後に続く種類のクエリをネイティブにサポートしていないため、ネイティブにこれを1つのクエリで行うことはできないため、複数のクエリが必要になることです。これはターンが私達が賢くなることを必要とします、これが高価になることができて、そしてさらに銀行を破ることができるからです。

このセクションを解決するためにここで行うことは次のとおりです。

  • get_postsを使用して、著者が書いた投稿タイプpostからすべての投稿IDを取得します。これはコストのかかるオーバーヘッドになる可能性があるため、ここでは非常に賢い必要があります。 get_postsは法的にページングを壊すのでWP_Queryより速いですが、銀行を破る必要がないのでもっと速くする必要があります。

    私たちがすることは、それを超高速にするために、'fields' => 'ids'get_postsクエリ引数に渡すことです。これはクエリにpost idの配列だけを返すように伝えます。他のpostdataを返さないので、これはクエリを非常に速くします。また、ポストタームとメタデータをキャッシュしないようにクエリに指示することで、さらに高速にすることができます。これは私たちが必要としないすべての無関係なものです

それでは、このクエリを見てみましょう(注意:すべてのコードはテストされていないのでPHP 5.4+

$author_name = sanitize_title_for_query( $q->query['author_name'] );

$args_1 = [
    'author_name'            => $author_name, // Get from referenced query
    'posts_per_page'         => -1, // Get all posts
    'cache_results'          => false, // Do not update post cache
    'update_post_meta_cache' => false, // Do not update post meta cache
    'update_post_term_cache' => false, // Do not cache post terms
];
$post_ids_1 = get_posts( $args_1 );

$post_ids_1は現在、著者が現在閲覧している投稿からの投稿IDの配列をデフォルトの投稿タイプpostから保持します。

  • ユーザーがクレジットされているすべてのプロジェクト(CPT)(CPTのACFフィールドを介して割り当てられます)

このセクションでは、上記とまったく同じプロセスに従いますので、ここでは詳しく説明しません。コードを見てみましょう

// This section is also used by WP_Query to get user id
$author = get_user_by( 
    'slug', 
    $author_name 
);
$author_id = absint( $author->ID );

$args_2 = [
    'post_type'              => 'projects',
    'posts_per_page'         => -1, // Get all posts
    'cache_results'          => false, // Do not update post cache
    'update_post_meta_cache' => false, // Do not update post meta cache
    'update_post_term_cache' => false, // Do not cache post terms
    'meta_query' => [
        [
            'key'   => 'project_credits_%_user',
            'value' => $author_id
        ]
    ]
];
$post_ids_2 = get_posts( $args_2 );

投稿タイプprojectsから作者が言及されたすべての投稿IDを取得しました

すべての関連するIDが揃ったので、pre_get_postsアクションにすべてをまとめます。

add_action( 'pre_get_posts', function ( $q )
{
    // Remove action
    remove_action( current_action(), __FUNCTION__ );

    // Only target the main query, front end only on author archive pages
    if (    !is_admin()
         && $q->is_main_query()
         && $q->is_author()
    ) {
        // Now we can run our custom queries to get post ID's

        $author_name = sanitize_title_for_query( $q->query['author_name'] );

        $args_1 = [
            'author_name'            => $author_name, // Get from referenced query
            'posts_per_page'         => -1, // Get all posts
            'cache_results'          => false, // Do not update post cache
            'update_post_meta_cache' => false, // Do not update post meta cache
            'update_post_term_cache' => false, // Do not cache post terms
        ];
        $post_ids_1 = get_posts( $args_1 );

        // This section is also used by WP_Query to get user id
        $author = get_user_by( 
            'slug', 
            $author_name 
        );
        $author_id = absint( $author->ID );

        $args_2 = [
            'post_type'              => 'projects',
            'posts_per_page'         => -1, // Get all posts
            'cache_results'          => false, // Do not update post cache
            'update_post_meta_cache' => false, // Do not update post meta cache
            'update_post_term_cache' => false, // Do not cache post terms
            'meta_query' => [
                [
                    'key'   => 'project_credits_%_user',
                    'value' => $author_id
                ]
            ]
        ];
        $post_ids_2 = get_posts( $args_2 );

        // It is now just a matter of merging the two arrays of ids
        $combined = array_unique( 
            array_merge( 
                $post_ids_1, 
                $post_ids_2 
            ) 
        );

        // We need to make 100% sure we have id's, otherwise post__in will return all posts
        if ( !$combined )
            return;

        // Lets build the query
        $q->set( 'post_type', ['post', 'projects'] );
        $q->set( 'post__in',  $combined            );
    }
});

デフォルトのループを使用して、投稿を通常の投稿者アーカイブページに表示できます。ちょっと注意してください、サイトの構文のハイライトによると、あなたのauthor.phpの中のコードに構文エラーがあるようです

編集

私はあなたの編集を見ました、そして、いくつかの問題があります、しかし、それは必ずしもこれが問題を解決するという意味ではありません

  • wp_reset_postdata()wp_reset_query()を呼び出す必要はありません。後者はquery_posts()でのみ使われます。

  • get_posts()はフィルタによる変更を受け入れますが、これはデフォルトの振る舞いではありません。 get_posts()はデフォルトで'suppress_filters' => trueWP_Queryに渡し、クエリを変更するフィルタを抑制します。 'suppress_filters' => falseget_posts引数に渡すだけでこれをオーバーライドできます。これはフィルタがクエリを変更することを可能にします

  • デフォルトでは、WP_Query内のどのフィルタもWP_Queryメインクエリを含む)のすべてのインスタンスを変更します。関連するクエリのみを対象とするようにフィルタをトリガするために、何らかのトリガを使用することをお勧めします。私は間違いなくあなたのposts_whereフィルタでこれをするでしょう。

    できることは、トリガーをwpse_triggerと呼ぶことです。フィルタでターゲットにしたいクエリのクエリ引数に'wpse_trigger' => trueを渡すことができます。ここでやらなければいけないことは、triggerが設定されているかどうか、そしてそれがtrueに設定されているかどうか、私たちのフィルタの中をチェックすることです。現在のクエリは、2番目のパラメータとしてフィルタへの参照によって渡されます。

    コードを見てみましょう

    function posts_where_credited( $where, \WP_Query $q ) 
    {
        // Lets remove the filter
        remove_filter( current_filter(), __FUNCTION__ );
    
        // Lets see if our trigger is set and if the value is true, if not, bail
        if ( true !== $q->get( 'wpse_trigger' ) )
            return $where
    
        // Our trigger is set and true, lets alter this query
        $where = str_replace(
            "meta_key = 'project_credits_%_user", 
            "meta_key LIKE 'project_credits_%_user", 
            $where
        );
    
        return $where;
    }
    add_filter( 'posts_where' , 'posts_where_credited', 10, 2 );
    

    メタクエリを作成する2番目のget_postsインスタンスのクエリ引数は、次のようになります。

    $args_2 = [
        'wpse_trigger'    => true,
        'suppress_filter' => false,
        // Rest of your query args
    ];
    
  • あなたのフィルタが実際にmeta_key LIKEで正しく動作するかどうかはわかりませんが、 この記事 それが実際に失敗した2つ目のクエリである場合、/いくつかの代替案を見ることができます。

非常に奇妙なことは、すべてが作者1に対して機能しますが、他のすべての作者に対しては機能しないことです。ここであなたがチェックできることがいくつかあります

  • WP_Queryアクションの中にある2番目のクエリ用のpre_get_postsインスタンスを保持します。そして、そのクエリの後($post_type_projects_ids = new WP_Query();の直後)、var_dump( $post_type_projects_ids->request );を実行して著者ページをロードします。これにより、作成者ページの上にSQLクエリが印刷されます。結果のSQLクエリが他のすべての作者ページと作者1のものと一致するかどうかを確認します。それらが異なる場合は、プラグインまたはテーマのどこかに悪いフィルタ(posts_whereまたはposts_clauses)などの問題があります。 action(bad pre_get_posts)またはカスタム投稿タイプの機能に関する問題。 WP_Queryではうまくいきませんので、get_postsに気をつけてください。

  • SQLクエリがチェックアウトする場合は、var_dump( $post_type_projects_ids->posts );を実行し、クエリから返された投稿が実際にあるかどうかを確認します。投稿がある場合、これはIDを持つ配列になります。

  • 上記のことを確認したら、あなたの作者ページに行き、そのページのどこかに、var_dump( $wp_query->request );を追加してください。これにより、メインクエリによって生成されたSQLクエリが印刷されます。また、作者1が動作するので、そのSQLクエリを他の作者ページのSQLクエリと比較します。投稿者IDと作成者IDを除いて、クエリは一致する必要があります。そうでない場合は、デバッグのための箇条書きの1つを参照してください。

2
Pieter Goosen