1

What? I am modifying my theme to show comments of a post on a separate page.

How? Mostly based on this answer but with improved checks and code. So this is what my page-comments.php (kinda) looks like:

(The code is very easy to scan through, trust me!)

<?php get_header(); ?>

<?php
    /*
     * (Example URL: example.com/comments/?original_post=ID)
     *
     * Check if HTTP variable (original_post) exists in queried URL,
     * AND that it is set to some value (ID), AND that the value (ID) is a number.
     */
    if( array_key_exists( 'original_post', $_GET ) && isset( $_GET['original_post'] ) && ctype_digit( $_GET['original_post'] ) ) {

        $query_original_post = new WP_Query( array(
            'posts_per_page' => 1,
            'p'              => $_GET['original_post'],
            'post_type'      => 'any',
        ) );

        if( $query_original_post->have_posts() ) {

            while ( $query_original_post->have_posts() ) : $query_original_post->the_post();

                // [...]

            endwhile;
            wp_reset_postdata();

        } else {

            /*
             * Return 404 error if there are no posts
             */
            global $wp_query;
            $wp_query->set_404();
            status_header( 404 );
            nocache_headers();
            get_template_part( '404', 'archive' );
            //exit();

        }

    } else {

        /*
         * Return 404 error if the HTTP variable (original_post) doesn't
         * exist in queried URL, OR it isn't set to any value (ID),
         * OR the value (ID) isn't a number.
         */
        global $wp_query;
        $wp_query->set_404();
        status_header( 404 );
        nocache_headers();
        get_template_part( '404', 'archive' );
        //exit();

    }
?>

<?php get_footer(); ?>

(The code I use to return a 404 error is based on these two solutions.)

As you can see I am doing two checks in the code (at least that's what I intended to do):

  1. Check if HTTP variable (original_post) exists in queried URL, AND that it is set to some value (ID), AND that the value (ID) is a number. OTHERWISE, return a 404 error with appropriate headers.

  2. Check if the custom WordPress query ($query_original_post) has any results to loop over. OTHERWISE, return a 404 error with appropriate headers.

Problem:

  1. Is that the right way to do it? (or at least, can it be any simpler?)

  2. (If yes to #1) It appears to work, but returns 200 OK header when I go to an URL like: example.com/comments/?original_post=NUMBER, where NUMBER is any positive integer over 4 digits long (e.g. 14532).

    I don't understand the relation. Why'd something like ``example.com/comments/?original_post=14532` return 200 OK header when I am logged-into WordPress, and 404 error (which it should) when I am not?

1 Answer 1

3

Headers are sent long before you try to alter them. Headers are sent by actions associated with get_header(), so by the time your code executes, it is too late to alter the headers. You can demonstrate this with a simple experiment. Try each of the following:

get_header(); 
status_header( 404 );

and

status_header( 404 );
get_header(); 

In a template file and watch the output with a tool like HttpFox or Wireshark (if you really want to have some fun :) ).

To effectively change the headers you will need to run your logic before get_header().

I believe this will get the effect you want with fewer lines of code to boot:

/*
* (Example URL: example.com/comments/?original_post=ID)
*
* Check if HTTP variable (original_post) exists in queried URL,
* AND that it is set to some value (ID), AND that the value (ID) is a number.
*/

if( 
  array_key_exists( 'original_post', $_GET ) 
  && isset( $_GET['original_post'] ) 
  && ctype_digit( $_GET['original_post'] ) 
) {
  $query_original_post = new WP_Query( 
    array(
      'posts_per_page' => 1,
      'p'              => $_GET['original_post'],
      'post_type'      => 'any',
    ) 
  );
  if( !$query_original_post->have_posts() ) {
    global $wp_query;
    $wp_query->set_404();
    status_header( 404 );
    nocache_headers();
  } 
}

get_header();
if( !empty($query_original_post) && $query_original_post->have_posts() ) {
  while ( $query_original_post->have_posts() ) {
    $query_original_post->the_post();
    // [...]
  }
  wp_reset_postdata();
} else {
  get_template_part( '404', 'archive' );
}
get_footer();

And for the love of all that is holy please don't use PHP opening and closing tags unless you actually need them.

2
  • Had no clue the order matters. Thanks a lot for the detailed explanation (and the clean code)!
    – its_me
    Commented Oct 13, 2013 at 15:21
  • 1
    Most cases order does matter. PHP does not compile and then execute. It executes as it goes.
    – s_ha_dum
    Commented Oct 13, 2013 at 15:26

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.