最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

templates - Can a link in WordPress contain a query string that is picked up as $_POST

programmeradmin0浏览0评论

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

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 ));
Share Improve this question edited May 31, 2020 at 20:58 Nora McDougall-Collins asked May 30, 2020 at 23:02 Nora McDougall-CollinsNora McDougall-Collins 3952 silver badges15 bronze badges 8
  • Can you rephrase 1)? It's got a lot of options and it's very difficult to understand or visualize, I've re-read it a few times and don't understand what you meant, and it refers to things that haven't been mentioned. E.g. in 2) you refer to the second option but you've never mentioned this beforehand so it isn't clear what it is or where it comes from. Use the edit link under the post tags to modify the question so it's easier to understand and clearer – Tom J Nowell Commented May 30, 2020 at 23:38
  • I also don't understand what you mean by treating it as a $_POST variable, WP doesn't handle query values differently if they're GET or POST. Can you include your full pre_get_posts filter in your question? It's very difficult to debug without seeing the code – Tom J Nowell Commented May 30, 2020 at 23:40
  • Am I allowed to just add a link to the site? Sometimes I find the rules here to be subjectively enforced. – Nora McDougall-Collins Commented May 31, 2020 at 18:16
  • Your answers may have actually pointed me to the answer. If, on the first instance, the page loads with the default archive query, but a viewer clicks the View List link, which has the query string ?format=list, can pre_get_posts run? That is does WordPress only reload the template file? – Nora McDougall-Collins Commented May 31, 2020 at 18:25
  • pre_get_posts always run on queries, but as I said, your pre_get_posts filter is missing from your question, making it 1000x times more difficult to answer your question, if not impossible to answer. Update your question to include the code – Tom J Nowell Commented May 31, 2020 at 20:40
 |  Show 3 more comments

1 Answer 1

Reset to default 2

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
发布评论

评论列表(0)

  1. 暂无评论