web-dev-qa-db-fra.com

author.php avec ACF et les CPT

En écrivant ceci, je ferai de mon mieux pour éviter un problème XY.

Ce que j'essaie de faire:

J'essaie de construire un modèle author.php qui:

  • affiche les données des champs personnalisés avancés sur la page de profil de l'utilisateur
  • affiche les messages de l'auteur
    • tous les messages que l'utilisateur a créés
    • all projects (CPT) dans lequel l'utilisateur est crédité (affecté via un champ ACF pour le CPT)

Comment j'ai essayé de résoudre ceci:

Tentative 1 (modèle author.php)

Ma première tentative, et cela a surtout fonctionné. Ce qui m'a fait abandonner cette approche, c'est la pagination. Plus sur cela plus tard. J'ai eu trois questions:

  • Le premier a tous les messages créés par l'utilisateur,
  • le second a tous les projets auxquels l'utilisateur a été crédité,
  • et la troisième utilisait post__in via array_unique( array_merge($query1, $query2) ) pour afficher les publications de ces deux requêtes simultanément, organisées par date.

    <?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();
    

Comme je ne pouvais pas faire fonctionner la pagination sans un 404, j'ai changé mon approche.

Tentative 2

Après avoir lu plusieurs suggestions sur la façon dont un modèle author.php utilise la requête principale, je suis passé à une fonction modifiant la boucle principale avec l'action pre_get_posts. J'ai déplacé toutes les requêtes vers leur propre fonction qui n'a retourné que le tableau de messages que je voulais afficher pour la page de l'auteur. J'ai utilisé $query->set() et j'ai rencontré un problème où l'une de mes requêtes était une boucle infinie. Il n'y avait pas de boucles foreach ou while dans mon code, c'est donc un mystère. J'ai abandonné cette tentative à cause de la boucle infinie et des fonctionnalités de la poupée russe.

Tentative 3

Finalement, j'ai atterri sur ce code, qui devrait théoriquement fonctionner (mais ne fonctionne pas). Vous verrez trois requêtes $wpdb directes. Comme je venais de percuter ma boîte Vagrant pendant 45 minutes avec une boucle inexplicablement infinie, j'ai décidé d'essayer de créer la requête la plus légère et la moins encombrante possible. Je ne sais pas si c'est vraiment mieux, mais c'est ce que j'ai fait. Ce n'est pas le propos.

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' );

... et son author.php suivant:

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();

Pour l’essentiel, je crois que ce dernier code devrait fonctionne. Mais ce n'est pas le cas. Quelque chose ne se traduit pas. Si je fais un var_dump($wp_query); die; sur author.php, je vois ceci (j'ai supprimé les bits non pertinents ou sensibles):

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"
  }
}

Veuillez noter que le tableau post__in contient les publications correctes ... mais pour une raison quelconque, posts ne contient que "Hello World". Il devrait également y avoir au moins trois projets liés à cet auteur. Ils sont dans la requête, mais ils ne sont pas retournés. Pour les utilisateurs qui n'ont pas créé de posts, rien ne s'affiche dans la boucle. Pour User ID 1, posts AND projects apparaissent.

Peut-être que cela a quelque chose à voir avec la 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"

Je sais que c'est complexe et qu'il y a beaucoup de choses à demander, mais toute aide dans les étapes à suivre ou erreurs dans mon code serait extrêmement appréciée. Merci!


Mise à jour, après la réponse de @PieterGoosen:

Je devais apporter quelques modifications à son code afin de prendre en charge PHP <5.4 (ugh - serveurs client!). La seule modification majeure consiste à utiliser un WP_Query au lieu de get_posts() pour la deuxième requête, car get_posts() ne se raccorde pas à l'action posts_where, ce dont j'avais besoin car il y a un caractère générique dans meta_key (en raison du champ de répétition de champs personnalisés avancés):

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' );

Alors alors voici la fonction 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) me donnera les identifiants de posts et projects et affichera également ces publications et projets comme je l’attendais ... mais uniquement pour l’ID utilisateur 1. Pour la page author.php de tout autre auteur, les seuls objets affichés sont les publications avec le post_type of post - no projects s'affichera pour tout auteur/utilisateurSAUFpour l'utilisateur avec l'ID utilisateur 1.

C'est donc la seule chose à réparer, et je ne sais pas comment le réparer.

4
ethfun

APPROCHE RÉAFFINÉE

Le problème avec la réponse originale est que, bien que nous passions les identifiants de publication au paramètre post__in, situés sur la page de l'auteur, la requête principale supprime toutes les publications qui n'appartiennent pas à l'auteur. Nous pouvons passer une chaîne vide à author_name via le filtre pre_get_posts, mais cela casse intrinsèquement l'objet de la requête, qui est un no-no.

