Aleš Sýkora / November 28, 2023 / 3 comments

Custom Schema.org markup for WordPress Custom Post types

Post summary: Learn how to add Schema.org markup with JSON-ld and WordPress and create your own unique Schema.org plugin.

I made this tutorial because my first version Schema Markup For Blog Post W/ Gogle Tag Manager And Toolset Layouts is not supported by Google anymore. You can see those Schema on my WordPress store www.bestonline.cz.

What I used? Of course – WordPress with my favourite Astra theme custom Child theme without pre built Schema markup (ask Astra support or send me a PM for this!) and Toolset Types.

Implementation steps:

  1. Select Schema.org markup type for each WordPress CPT (Custom Post Type)
  2. Create PHP file with variables and Schema markup code
  3. Create plugin from the PHP file

Download mine Schema.org plugin example for FREE

Schema markup selection

First what you’ll need is to decide which Schema markup you need for every Custom Post Type. In this scenario I have custom post Article (created with Toolset Types) and Product (from Woocommerce).

I decided to use this types of Schema.org: BlogPosting & Product.

Schema.org usable for Product

  • Product https://schema.org/Product – “Any offered product or service. For example: a pair of shoes; a concert ticket; the rental of a car; a haircut; or an episode of a TV show streamed online.”

Schema.org usable for Article

  • NewsArticle https://schema.org/NewsArticle“A NewsArticle is an article whose content reports news, or provides background context and supporting materials for understanding the news.”
  • BlogPosting https://schema.org/BlogPosting“A blog post.”
  • TechArticle https://schema.org/TechArticle“A technical article – Example: How-to (task) topics, step-by-step, procedural troubleshooting, specifications, etc.”
  • Article https://schema.org/Article“An article, such as a news article or piece of investigative report. Newspapers and magazines have articles of many different types and this is intended to cover them all.”

Usable links

generating Schema.org JSON-Ld in PHP

If you want to add some variable, look how to get the value in the WordPress Code Reference. If you need to add custom fields created with Toolset, look into Types Field API.

Types fields API uses this functions:

types_render_field( 'field-slug', array( 'arg1' => 'val1', 'arg2' => 'val2' ) ); //Types fields
types_render_usermeta( 'field-slug', array( 'arg1' => 'val1', 'arg2' => 'val2' ) ); //Types user meta fields

1) Create the PHP file and function in your code editor (I am using VS Code). Plus add action which inject the function into the WordPress head section.

<?php
function addschemaorg() {} //Function for Schema.org
add_action('wp_head', 'addschemaorg'); //Add Schema to header
?>

2) Decide which values you need to use as a Global variables (in all schemas) and get them.

My Global Variables:

  • Post Title
  • Description from Custom Types field
  • Permalink
global $post;
$headline = get_the_title($post->ID); //Post Title (also headline)
$description = types_render_field('meta-description'); //Post short description from custom field
$permalink = get_permalink(); //Current post permalink

3) Create Condition based on Post Type to display right Schema

if (is_singular('blog')) {} //only for post type blog
else if (is_singular('product')) {} //only for post type product
endif;

4) Add custom variables to the conditions

WordPress BlogPosting custom variables

  • Author Display name
  • Thumbnail URL
  • Published date
  • Modified date
$author_id = $post->post_author; //Post Author id
$author = get_the_author_meta('display_name', $author_id); //Post Author Display Name
$imgurl = get_the_post_thumbnail_url(); //Post Thumbnail
$datepublished = get_the_date('c'); //Date published in ISO 8601 format
$datemodified = get_the_modified_time('c'); //Date modified in ISO 8601 format

WordPress Product custom variables

  • Product Image
  • Product Brand Term
  • Price
$productimg = get_the_post_thumbnail_url(); //product image
$terms = get_the_terms($post->ID, 'znacka-produktu'); //get terms from custom category znacka-produktu
$term = array_shift($terms); //use only first term
$productbrandterm = $term->name; //get custom term used for product brand
$price = get_post_meta(get_the_ID(), '_regular_price', true); //product priceInsert Var

5) Insert Schema markup variableVariables to the Schema markup in PHP

BlogPosting

$schema_blogposting = array(
            '@context'  => "https://schema.org",
            '@type'     => "BlogPosting",
            'mainEntityOfPage' => array(
                '@type' => "WebPage",
                '@id'   => $permalink
            ),
            'headline' => $headline,
            'image'     => array(
                '@type'     => "ImageObject",
                'url'       => $imgurl,
                'height'    => "440",
                'width'     => "880"
            ),
            'datePublished' => $datepublished,
            'dateModified' => $datemodified,
            'author'    => array(
                '@type'     => "Person",
                'name'      => $author
            ),
            'publisher' => array(
                '@type' => "Organization",
                'name'  => "Your Organization Name",
                'logo'  => array(
                    '@type'  => "ImageObject",
                    'url'    => 'https://www.yourweb.com/yourlogoadress.png',
                    'width'  => "250",
                    'height' => "66"
                )
            ),
            'description' => $description
        );

Product

$schema_product = array(
            '@context'  => "https://schema.org",
            '@type'     => "Product",
            'name' => $headline,
            'image' => $productimg,
            'description' => $description,
            'brand' => array(
                '@type' => "Thing",
                'name'   => $productbrandterm
            ),
            'Offers' => array(
                '@type' => "Offer",
                'url'   => $permalink,
                'priceCurrency' => 'CZK',
                'price'   => $price,
                'url'   => $permalink,
                'itemCondition' => "https://schema.org/NewCondition",
                'availability' => "https://schema.org/InStock",
                'seller' => array(
                    '@type' => "Organization",
                    'name' => "Your Organization Name"
                )
            )
        );

