Pagination, filtering, date field query

I use paging in a loop with paged=10. The loop returns 9 posts. I expect these 9 posts to be displayed on one page, and no paging buttons to be displayed. Instead, paging buttons are displayed for 3 pages, and the posts are displayed as follows:

  • 6 posts on page 1
  • 1 post on page 2
  • 2 posts on page 3

I’m using this code:

<If loop exists type=post category=presseartikel status=publish orderby_field=veroeffentlichung-datum order=desc>
<Date all_locale=de />
<Loop>
  <If first><h1></h1></If>
  <If field=ankundigung_zum before=today>
    <If field="image" exists><div class="veranstaltungen-image"><a href="{Field url}"><Field image size=thumbnail /></a></div></If>
    <div class="veranstaltungen-title"><a href="{Field url}"><Field title /></a></div>
    <div class="veranstaltungen-datum"><Field veroeffentlichung-datum from_format="Ymd" date_format="d.m.Y" /></div>
    <div class="veranstaltungen-excerpt"><Field excerpt auto=true words=80 more="&hellip;&nbsp;" /><a href="{Field url}"><Field excerpt auto=true words=0 more="&nbsp;weiterlesen" /></a></div>
    <div style="clear: both;"></div>
    <hr />
  </If>
</Loop>
<Else />
  (Noch keine Eintr&auml;ge)
</If>

<div style="align:center"><PaginateButtons scroll_top=true /></div>

Any ideas?

Hi Mihal, thank you for the issue description.

That does sound like a bug, probably caused by the combination of pagination with <Loop> and “loop exists”.

I’ve made a note to look into this issue deeper, and will comment back here when it’s solved.

1 Like

Hi Eliot,

thanks for the quick reply. In the meantime I have narrowed down the issue. The problem has to do with the filter.

This works fine:

<Loop type=post category=presseartikel paged=10>
    <Field title /><br/>
</Loop>

<PaginateButtons />

This does not work correctly:

<Loop type=post category=presseartikel paged=10>
  <If field=ankundigung_zum before=today>
    <Field title /><br/>
  </If>
</Loop>

<PaginateButtons />

I suspect the hit count is done before the filter was applied.

Cheers,
Mihal

I see, that does narrow down the cause of the issue. Yes, it’s exactly how you said in the last sentence.

Pagination happens when the loop is created at the start. And any filtering done inside the content, using If tag, will be applied after the items are paginated already, inside of each item as they’re being looped.

What’s happening in the second code snippet is that items which don’t match the condition just have empty content - but they still exist as items within a page.


For pagination to work, the filter (using If tag) needs to be converted into a query (for the Loop tag).

Fortunately the condition is a date field query, which is supported by the Post loop type. In the linked documentation page, the following query parameters are relevant:

  • custom_date_field
  • custom_date_field_compare
  • custom_date_field_format
  • custom_date_field_type
  • custom_date_field_value

The last parameter is a question. In the docs, I see it supports the value current, but not today. (I believe the reason is that today is a duration, not a specific point in time.) The expected date format is Ymd, so we can create it with the Date tag.

Something like this could work:

<Loop type=post category=presseartikel paged=10
  custom_date_field=ankundigung_zum
  custom_date_field_compare=before
  custom_date_field_value="{Date format=Ymd}"
>
2 Likes

Hi @benjamin - I wanted to elaborate on the above post, because there are some topics I’ve had difficulty explaining. Maybe they deserve a separate documentation page, blog post, tutorial (?), with examples demonstrating how they work.


One topic is about the difference between:

  • Using loop query to get matching posts
  • Filtering posts with If tag

Loop query is performed by the database engine (MySQL/MariaDB), and It’s much more efficient/faster to get posts that match a set of query parameters - compared to getting a larger number of posts (all posts, or all posts in a category, etc.), then to loop each item and filter them using If conditions.

And, as this current issue shows, filtering with If does not work with pagination, because the items are already paginated before they get filtered out by the If statement.


Another topic is about the difference between:

The Post loop type’s query parameter custom_field is for querying raw field values. Here, “raw” means the field values as they are stored in the database, before they get processed by WordPress core or plugins. This distinction means such queries are limited to simple value types like text, number, and dates (if they’re in the right format).

In contrast, the field attribute of the Loop tag is not a query parameter.

It’s currently documented in the page Loop query - but actually, that page should be titled, Loop filters. These features are supported by all loop types, because it’s implemented in the “base loop class” that serves as a common base.

Loop filters are less efficient than queries because they happen after the query is made, same as filtering with If tag. (Notably, sort_field is a loop filter, in contrast to orderby which is a query parameter of the loop types Post, Taxonomy, User, and maybe others.)

In general, it’s always better to use custom field query where possible.

The reason why loop filters exist is for extensibility beyond querying raw field values. For example, some custom fields are not stored as simple text or number values, and need to be processed by a plugin (such ACF, Pods, WooCommerce, LearnDash) before they can be “queried”, or rather, filtered. Loop filters could be useful in such cases.

In hindsight, I probably should have named the attribute filter_field to clarify its behavior as a filter and not a query parameter. Then I could have renamed custom_field to field, so that the better, more efficient solution is easier to express.


That’s why the date field query is done using custom_date_field, instead of just date_field. The latter I suppose could be a filter that supports a wider range of date formats and more complex conditions.

It’s not simple to use, requiring two or more long parameters to express. I think it needs its own documentation page with common usage examples. Same with taxonomy term query, especially involving multiple terms.


Anyway, just for your information, in case you encounter these topics/questions in the future.

2 Likes

Hi Julia, I was having similar issue and I had created a post for it but it wasnt responded by you. Can you see my post here again: https://discourse.tangible.one/t/template-returns-first-post-in-loop-3-times/563

Yes this works. Thanks for your great support!

Mihal

1 Like

What about <Loop acf_relationship…> that doesn’t support filtering attributes such as Taxonomy i think?
With such a loop, i filtered using <If> in the loop, and my pagination works fine but doesn’t respect paged=x (the number of posts displayed varies initially and after i click the pagination numbers)

Hey @avanti, here’s an explanations about why that’s happening:

This seems to just be a limitation of the ACF relationship loop that it doesn’t accept query parameters. Depending on what data exists in your relationship field, you might also be able to just pass the data to a post loop, which would then allow you to filter it using query parameters. I just expressed how one might implement that idea in this thread.

1 Like

Hi @benjamin,

Thanks a lot for your insight again, the solution works fine and looks very clever (looping through Posts and passing ACF Relationship IDs).

The number of Posts set in the pagination is now respected.

My code:

<Loop type=output id="{Field project_outputs}" taxonomy=information_type terms=journal-article,technical-report orderby=selection order=desc paged=3>
  <strong><Taxonomy information_type><Term title /></Taxonomy></strong> - <Field title /><br>
</Loop>
<PaginateButtons />

One more question about this project: can i add multiple terms in the loop parameter? :wink:
[Update] So simple: multiple terms separated by a comma… (code above is now updated)

1 Like