Cela appelle une nouvelle approche et voici ce que nous allons faire:

  • Nous laisserons la requête principale s'exécuter normalement, c'est-à-dire qu'elle renverra toutes les publications du type de publication par défaut post qui a été créé par l'auteur en cours de visualisation. Cela traitera automatiquement le problème 2. Le premier problème avec l'affichage des champs personnalisés est traité dans l'approche d'origine.

    Nous pouvons utiliser pre_get_posts ici si nous devons ajouter des types de publication personnalisés à la requête principale d'origine, mais d'après ce que je comprends, vous avez uniquement besoin de publications normales. Cette opération n'est donc pas nécessaire.

  • Pour trier le deuxième problème pour lequel nous n'avons besoin que des publications du type d'article projetcs où l'auteur en cours de visualisation est mentionné, nous modifierons plutôt la requête SQL générée plutôt que d'ajouter nos articles via pre_get_posts.

    Pour cela, nous allons utiliser le filtre posts_where. Nous allons exécuter une requête personnalisée pour renvoyer les identifiants de tous les posts où l'auteur est mentionné à partir de projects. Nous prendrons ensuite ces identifiants et modifierons la clause WHERE de la requête SQL pour obtenir également les posts.

    Nous utiliserons toujours notre déclencheur personnalisé pour déclencher la requête personnalisée afin de modifier également le SQL généré pour le meta_query.

Ainsi, pour le code, vous pouvez supprimer tout le code que j'ai publié dans mon approche d'origine et le remplacer par notre nouveau filtre. ( Encore une fois, nous avons besoin de 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;
}

APPROCHE ORIGINALE

Vous êtes très proche de vos approches, juste un petit problème ici et là. Permet de décomposer tout cela

affiche les données des champs personnalisés avancés sur la page de profil de l'utilisateur

Cela devrait être simple. Malheureusement, je n'ai jamais travaillé avec ACF, donc je ne sais pas comment les données sont stockées. En bref, tout ce dont vous avez besoin est l’identifiant actuel de la page d’archive de l’auteur en cours de visualisation. Vous avez déjà cet ID disponible ( +1 pour utiliser l'objet demandé ).

Sinon, un moyen beaucoup plus fiable d'obtenir l'objet interrogé consiste à utiliser l'objet de requête principal stocké dans $GLOBALS['wp_the_query']. $GLOBALS['wp_the_query'] est beaucoup plus fiable que $GLOBALS['wp_query'] car ce dernier peut être modifié par des fonctions de mauvaise qualité comme query_posts. Donc, en bref, dans votre page d’archive auteur, vous pouvez utiliser le code suivant

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

Vous pouvez ensuite utiliser $whose_ID dans vos fonctions get_field() pour renvoyer les données ACF. D'après votre code, il semble que la clé ait le préfixe user, donc

$search = 'user_' . $whose_ID;

devrait faire.

affiche les messages de l'auteur tous les messages de l'utilisateur

C'est ici que toutes vos approches manquent d'une petite chose ou de deux ou ont juste besoin d'être raffinées. Votre première approche et votre dernière approche auraient dû être fusionnées en une seule. Il convient de garder à l’esprit que WP_Query ne prend pas en charge de manière native le type de requête que vous recherchez, de sorte que nous ne pouvons pas le faire de manière native dans une requête. Par conséquent, nous aurons besoin de plusieurs requêtes. C’est donc à notre tour que nous devons être intelligents car cela peut coûter cher et même casser votre tirelire.

Ce que nous allons faire ici pour résoudre cette section est:

  • Utilisez get_posts pour obtenir tous les ID d'article du type d'article post écrit par l'auteur. Cela peut coûter cher, nous devons donc être très intelligents. get_posts sont plus rapides que WP_Query car il coupe légalement la pagination, mais nous devons le faire encore plus vite car nous n'avons pas besoin de casser la tirelire.

    Ce que nous allons faire est, pour le rendre super rapide, nous allons passer 'fields' => 'ids' à nos arguments de requête get_posts. Cela indiquera à la requête de ne renvoyer qu'un tableau d'identificateurs de publication. Cela rend la requête très rapide car nous ne renvoyons aucune autre donnée postérieure. Nous pouvons également rendre la procédure encore plus rapide en indiquant à la requête de ne pas mettre en cache les conditions de publication et les métadonnées. Ce sont toutes des choses non pertinentes dont nous n'avons pas besoin

