What's in this article

    Why add schema markup?

    Schema markup helps search engines understand what your blog is all about.  Schema tells the search engine what the content means by adding more context, for example we can add schema markup to tell search engines that a page is a Blog article and who the author is etc.

    Your website experiences a boost in traffic because Schema markup enables the creation of rich snippets, leading to increased clickthrough rates compared to standard search results.

    Your web pages have an underlying meaning that people understand when they read the web pages. But search engines have a limited understanding of what is being discussed on those pages. By adding additional tags to the HTML of your web pages—tags that say, "Hey search engine, this information describes this specific movie, or place, or person, or video"—you can help search engines and other applications better understand your content and display it in a useful, relevant way.

    schema.org

    Our schema markup for our blog posts

    There are different types of schema markup, RDFa, Microdata, and JSON-LD.  In this article we will look at JSON-LD which is the newer type, less prone to errors and easier to implement in one block of new code, rather than trying to inject it into a page of existing code.

    The following is an example of schema markup in the JSON-LD format on a blog page and is the code we will be adding in our Concrete CMS websites' blog article:

    <script type="application/ld+json">
    { 
      "@context": "http://schema.org",
      "@type": "Article",
      "mainEntityOfPage": {
        "@type": "WebPage",
        "@id": "https://www.madesimplemedia.co.uk/blog/how-to-drive-job-applications-through-your-recruitment-agency-website"
      },
      "headline": "How to drive job applications through your recruitment agency website",
      "publisher": {
        "@type": "Organization",
        "@id": "https://www.madesimplemedia.co.uk/blog/how-to-drive-job-applications-through-your-recruitment-agency-website",
        "name": "Made Simple Media",
            "logo": {
            "@type": "ImageObject",
            "name": "myOrganizationLogo",
            "width": "236",
            "height": "40",
            "url": "/application/themes/website_by_madesimplemedia/images/logo.png"
        }
      },
      "image": "https://www.madesimplemedia.co.uk/application/files/cache/thumbnails/1a01f2369df5b722b948d175b5a2fd08.jpg",
      "author": [
        {"@type": "Person"
        ,"name": "David Reeder"
        ,"url": "https://www.madesimplemedia.co.uk/david-reeder"
        }
      ],
        "datePublished": "2023-05-09 14:43:09",
        "description": "The number of job vacancies is falling and the number of payrolled employees is increasing, according to official data.  The talent pool is drying up and it's hard for agencies to find great people for their clients jobs.  Users finding your jobs and applying is essential, so how do you maximise job applications through your website?",
        "dateModified": "2023-06-14 17:10:09"
      }
    </script>

    There is quite a lot there, so let's go through it a few lines at a time.

    Let's take a closer look at the markup

    All of our JSON Schema code needs to go in it's own JavaScript block, note the type attribute we are using:

    <script type="application/ld+json">
    ...
    </script>

    There's then a line to tell browsers/search engines that this is a block of schema markup.

    After this we have our @type to say that this is an Article.  This is an important one you can edit depending on what your page is about.  E.g. On products you would set this as Product.  See Supported Schema Types for a full list.  For our blog article we need to leave this set as Article:

    ...
    "@context": "http://schema.org",  
    "@type": "Article",
    ...
    

    The mainEntityOfPage section defines the main entity or part of the page.  For our blog it's quite simply about the topic we specify in the main heading and url.

    ...
    "mainEntityOfPage": {
        "@type": "WebPage",
        "@id": "https://www.madesimplemedia.co.uk/blog/how-to-drive-job-applications-through-your-recruitment-agency-website"
    },
    ...
    

    For the next part, we just add the title of our blog:

    ...
    "headline": "How to drive job applications through your recruitment agency website",
    ...
    

    Followed by Publisher details, which is the organisation or company writing the blog.  In this case it us, Made Simple Media. 

    We add our name and logo, complete with suggested dimensions:

    ...
    "publisher": {
        "@type": "Organization",
        "@id": "https://www.madesimplemedia.co.uk/blog/how-to-drive-job-applications-through-your-recruitment-agency-website",
        "name": "Made Simple Media",
            "logo": {
            "@type": "ImageObject",
            "name": "myOrganizationLogo",
            "width": "236",
            "height": "40",
            "url": "/application/themes/website_by_madesimplemedia/images/logo.png"
        }
    },
    ...
    

    Next we load the main image for this blog post:

      "image": "https://www.madesimplemedia.co.uk/application/files/cache/thumbnails/bd181f7020da238e9cb174165935659a.jpg",

    Followed by some Author information:

    "author": [
    	{"@type": "Person"
    	,"name": "David Reeder"
    	,"url": "https://www.madesimplemedia.co.uk/david-reeder"
    	}
      ],

    And some metadata type stuff to finish:

      "datePublished": "2023-08-29 13:21:44",
      "description": "Despite the remarkable progress we've seen in the business realm, women entrepreneurs continue to brave a distinct set of challenges. From battling for funding in a crowded arena to breaking through the stubborn barriers of societal bias, their journey is nothing short of extraordinary.",
      "dateModified": "2023-08-29 13:21:44"
      }

    It's pretty easy to copy and paste that from somewhere, but it needs to be dynamic and grab all the right values for that particular page before the page loads.

    This is where Concrete CMS attributes come in and we can load values with PHP.

    Added dynamic values with PHP

    Before we need to do anything, we'll populate some PHP variables with the values we need. 

    First we get the current page like this:

    <?php
        // For Rich Snippets
        $page = Page::getCurrentPage();

    Then we get our articles heading:

    $articleHeadline = $page->getCollectionName();
    

    Assign a variable to the Concrete CMS thumbnail helper here, then get a thumbnail of a certain size:

    $ih = Loader::helper('image');
    $thumbnail = $page->getAttribute('thumbnail');
    if($thumbnail) {
       $imageUrl = $ih->getThumbnail($page->getAttribute('thumbnail'), 800, 800, true)->src;
    }
    else {
       $imageUrl = "";
    }

    Next up, I have created an attribute called "Author" which means we can set a different author in the future for blog posts if we want to.  We can get it like this:

    $author = $page->getAttribute('author');

    In a similar way, we get the published date and description:

    $datePublished = $page->getCollectionDateAdded('Y-m-d');
    $description = $page->getCollectionDescription();

    Next we can get the date modified using the getVersionObject() and the pages URL:

    $vo = $c->getVersionObject();
    $dateModified = $vo->getVersionDateCreated();
    $url = $c->getCollectionLink();

    The final code

    We can then put it all together with a few extra functions to improve the rendered description.  E.g. if the description contains a double quote, it can break our code so we just remove it:

    <script type="application/ld+json">
    { 
      "@context": "http://schema.org",
      "@type": "Article",
      "mainEntityOfPage": {
        "@type": "WebPage",
        "@id": "<?php echo $url; ?>"
      },
      "headline": "<?php echo str_replace('"', '', $articleHeadline) ?>",
      "publisher": {
        "@type": "Organization",
        "@id": "<?php echo $url; ?>",
        "name": "<?php echo Config::get('concrete.site'); ?>",
            "logo": {
            "@type": "ImageObject",
            "name": "myOrganizationLogo",
             "width": "457",
            "height": "188",
            "url": "<?php echo $this->getThemePath()?>/images/MadeSimpleMedia-White.svg"
        }
      },
      "image": "<?php echo $imageUrl ?>",
      "author": [
        {"@type": "Person"
        ,"name": "David Reeder"
        ,"url": "https://www.madesimplemedia.co.uk/david-reeder"
        }
      ],
      "datePublished": "<?php echo $datePublished ?>",
      <?php if($description) { 
          $description = str_replace('"', "", $description);
          ?>
      "description": "<?php echo str_replace('"', '', $description) ?>",
      <?php } ?>
      <?php if($dateModified) { ?>
      "dateModified": "<?php echo $dateModified ?>"
      <?php } ?>
    }
    </script>
    

    Schema validator

    You can validate and check for errors in your schema code using the validator here:
    ​​​​​​​https://validator.schema.org/

    Adding the author page and schema markup

    You'll notice above we added an author with a link to another page on our site: https://www.madesimplemedia.co.uk/david-reeder

    The point of this page is to have information about the author.  This supports the article, showing who wrote it and their skills and experience that make them an authority on the subject.

    You will need to add a new page in Concrete CMS and may want to hide it from the main navigation.

    The page also needs schema markup as follows:

    <script id="schema-unified_1-0" type="application/ld+json">                
    [
        {
            "@context": "http://schema.org",
            "@type": ["ProfilePage"]
            ,"@id": "https://www.madesimplemedia.co.uk/david-reeder"
            ,"about": {
                "@type": "Person"
                ,"name": "David Reeder"
                ,"description": "David Reeder is a Director, Designer and Front-end Developer with over 15 years experience working on software, web and digital projects for SMEs, international companies, charities and start-ups."
                ,"url": "https://www.madesimplemedia.co.uk/david-reeder"
                ,"jobTitle": "Web Designer and Developer"
                ,"knowsAbout": ["HTML, CSS/less, JavaScript/jQuery, UI/UX Design, SEO, Business Development, Artificial Intelligance, Consumer Tech, Photography, Tech Culture"]
                ,"alumniOf": [
                    {
                        "@type": "Organization",
                        "Name": "Brooklands College"
                    }
                ]
            }
            ,"publisher": {
                "@type": "Organization",
                "name": "Made Simple Media Ltd",
                "url": "https://www.madesimplemedia.co.uk",
                "logo": {
                    "@type": "ImageObject",
                    "url": "https://www.madesimplemedia.co.uk/application/files/1416/3888/7741/madesimplemedia-mark-white.svg",
                    "width": 197,
                    "height": 125
                },
                "brand": "Made Simple Media"
                , "publishingPrinciples": "https://www.madesimplemedia.co.uk/publishing-principles"
                , "sameAs" : [
                    "https://www.facebook.com/pages/Made-Simple-Media/141012525936236",
                    "https://www.linkedin.com/company/made-simple-media?trk=cp_followed_name_made-simple-media",
                    "https://www.instagram.com/madesimplemedia/",
                    "https://twitter.com/madesimplemedia"
                ]
            }
        }
    ]</script>

    As you can see, the schema markup associates the author with the website's organisation, and adds more detail about their background, such as education and social media pages.

    In this case I didn't make the code dynamic this time with PHP variable because we just have one author, but there is nothing to stop you from doing so.  You could even base it on User Attributes that you add in the Dashboard for each user.

    Create a publishing principles page

    Our author page schema links to our publishing principles page that defines what content we accept in our blog. 

    If you accept blog posts from other authors this sets out the rules they must follow to ensure you maintain a high level of quality in your blog.

    These are our publishing principles.  

    Conclusion

    Google is ever-striving to understand and rank content appropriately to provide the best search results for users.  Schema markup is a great addition to your website, helping Google and users understand things more easily.

    The official site schema.org provides a database of all schema markup and frequently asked questions to help you work with it.  There is also a Getting Started section if you want to learn more about where this markup comes from.

    Who are we?

    We are a digital agency specialising in Web Design, Development, Concrete5 and digital marketing, based in London & West Sussex.

    We make digital simple. Our purpose is to simplify your frustrations in digital and solve the challenges you face to help make you more money and progressively grow your business or organisation.

    Tell me more

    Keep up to date

    Call us