Question

This question is about a very specific circumstance.

  1. The site has one template file that can run a default category query with thumbnail, linked title and excerpt, or it can run a linked title only depending on a viewer choice. That is, once on the category default page, the viewer can click a List Only option. https:// domain/category/ glossary-of-wood-terms ?format=list This part works fine.

  2. The second option (linked title only) should pick up the whole dataset, not a paginated dataset.

  3. Using a pre_get_posts, I can set the query to get the whole dataset (not paginated) with

$query->set( 'posts_per_page', -1 );

and an if test that will only run that code on a particular URL. Here is where the problem lies.

It turns out that WordPress sees the address as https://domain/category/glossary-of-wood-terms?category_name=glossary-of-wood-terms with the query string hidden. But WordPress is treating it as a $_POST variable not a $_GET variable.

What address should I used in the pre_get_posts test?

Here is the code I originally added to functions.php

function get_all_terms($query) 
{
    // This will run for all main queries that are not in wp-admin.
    // You may want "is_archive()", "is_page('slug')" or some other condition.

    if(empty($Format))
      $Format = 'test 1';

    echo $Format;

    if ( ! is_admin() && $query->is_main_query() && ($Format == 'list'))
    {
        $query->set( 'posts_per_page', -1 );
    }
}
  add_action( 'pre_get_posts', 'get_all_terms' ); 

Here is code I added to see what WordPress shows as the URL. This code is in header.php. There is an echo on $current_url in the body

  global $wp; 
  if(!empty($_POST['format']))
    $Format = $_POST['format'];
  $current_url = add_query_arg( $wp->query_vars, home_url( $wp->request ));
Était-ce utile?

La solution

Looking at the pre_get_posts hook, the problem becomes apparent, the $Format variable is being pulled out of thin air:

function get_all_terms($query) 
{
    if(empty($Format))
      $Format = 'test 1';

    echo $Format;

This variable is undefined, you cannot declare a variable in one file then use it in in other places like this. To do that you have to declare it as a global variable, and you have to declare this in every place you want to use it.

My recommendation: don't, there is no need for this variable, take a different approach.

Additionally, there's a misunderstanding about URLs. WordPress does not know or care what the URL by the time it gets to the pre_get_posts step, and sometimes there is no URL! E.g. in a WP CLI command.

Query variables are just the parameters that WP_Query takes. Rewrite rules convert pretty URLs into lists of query variables, and you can put a query variable in the URL to override most of the time. But query variables isn't meant to be a representation of what WP thinks the URL is. They can even disagree with the URL!

Instead, if you want to change behaviour based on the URL, just check the URL:

function nora_get_all_terms( \WP_Query $query ) {
    if ( !isset( $_GET['format' ] ) ) {
        return;
    }

Here we check the format URL parameter, and if it is not set, we return early. If it is set, continue the function and use $_GET['format'].

Some notes:

  • get_all_terms is a very generic name, at the very least prefix it or use a more specific name
  • global variables are bad, avoid them
  • Don't echo out, use a tool such as query monitor to look at the query variables, or better yet, use xdebug + and IDE such as PHPStorm to look at the variables directly with a debugger
  • keep variable names to lowercase, and follow the WP coding standards
  • A decent code editor will automatically indent for you, the codes indenting is broken and this can cause easy mistakes that are impossible when indenting is correct. At a minimum, fix indenting before showing the code to other people as broken indenting makes code difficult to read and understand
  • $_POST and $_GET are populated by PHP, not WordPress. $_POST won't be populated unless your browser made a POST request
  • Always start with the problem you were trying to solve, don't fall into the trap of an XY question
  • Consider looking into rewrite rules, you can add a custom query variable, and remove the URL parameter entirely by embedding it in the URL itself with a format/list on the end
  • whitelist and validate the format value, otherwise people can put malicious values in and if the format value is printed anywhere on the page you'll have a URL injection attack
Licencié sous: CC-BY-SA avec attribution
Non affilié à wordpress.stackexchange
scroll top