Search code examples
phpwordpressloopswhile-loopcategories

Schema markup from a PHP loop


I am trying to auto generate a schema markup from a WordPress PHP loop. I am trying to create my markup from five latest post in my "hovedret" WordPress post category.

The schema markup I am trying to generate:

<script type="application/ld+json">
    {
      "@context":"https://schema.org",
      "@type":"ItemList",
      "itemListElement":[
        {
          "@type":"ListItem",
          "position":1,
          "url":"http://example.com/peanut-butter-cookies.html"
        },
        {
          "@type":"ListItem",
          "position":2,
          "url":"http://example.com/triple-chocolate-chunk.html"
        },
        {
          "@type":"ListItem",
          "position":3,
          "url":"http://example.com/snickerdoodles.html"
        }
      ]
    }
    </script>

My code should loop through the latest five posts in "hovedret" category so I would have positions 1, 2, 3, 4, and 5. I am using get_the_permalink in order to fill in URL.

I am using wp_head hook in order to return my code in of my website. For some reason, the code breaks my site. I am not sure if I have constructed my while loop the right way or something else is wrong with my code? I have tried echo instead of return $string;

any clues on what I am missing ??

//SCHEMA MARKUP
function tt_hook_schema_new()
{
  if ( is_category() ) 
  {
        $post_per_page = 5;
            $the_query = new WP_Query( array( 'category_name' => 'hovedret', 'posts_per_page' => $post_per_page ) ); 
            
      if ( $the_query->have_posts() ) 
      {
                    $string .= '<script type="application/ld+json">
                                        {
                                    "@context":"https://schema.org",
                                    "@type":"ItemList",
                      "itemListElement":[';
          $counter = 0;
          
          while ( $the_query->have_posts() )
          {
              $counter = $counter + 1;
              $string .= '{';
              $string .= '"@type":"ListItem",';
              $string .= '"position":' . $counter;
              $string .= '"url":"' . get_the_permalink() . '"';   
              $string .= '}';
              
              if($counter != $post_per_page)
              {
                $string .= ',';
              }
          }
          $string .= ']
                                }
                      </script>';
                      
        return $string;

/* Restore original Post Data */
wp_reset_postdata();
            }

  }
}
add_action('wp_head', 'tt_hook_schema_new');

Solution

  • There is one syntax error:

    $string .= '<script type="application/ld+json"> should become
    $string = '<script type="application/ld+json">
    (removing the dot, since $string wasn't defined before).

    And you run into an infinite loop, since you never get the next post. It should be:

    while ( $the_query->have_posts() ) {
        $the_query->the_post();
        // ...
    }
    

    And you still have to echo the contents.

    Edit: I fixed some more mistakes and here is a corrected version (look at the comments for the changes):

    function tt_hook_schema_new() {
        if ( is_category() ) {
            $post_per_page = 5;
            $the_query     = new WP_Query(
                array(
                    'category_name'  => 'hovedret',
                    'posts_per_page' => $post_per_page,
                )
            );
    
            if ( $the_query->have_posts() ) {
                // Here was a `.` too much.
                $string  = '<script type="application/ld+json">
                            {
                                "@context":"https://schema.org",
                                "@type":"ItemList",
                                "itemListElement":[';
                $counter = 0;
    
                while ( $the_query->have_posts() ) {
                    // This line was missing.
                    $the_query->the_post();
    
                    $counter++;
                    $string .= '{';
                    $string .= '"@type":"ListItem",';
                    // There was a missing comma.
                    $string .= '"position":' . $counter . ',';
                    $string .= '"url":"' . get_the_permalink() . '"';
                    $string .= '}';
    
                    // Having less then `$post_per_page` would still have the last comma.
                    if ( $counter < $the_query->found_posts ) {
                        $string .= ',';
                    }
                }
                $string .= ']
                        }
                        </script>';
    
                // Echoing stuff without escaping can be insecure!
                echo $string;
            }
            // You should reset postdata outside the `if` statement.
            /* Restore original Post Data */
            wp_reset_postdata();
        }
    }
    add_action( 'wp_head', 'tt_hook_schema_new' );