• When

    $in_same_term = true

    when using the get_next_post and get_previous_post functions, and the current post has several parent categories and several child catgeories:

    – will the function pick the next/previous post only from the current posts parent categories or will it also consider child categories?

    – if the post has several categories, let’s say: first, second and third category (both parent and child categories), will it choose a post from all 3 categories, or only from the first?

    And if the current post has categories A and B, then will an other post that has the categories A and B have priority in the next/prev choice, even if its publish date falls further away than let’s say an other post, that has categories A and C?

    And is there any difference in the choices of the functions in comparison, when using get_next_post & get_previous_post, get_adjacent_post and get_{$adjacent}_post_where ?

Viewing 15 replies - 1 through 15 (of 63 total)
  • Moderator bcworkz

    (@bcworkz)

    You need to pass a true argument in order to get next/previous posts with the same category terms. Any posts with any of the same terms will be considered for next/previous. The functions are essentially wrappers for get_adjacent_post() which are direction specific. get_adjacent_post() goes in whatever direction is specified in its 3rd argument.

    “get_{$adjacent}_post_where” isn’t a function, it’s a filter hook that lets you alter the WHERE SQL clause as desired, so you can alter what post ends up being linked as the adjacent post. By default the adjacent post is determined by the post date. WP queries don’t have a best match kind of ordering, as in posts with more matching terms come first. You’d need to make your own query for that, or use a plugin that does so.

    Thread Starter berry metal

    (@erikalleman)

    I see.
    It seems that next/prev post buttons with the same term argument set to true become a bit pointless, if posts have multiple categories.

    For example if I have an article about “Left wing musicians” with the categories “music” and “politics” and an other one about “Right wing philosophers” with the categories “philosophy” and “politics”, then when people navigate via the buttons with the same term set to true, because all categories are considered, in just 3 clicks they can arrive from an article about music to an article about philosophy (2 categories that are unrelated). So does this mean that it’s basically impossible to navigate by category, if there are multiple categories per post?

    Perhaps the only true navigation by category that would make sense in the scenario of multiple categories is to write a query that brings in articles that have ALL the categories of the current post, is that right?
    But then visitors would quickly run out of options, because few articles share exactly the same categories.

    So the conclusion is that navigation by category won’t make sense at all, if posts have multiple categories. Do you agree?

    Thread Starter berry metal

    (@erikalleman)

    So the only option left that makes sense for navigation by category in case of multiple categories, is navigating by the first category of the current post.

    Is it possible to define that in the clause?

    Thread Starter berry metal

    (@erikalleman)

    Or the Yoast plugin introduces something like “primary” category (whichever is flagged as primary, the second or third can also be marked as primary), and use that in the clause?

    Thread Starter berry metal

    (@erikalleman)

    But navigation by only the cat[0] or by the Yoast primary is very not optimal, so now I am trying to set only the default next/prev links to cat[0] or Yoast primary, and put a dropdown beside the links, where users could select a specific category from the current posts array of categories to navigate further only by those categories (and they could select one or multiple), and then modify the next/prev links with AJAX after the selection.

    Something that I don’t understand in this theoretical setup is that once a person would choose a category from the dropdown, and click next/prev, how would WP “remember” that choice in the dropdown, IF I have set the default links of all posts to cat[0] or Yoast primary. Because I must set something for default for the case that the user does not intend to use the dropdown to modify the button query.

    I would use this code for the button shortcode:

    How do I transform this into a shortcode?

    <?php
    $post_id = $post->ID; // current post ID
    $cat = get_the_category(); 
    $current_cat_id = $cat[0]->cat_ID; // current category ID 
    
    $args = array( 
        'category' => $current_cat_id,
        'orderby'  => 'post_date',
        'order'    => 'DESC'
    );
    $posts = get_posts( $args );
    // get IDs of posts retrieved from get_posts
    $ids = array();
    foreach ( $posts as $thepost ) {
        $ids[] = $thepost->ID;
    }
    // get and echo previous and next post in the same category
    $thisindex = array_search( $post_id, $ids );
    $previd    = isset( $ids[ $thisindex - 1 ] ) ? $ids[ $thisindex - 1 ] : false;
    $nextid    = isset( $ids[ $thisindex + 1 ] ) ? $ids[ $thisindex + 1 ] : false;
    
    if (false !== $previd ) {
        ?><a rel="prev" href="<?php echo get_permalink($previd) ?>">Previous</a><?php
    }
    if (false !== $nextid ) {
        ?><a rel="next" href="<?php echo get_permalink($nextid) ?>">Next</a><?php
    }

    and this code for AJAX:

    JS:

    jQuery(document).ready(function($) {
     
        // We'll pass this variable to the PHP function example_ajax_request
        var fruit = 'Banana';
         
        // This does the ajax request
        $.ajax({
            url: example_ajax_obj.ajaxurl,
            data: {
                'action': 'example_ajax_request',
                'fruit' : fruit,
                'nonce' : example_ajax_obj.nonce
            },
            success:function(data) {
                // This outputs the result of the ajax request
                console.log(data);
            },
            error: function(errorThrown){
                console.log(errorThrown);
            }
        });  
                  
    });

    PHP:

    <?php
    function example_ajax_request() {
     
        $nonce = $_POST['nonce'];
    
        if ( ! wp_verify_nonce( $nonce, 'example-ajax-script' ) ) {
            die( 'Nonce value cannot be verified.' );
        }
     
        // The $_REQUEST contains all the data sent via ajax
        if ( isset($_REQUEST) ) {
         
            $fruit = $_REQUEST['fruit'];
             
            // Let's take the data that was sent and do something with it
            if ( $fruit == 'Banana' ) {
                $fruit = 'Apple';
            }
         
            // Now we'll return it to the javascript function
            // Anything outputted will be returned in the response
            echo $fruit;
             
            // If you're debugging, it might be useful to see what was sent in the $_REQUEST
            // print_r($_REQUEST);
         
        }

    Could you help with an example code, and if the issue with the conflict between the links query set for default and the dropdown choice is real?

    Because then maybe the user will be forced to re-select his category of choice on every post, if WP cannot remember the choice due to the default setting, which is necessary?

    So the code above, unlike the get_next_post / get_previous post functions, navigates only by the first category, so far so good.

    But I want to modify the choice for the singular category by the ajax dropdown, and also allow multiple selections, meaning that: show me the next or previous posts that have both A and B categories, like the current one.

    I don’t know how to adapt the AJAX script for the category change…
    Could you help with a code example?

    Thanks!

    • This reply was modified 3 years, 7 months ago by berry metal.
    Thread Starter berry metal

    (@erikalleman)

    So this script would do the same basically what my grid category facets do, but one post at a time…so the user will not have to turn back to the homepage or to scroll back…

    Thread Starter berry metal

    (@erikalleman)

    I forgot to include how to define ajaxurl as a global variable on the frontend.

    <?php
    function example_ajax_enqueue() {
    
    	// Enqueue javascript on the frontend.
    	wp_enqueue_script(
    		'example-ajax-script',
    		get_template_directory_uri() . '/js/simple-ajax-example.js',
    		array('jquery')
    	);
    
    	// The wp_localize_script allows us to output the ajax_url path for our script to use.
    	wp_localize_script(
    		'example-ajax-script',
    		'example_ajax_obj',
    		array(
    			'ajaxurl' => admin_url( 'admin-ajax.php' ),
    			'nonce' => wp_create_nonce('ajax-nonce')
    		)
    	);
    
    }
    add_action( 'wp_enqueue_scripts', 'example_ajax_enqueue' );

    and it says I need to update the ajaxurl variable:

    url: example_ajax_obj.ajaxurl

    I am just not sure how to put all this together, and I could use an example code…

    Moderator bcworkz

    (@bcworkz)

    For your situation, the same categories option of adjacent post links may not work very well. That doesn’t mean it’s a pointless option for other situations ?? Letting users select what category should be used in adjacent post links is feasible, but features using Ajax aren’t conducive for making into a shortcode solution. There are too many disparate elements involved. Shortcodes work best to generate output when content is first requested. They don’t accommodate user interaction very well.

    For example, a shortcode to output a dropdown field for category selection alone can be done via shortcode. But making an Ajax request and saving the user selection isn’t feasible by shortcode alone. The required elements need to be implemented outside of the shortcode itself.

    I’ll try to help you accomplish whatever you want, but are you sure this dropdown user experience is the best way forward? TBH, it strikes me as rather cumbersome. Putting myself in the end user’s role, I think making links based on a primary category is a better choice. Then I (as a user) don’t have to think or do anything to get to what I’m most likely interested in to start with.

    I’m unsure how Yoast designates a primary category. I’d assume some sort of term meta value. I’m skeptical the primary category would always be $cat[0] unless the query to get category terms was specifically crafted to ensure it is so. All the same, querying for a post’s primary category shouldn’t be too difficult. If Yoast implements a primary category, perhaps there’s also a helper function so we could easily get the primary category? IDK, it’d be something to ask over at Yoast support.

    Thread Starter berry metal

    (@erikalleman)

    And what if I would make a “multicat” taxonomy and create a term in there from concatenated categpries, like music-philosophy?
    And then if there are multiple categories, then the links would navigate by the “multicat” term.

    So first we have to check how many categories are there, if more than one, then the next/prev links should navigate by the corresponding “multicat” term.

    And the statement “navigate by category” would still be true.
    People will get much less matches, but they will get more related matches, so that compensates.

    So first the button should check how many categories the current post has. If only one, then the next/prev links should navigate with the regular “in same term” set to true, the default category.

    If it has several categories, then it should navigate by the “multicat” term.

    Because often the 2 categories or 3 have equal weight, so it’s impossible to decide by a fair primary category.

    How would this code look if it should be a next/prev button shortcode, and how could it check if the category is singular or multiple, and decide the taxonomy for navigation based on that?

    <?php
    $post_id = $post->ID; // current post ID
    $cat = get_the_category(); 
    $current_cat_id = $cat[0]->cat_ID; // current category ID 
    
    $args = array( 
        'category' => $current_cat_id,
        'orderby'  => 'post_date',
        'order'    => 'DESC'
    );
    $posts = get_posts( $args );
    // get IDs of posts retrieved from get_posts
    $ids = array();
    foreach ( $posts as $thepost ) {
        $ids[] = $thepost->ID;
    }
    // get and echo previous and next post in the same category
    $thisindex = array_search( $post_id, $ids );
    $previd    = isset( $ids[ $thisindex - 1 ] ) ? $ids[ $thisindex - 1 ] : false;
    $nextid    = isset( $ids[ $thisindex + 1 ] ) ? $ids[ $thisindex + 1 ] : false;
    
    if (false !== $previd ) {
        ?><a rel="prev" href="<?php echo get_permalink($previd) ?>">Previous</a><?php
    }
    if (false !== $nextid ) {
        ?><a rel="next" href="<?php echo get_permalink($nextid) ?>">Next</a><?php
    }
    Moderator bcworkz

    (@bcworkz)

    You can do multi-cat terms if that really makes sense to you and end users.

    When you get a post’s categories, it comes back as an array. Doing count() on the array will tell you right away if there are more than one. You could skip that step and search all terms for any that contain a “-” in the name. If found, use that one, otherwise use $cat[0]. Getting the adjacent post that has the category so found would mean you’d have to make your own query (as you are in your latest code snippet) since the WP adjacent post function finds posts of any of the current post’s categories.

    However, the WP function does have the option to exclude certain categories from the matching algorithm. So you could use the WP function by passing all other terms but the one with the “-” if one is found. Otherwise there’s only one term and the function works as-is.

    To step back a bit, you need some way to designate a primary category term, whether by the presence of “-“, something in term meta, or some other scheme; it doesn’t matter as long as there is some way to designate primary.

    Your code looks pretty good, except it only relies upon $cat[0], which may not be the best category to match against. But it’s a good framework to add in the logic discussed above. One small correction, if using term ID in get_posts(), the argument key to use is 'cat', not 'category'. 'category' only works for term slugs.

    With those changes, your code should work OK, but on a large site it wouldn’t be the most efficient approach. The algorithm used by get_adjacent_post() and its variants is much more efficient. I recommend using the WP functions in conjunction with excluding all terms but the primary, when applicable.

    Since you really need the adjacent post’s link, not the post itself, consider using get_next_post_link() and get_previous_post_link() functions.

    Thread Starter berry metal

    (@erikalleman)

    Thanks.

    But I got an other idea, instead of making a separate taxonomy that just adds complexity, isn’t it possible to code it so, that if the post has more than one terms, then it would fetch only those post links for next/prev, that have the same terms.

    And in fact the code should do the same if there is only one term: fetch the links of the posts that have the same term, so the “more than one” conditional wouldn’t even be necessary.

    I think this is possible in 2 steps:

    1. check for posts that have an identic number of terms, only
    2. define an “inclusive” array, meaning that all terms must match, but the order (like cat[0], cat[1], etc…) doesn’t matter.

    This would be sufficient to get the links, and no extra taxonomy is needed.

    What do you think? Can this be coded as I described it?

    Thread Starter berry metal

    (@erikalleman)

    I noticed the category__in array, but that doesn’t seem to be inclusive.
    Is it possible to query posts with exactly the same terms (indifferently of their number) with category__in ?

    Thread Starter berry metal

    (@erikalleman)

    This code aims to get posts that match specific terms of multiple taxonomies (I only have one taxonomy, but the code may be useful as example):

    <?php
    
        //Query to match department
        $args = array(
         'tax_query' => array(
             array(
                 'taxonomy' => 'department',
                 'field' => 'slug',
                 'terms' => array( 'department_name' )
             ),
         ),
         'orderby' => 'title',
         'order' => 'ASC',
         'post_type' => 'prod', 'posts_per_page' => '-1', 'posts_per_page' => '-1'
        );
        $query = new WP_Query( $args );
    
        if ( $query->have_posts() ) {
    
          // Array of brands
          $brands= array();
    
          $term = $query->queried_object;
    
         while ( $query->have_posts() ) : $query->the_post(); ?>
             <!-- Loop to show the brand -->
             <?php
              $terms = get_the_terms( $post->ID , 'brabds' );
     // Loop por el array de marcas
              if ( $terms != null ){
                foreach( $terms as $term ) {
    
                  // I want to check if my brand has only one product or more
                  // Only one product
                  if ($term ->count == 1){
                    // I create a variable so I can check if it's in my brands array
                       $marca = $term->name;
                    // If is not in array, push it there
                        if ( ! in_array($marca, $marcas)){
                            array_push($marcas, $marca);
                    // This query is to link to a product and get some info
                            $tax_query = '';
                                        $tax_query[] = array('taxonomy' => 'brands','field' => 'term_id','terms' => $term->term_id);
                                        $term_post = get_posts(array('post_type' => 'prod','tax_query' => $tax_query));
                                        if (!empty($term_post)) {
                                            $term_post_link = get_permalink($term_post[0]->ID);
                                            $id_prod = url_to_postid($term_post_link);
                                            $nombre_prod = get_the_title($term_post[0]->ID);
                                            echo '<a title="'.$term->name.'" rel="'.$id_prod.'">'.$term->name.'</a>';
                                        }
                        }
                  }
                  // Marcas MULTI
                  else{
                    // If there are more than a product, do the same thing but query as my needs
                        $marca = $term->name;                    
                        if ( ! in_array($marca, $marcas)){
                            array_push($marcas, $marca);
                            echo '<a rel="'.$term->term_id.'" title="'.$term->name.'">'.$term->name.'</a>';
                        }
                  }
                }
              }
              // End loop
    ?>
    
        <?php
        endwhile;
    
        wp_reset_query();
        } ?>
    Thread Starter berry metal

    (@erikalleman)

    If it’s not possible to code point 2 that I described above, to “magically” match all categories by checking for a similar array (comparing arrays?), then for point 2 it could be done to match cat[0] with cat[0], and cat[1] with cat[1], and so on… right? But then the order would matter, and I am not sure how wordpress decides which is first and second category?

    The one that has been assigned first, is that first, so is it the date that matter, or the ABC order?

    Thread Starter berry metal

    (@erikalleman)

    I would need an answer on if I could drop the extra taxonomy, and directly match as I described above? Is that feasible?

Viewing 15 replies - 1 through 15 (of 63 total)
  • The topic ‘get_next_post options’ is closed to new replies.