Alors regardons cette requête ( VEUILLEZ NOTER: Tout le code n'est pas testé et nécessite 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 va maintenant contenir un tableau d'identifiants de post provenant de posts que l'auteur a été actuellement visualisé, créés à partir du type de post par défaut post

  • tous les projets (CPT) dans lesquels l'utilisateur est crédité (affecté via un champ ACF pour le CPT)

Pour cette section, nous suivrons exactement le même processus que ci-dessus, je ne vais donc pas entrer dans les détails ici. Regardons le code

// 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 );

Vous avez maintenant tous les identifiants de publication pour lesquels l'auteur a été mentionné dans le type de publication projects

Maintenant que nous avons tous les identifiants pertinents, il est temps de tout mettre ensemble dans notre action 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            );
    }
});

Vous pouvez afficher vos publications normalement sur la page d’archive de votre auteur avec la boucle par défaut. Juste une remarque, selon le surligneur de syntaxe du site, il semble y avoir une erreur de syntaxe dans le code de votre author.php

MODIFIER

J'ai jeté un coup d'oeil à votre montage, et il y a quelques problèmes, mais cela ne signifie pas nécessairement que cela résoudra le problème.

  • Vous n'avez pas besoin d'appeler wp_reset_postdata() et wp_reset_query(). Ce dernier est utilisé uniquement avec query_posts() que vous ne devriez jamais utiliser

  • get_posts() accepte d'être modifié par les filtres, mais ce n'est pas le comportement par défaut. get_posts() passe 'suppress_filters' => true à WP_Query par défaut, ce qui supprime les filtres altérant la requête. Vous pouvez remplacer ceci en passant simplement les arguments 'suppress_filters' => false à get_posts. Cela permettra aux filtres de modifier la requête

  • Par défaut, l'un des filtres de WP_Query modifiera toutes les instances de WP_Query ( qui inclut la requête principale ). C'est toujours une bonne idée d'utiliser une sorte de déclencheur pour déclencher un filtre afin de ne cibler que la requête pertinente. Je le ferais certainement avec votre filtre posts_where.

    Ce que nous pouvons faire est, appelons notre déclencheur wpse_trigger. Nous pouvons passer 'wpse_trigger' => true à notre argument de requête de la requête que nous voudrions cibler avec notre filtre. Il ne nous reste plus qu'à vérifier à l'intérieur de notre filtre si notre déclencheur est défini et s'il est défini sur true. N'oubliez pas que la requête en cours est transmise au filtre en tant que deuxième paramètre.

    Regardons le code

    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 );
    

    Vos arguments de requête pour votre deuxième instance get_posts où vous créez la méta requête peuvent maintenant ressembler à ceci:

    $args_2 = [
        'wpse_trigger'    => true,
        'suppress_filter' => false,
        // Rest of your query args
    ];
    
  • Je ne sais pas si votre filtre fonctionne correctement avec le meta_key LIKE, mais vous pouvez jeter un coup d'œil à cet article pour certaines alternatives s'il s'agit en fait de la requête deux qui échoue

Ce qui est assez étrange, c'est que tout fonctionne pour l'auteur 1, mais pas pour aucun autre auteur. Voici quelques points à vérifier

  • Conservez votre instance WP_Query pour la deuxième requête à l'intérieur de votre action pre_get_posts. Ensuite, après cette requête ( juste après $post_type_projects_ids = new WP_Query();), exécutez var_dump( $post_type_projects_ids->request ); et chargez la page de l'auteur. Ceci imprimera la requête SQL en haut de votre page d’auteur. Vérifiez si la requête SQL résultante correspond sur toutes les autres pages d'auteur et sur celle de l'auteur 1. Si elles diffèrent, vous rencontrez un problème quelque part dans un plugin ou dans le thème avec un filtre incorrect ( comme posts_where ou posts_clauses), action ( bad pre_get_posts) ou un problème lié aux fonctionnalités de votre type de publication personnalisé. Notez que vous devez passer à WP_Query car cela ne fonctionnera pas avec get_posts

  • Si les requêtes SQL aboutissent, exécutez var_dump( $post_type_projects_ids->posts ); et vérifiez si vous avez réellement des publications renvoyées par la requête. Ce sera juste un tableau avec des identifiants s'il y a des posts

  • Si ce qui précède se vérifie, accédez à la page de votre auteur et, n'importe où sur cette page, ajoutez var_dump( $wp_query->request );. Ceci imprimera la requête SQL générée par la requête principale. Encore une fois, étant donné que l'auteur 1 fonctionne, comparez cette requête SQL avec la requête SQL d'autres pages d'auteur. À l'exception des identifiants post et author, les requêtes doivent correspondre. Sinon, reportez-vous à la première puce pour le débogage

2
Pieter Goosen