6) Encode PHP to JSON-ld

In this step – you need to decode the PHP variable into JSON-ld. I will use the json_encode function.

echo '<script type="application/ld+json">' . json_encode($schema_product) . '</script>'; //encode schema for product
echo '<script type="application/ld+json">' . json_encode($schema_blogposting) . '</script>'; //encode schema for blogposting

7) Complete the PHP file

Well that’s it. Now it is time to put all blocks together and finallize the script. You can grab mine code from below and change the values.

You can put this code in the functions.php now and test your structured data in Google Structured Data testing Tool. If you don’t want mess in functions.php then go to the next step and create the plugin from the script.

<?php
function addschema() //Function for Schema.org
{
    global $post;
    $headline = get_the_title($post->ID); //Post Title (also headline)
    $description = types_render_field('meta-description'); //Post short description from custom field
    $permalink = get_permalink(); //Current post permalink
    if (is_singular('blog')) { //only for post type Blog
        $author_id = $post->post_author; //Post Author id
        $author = get_the_author_meta('display_name', $author_id); //Post Author Display Name
        $imgurl = get_the_post_thumbnail_url(); //Post Thumbnail
        $datepublished = get_the_date('c'); //Date published in ISO 8601 format
        $datemodified = get_the_modified_time('c'); //Date modified in ISO 8601 format
        $schema_blogposting = array(
            '@context'  => "https://schema.org",
            '@type'     => "BlogPosting",
            'mainEntityOfPage' => array(
                '@type' => "WebPage",
                '@id'   => $permalink
            ),
            'headline' => $headline,
            'image'     => array(
                '@type'     => "ImageObject",
                'url'       => $imgurl,
                'height'    => "440",
                'width'     => "880"
            ),
            'datePublished' => $datepublished,
            'dateModified' => $datemodified,
            'author'    => array(
                '@type'     => "Person",
                'name'      => $author
            ),
            'publisher' => array(
                '@type' => "Organization",
                'name'  => "Your Organization Name",
                'logo'  => array(
                    '@type'  => "ImageObject",
                    'url'    => 'https://www.yourweb.com/yourlogo.png',
                    'width'  => "250",
                    'height' => "66"
                )
            ),
            'description' => $description
        );
        echo '<script type="application/ld+json">' . json_encode($schema_blogposting) . '</script>'; //encode schema for blogposting
    } else if (is_singular('product')) { //only for post type product
        $productimg = get_the_post_thumbnail_url(); //product image
        $terms =  get_the_terms($post->ID, 'znacka-produktu'); //get terms from custom category znacka-produktu
        $term = array_shift($terms); //use only first term
        $productbrandterm = $term->name; //get custom term used for product brand
        $price = get_post_meta(get_the_ID(), '_regular_price', true); //product price
        $schema_product = array(
            '@context'  => "https://schema.org",
            '@type'     => "Product",
            'name' => $headline,
            'image' => $productimg,
            'description' => $description,
            'brand' => array(
                '@type' => "Thing",
                'name'   => $productbrandterm
            ),
            'Offers' => array(
                '@type' => "Offer",
                'url'   => $permalink,
                'priceCurrency' => 'CZK',
                'price'   => $price,
                'url'   => $permalink,
                'itemCondition' => "https://schema.org/NewCondition",
                'availability' => "https://schema.org/InStock",
                'seller' => array(
                    '@type' => "Organization",
                    'name' => "Your Organization Name"
                )
            )
        );
        echo '<script type="application/ld+json">' . json_encode($schema_product) . '</script>'; //encode schema for product
    }
endif;
}
add_action('wp_head', 'pridatschema'); //Add Schema to header

?>

Create your own Schema.org WordPress plugin

Adding the code into WordPress functions.php is not recommended in many ways. It is so easy to create small plugin from the code. Just add this header after opening PHP tag:

<?php 
/**
 * Plugin Name: Schema.org for Toolset.wiki
 * Description: Add Schema.org in JSONld to blog post and product
 * Plugin URI: https://www.great-tit.com/
 * Author: Aleš Sýkora
 * Author URI: https://www.alessykora.cz/
 * Version: 1.0.0
 * License: GPL2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 */

//place plugin functions and code here

?>

Then add into *.zip archive and install from WordPress admin.

Download mine Schema.org plugin example for FREE

Final Result

If you did everything good, then you should have results like me.

Schema.org for Product in WordPress
Schema.org for Product in WordPress
Schema.org for Blog Post in WordPress
Schema.org for Blog Post in WordPress

You can implement any kind of Schema.org structure with this tutorial. For example recipe, event and more.

I will be happy if you want share your code with us here in comments or in PM (use the share snippet form). I will post it here with your permission.

Fuel my passion for writing with a beer🍺

Your support not only makes me drunk but also greatly motivates me to continue creating content that helps. Cheers to more discoveries and shared success. 🍻

3 comments

  • Hi, I downloaded your plugin, but it’s getting error in line 90, when I try to activate it. Can you please rectify it?

  • A

    Or maybe try to delete the line 90 – the endif

  • A

    Hello, Toolset is not being maintained anymore, so my snippets for it will not have any future updates. I am Sorry. I will create a new tutorial maybe, for solution without Toolset. Would you like it?

Share Your Thoughts