2

I have a custom Taxonomy called 'owner' and it has multiple posts as owner names (Using as a category) so I can filter posts by 'owner' taxonomy.

I'm trying to make an index page of all owner names which starts with letter 'A'. I was able to list all the owners with following code.

foreach ( get_terms( 'owner' ) as $o ){
        $owner = $o -> name;
        if($owner[0] === 'A'){
            // Coding here...
        }
}

The issue I face is I want to show a pagination at the bottom of the page because there are hundreds of authors stars with 'A'.

6
  • 3
    You should not be naming your taxonomy author, author is a reserved term Commented Oct 11, 2015 at 16:59
  • actually I have changed that now to a different name. However the issue is still exists. Commented Oct 11, 2015 at 17:16
  • Might be best to manually create pagination using URL ($_GET) variables and your own custom prev/next links.
    – cfx
    Commented Oct 11, 2015 at 17:38
  • Any code snippets? Commented Oct 12, 2015 at 0:06
  • I'm using my own shortcode to display owners. I just want to add the pagination instead of displaying all the owners. Commented Oct 12, 2015 at 0:22

2 Answers 2

5
+50

Before we look at pagination, from what I have picked up in your question, you only need terms starting with A. If so, you can make use of the name__like parameter in get_terms to get terms only that starts with A. Just a note on that, the operation of the parameter was changed in Wordpress V3.7, so you will need to apply the following filter for this to work as expected (Credit to @s_ha_dum, see his answer here. NOTE: The code requires PHP 5.4+)

add_filter( 'terms_clauses', function ($clauses) 
{
  remove_filter( 'term_clauses', __FUNCTION__ );

  $pattern = '|(name LIKE )\'%(.+%)\'|';
  $clauses['where'] = preg_replace($pattern,'$1 \'$2\'',$clauses['where']);
  return $clauses;
});

$terms = get_terms( 'ownwer' ['name__like' => 'A'] );

To paginate a list of terms, we need:

  • The current page number

  • The total amount of terms in the list

  • Total amont of pages there will be

To get the page number of the current page or any page is easy. This will work on all pages including static front pages and single post pages

if ( get_query_var( 'paged' ) ) {
    $current_page = get_query_var( 'paged' );
} elseif ( get_query_var( 'page' ) ) {
    $current_page = get_query_var( 'page' );
} else {
    $current_page = 1;
}

We now need to know the total amount of terms from the taxonomy. Here we can use either wp_count_terms(), which uses get_terms() or use get_terms() itself. Remember, if we used the filter to get terms by a specific letter/name, the filter will be applied to this run of get_terms()/wp_count_terms() as well as we are making using of a closure

$terms_count = get_terms( 'owner', ['name__like' => 'A', 'fields' => 'count'] );

Now we have the total amount of terms matching our criteria. Just remember, if your are going to use wp_count_terms(), just remember to set hide_empty to true if you do not need to include empty terms. By default, wp_count_terms() sets this to false

Now we can calculate our maximum amount of pages

// Set the amount of terms we need to display per page
$terms_per_page = 10;
// Get the total amount of pages
$max_num_pages = $terms_count / $terms_per_page;

To get pagination links to next and previous pages, it is really easy. The only thing a pagination function ever needs to know from any query is the maximum amount of pages, nothing else. It does not need to know what it should paginate. So we can simply use the next_posts_link() and previous_posts_link() functions. You can also make use paginate_links() or even write your own function to suite your needs. Just remember to pass $max_num_pages as the maximum amount of pages to the pagination function

next_posts_link( 'Next terms', $max_num_pages );
previous_posts_link( 'Previous terms' );

The only thing we still need to do is to paginate get_terms(), which is also really easy. We will make use of the offset parameter to offset the terms according to page and number to get the required amount of terms per page

// Calculate offset
$offset = ( $current_page == 1) ? 0 : ( ($current_page - 1) * $terms_per_page );
// Setup our arguments
$args = [
    'number' => $terms_per_page,
    'offset' => $offset
];

We can now put everything together

ALL TOGETHER NOW

Just before we do, a couple of important notes

  • All of the code is untested

  • The code needs at least PHP 5.4, which is the absolute minimum PHP version you should be running at time of this post

  • Modify and tear apart as needed

Here is the code, finally

add_filter( 'terms_clauses', function ($clauses) 
{
  remove_filter( 'term_clauses', __FUNCTION__ );

  $pattern = '|(name LIKE )\'%(.+%)\'|';
  $clauses['where'] = preg_replace($pattern,'$1 \'$2\'',$clauses['where']);
  return $clauses;
});

$taxonomy = 'owner';

$terms_count = get_terms( $taxonomy, ['name__like' => 'A', 'fields' => 'count'] );
if ( $terms_count && !is_wp_error( $terms ) ) {

    if ( get_query_var( 'paged' ) ) {
        $current_page = get_query_var( 'paged' );
    } elseif ( get_query_var( 'page' ) ) {
        $current_page = get_query_var( 'page' );
    } else {
        $current_page = 1;
    }


    // Set the amount of terms we need to display per page
    $terms_per_page = 10;
    // Get the total amount of pages
    $max_num_pages = $terms_count / $terms_per_page;

    // Calculate offset
    $offset = ( $current_page == 1) ? 0 : ( ($current_page - 1) * $terms_per_page );
    // Setup our arguments
    $args = [
        'number' => $terms_per_page,
        'offset' => $offset,
        'name__like' => 'A'
    ];
    $terms = get_terms( $taxonomy, $args );

    // Do what you need to do with $terms

    next_posts_link( 'Next terms', $max_num_pages );
    previous_posts_link( 'Previous terms' );

}
11
  • This made me think of Yellow Submarine :) Commented Oct 17, 2015 at 8:18
  • @ialocin Hahaha, great oldtimer. ;-) Commented Oct 17, 2015 at 8:23
  • Thanks for the code. However this is displaying all the owners. Not only people starts with 'A' but also everyone :( Commented Oct 18, 2015 at 9:45
  • name_like should be name__like Commented Oct 18, 2015 at 9:56
  • 1
    Check my pagination function here. You will need to make a few alterations as by default, it uses the query object, you need to convert it to work with the integer value from $max_num_pages. If you have an issue, feel free to ask a new question with all the specifics :-) Commented Oct 18, 2015 at 15:30
2

If you want to only visually limit the number of displayed names, you could use javascript or jQuery and CSS to paginate the results into smaller chunks that visitors could read through. But this will not create real, distinct pages.

I will update this answer with a piece of code I used to limit a long list at X numbers of items, that you browse with a previous / next link, but also can easily add a numbered pagination to.

Otherwise, a quick search produced that (WordPress) plugin, but I have not tested it, and am not sure about compatibility with current WP versions: http://wordpress.mfields.org/plugins/taxonomy-list-shortcode/ It seems it does precisely what you want (PHP) in the form of a shortcode.

Update: I had scavenged most of this code from somewhere and modified it to suit my needs. In my application I used functions to disable and enable elements etc, which I reverted here into straight jQuery, so take into account there might be a piece or another of custom code that remains there that will need changing to work with your thing.

This in jQuery:

var paginate_list = function(items) {
    var pageSize = items; // How many items per page
    var numberOfPages = Math.ceil(($('.lists li').length)/pageSize); // I used list items but you can use anything, this counts how many elements in total, and divides by the previous to know how many pages total
    var pageCounter = $("#current-page"); // I store the current page number in a hidden input value for my particular situation but you can keep track of it anyway else
    var prev = $('#navigation .key-prev');
    var next = $('#navigation .key-next'); // the navigation buttons
    pageCounter.val(1); // initialize to page 1, also peculiar to my application
    prev.attr('disable', true); // disable prev button if page 1
    if ( numberOfPages <= 1 ) {
        next.attr('disable', true); // disable next if only 1 page
    }
    next.on('click', function () {
        // calculate the list offset
        $(".lists li:nth-child(-n+" + ((pageCounter.val() * pageSize) + pageSize) + ")").show();
        $(".lists li:nth-child(-n+" + pageCounter.val() * pageSize + ")").hide();
        pageCounter.val(Number(pageCounter.val()) + 1); // update page counter
        if (pageCounter.val() != 1) {
            prev.attr('disable', false); // enable previous button
        }
        if (pageCounter.val() == numberOfPages) {
            $(this).attr('disable', true); // disable the next button when you reach the end
        }
    });
    prev.on('click', function () {
        // the same in reverse
        pageCounter.val(Number(pageCounter.val()) - 1);
        $(".lists li").hide();
        $(".lists li:nth-child(-n+" + (pageCounter.val() * pageSize) + ")").show();
        $(".lists li:nth-child(-n+" + ((pageCounter.val() * pageSize) - pageSize) + ")").hide();
        if (pageCounter.val() == 1) {
            $(this).attr('disable', true);
        } 
        if (pageCounter.val() < numberOfPages) {
            next.attr('disable', false);
        } 
    });
};

And it would work with lists like this:

<ul class="lists">
  <li><!-- your first item --></li>
  <li><!-- your second item --></li>
  <li><!-- your third item --></li>
  <li><!-- your fourth item etc... --></li>
</ul>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.