K2 supports Google Structured Data (GSD) since version 2.10.x (in the item view). However it does so for the most basic content types of GSD: article, news article & blog post
In the K2 component's Settings you'll notice that 6 more content types are listed there for product, event, video, course, movie and recipe. However these additional content types require data to be output that are not standard in K2, e.g. the start and end dates for an event. Usually K2 integrators will create these as extra fields and display them to one or more K2 categories.
If you've done that step already, then extending K2's GSD output to support additional content types is not hard.
Here are the steps to do so for the "event" content type...
0. Upgrade to K2 v2.10.3 (dev) from https://getk2.org/downloads/?f=K2_Development_Release.zip - this is required to be able to get the raw URL from a "link" type extra field. This step will not be necessary once K2 v2.10.3 is officially released.
1. Create an override for item.php to apply our GSD code for event content types. Copy the file /components/com_k2/templates/default/item.php into /templates/YOUR_TEMPLATE/html/com_k2/events/ (create the additional folders after /templates/YOUR_TEMPLATE/html/). This will only override the item view. If you want to override the category listing as well (for templating reasons), just copy all the files in /components/com_k2/templates/default/ into /templates/YOUR_TEMPLATE/html/com_k2/events/. More info on overriding K2 templates can be found here: https://getk2.org/documentation/tutorials/templating-with-k2-and-the-concepts-of-sub-templates
2. Create a new K2 Extra Fields Group and call it "Events".
3. Create a K2 Category and also call it "Events". Make sure that the new "events" sub-template (created on step 1) as well as the "Events" extra fields group (created on step 2) are both selected.
4. Now create extra fields in K2 for each of the GSD data you wish to add. According to https://developers.google.com/search/docs/data-types/event the bare minimum for a GSD event type are "location" (object), "name" (we can use the K2 item's title here), "startDate" and optionally "endDate" and "offers" (object). The GSD properties "description" and "image" already come with default K2 GSD. For any object element referenced, you'll have to create an extra field for each of its properties. So for "location" and given that GSD guidelines reference this:
"location": { "@type": "Place", "name": "Snickerpark Stadium", "address": { "@type": "PostalAddress", "streetAddress": "100 West Snickerpark Dr", "addressLocality": "Snickertown", "postalCode": "19019", "addressRegion": "PA", "addressCountry": "US" } }
...you would need to add the following ("text" type) extra fields:
- Location Name (with extra field alias 'e_loc_name')
- Location Address (with extra field alias 'e_loc_addr')
- Location Town/City (with extra field alias 'e_loc_city')
- Location Postal Code (with extra field alias 'e_loc_pc')
- Location State/Province (with extra field alias 'e_loc_state')
- Location Country (with extra field alias 'e_loc_country')
Additionally, for the rest of the fields
- Start Date ("date" type extra field and alias 'e_start_date')
- End Date ("date" type extra field and alias 'e_end_date')
- Ticket Price ("text" type extra field and alias 'e_ticket_price')
- Ticket Purchase URL ("link" type extra field and alias 'e_ticket_link')
Make sure the extra field "alias" is inserted exactly as stated in each line above (but without the quotes). This step is important as we will fetch each extra field separately by using this alias.
6. You will now fetch each of these extra fields separately (as described here as well https://getk2.org/documentation/tips-a-tricks/display-single-extra-fields-anywhere-in-your-k2-content) and build your new GSD properties.
Your default K2 GSD look like this: https://jmp.sh/gmcOnu3 (or just do a view source on https://getk2.org/blog/k2-v2102-released-now-with-a-100-mobile-friendly-backend-user-interface).
We will change and extend these using the following PHP code added in your item.php override, right after the "defined('_JEXEC') or die;" part:
// Get current GSD $getItemGSD = $this->params->get('itemGoogleStructuredData'); // Search and extend/replace GSD $document = JFactory::getDocument(); foreach ($document->_script as $type => $script) { if ($type == 'application/ld+json' && $script == $getItemGSD) { // Remove current GSD from the unset($document->_script['application/ld+json']); $itemGSD = json_decode($getItemGSD); // Remove any default K2 GSD properties we don't want for the GSD "event" content type unset($itemGSD->articleBody); unset($itemGSD->articleSection); unset($itemGSD->author); unset($itemGSD->dateModified); unset($itemGSD->datePublished); unset($itemGSD->headline); unset($itemGSD->keywords); unset($itemGSD->publisher); // Append new GSD data as object properties to '$itemGSD' $itemGSD->location = new stdClass; $itemGSD->location->{'@type'} = 'Place'; $itemGSD->location->name = $this->item->extraFields->e_loc_name->value; $itemGSD->location->address = new stdClass; $itemGSD->location->address->{'@type'} = 'PostalAddress'; $itemGSD->location->address->streetAddress = $this->item->extraFields->e_loc_addr->value; $itemGSD->location->address->addressLocality = $this->item->extraFields->e_loc_city->value; $itemGSD->location->address->postalCode = $this->item->extraFields->e_loc_pc->value; $itemGSD->location->address->addressRegion = $this->item->extraFields->e_loc_state->value; $itemGSD->location->address->addressCountry = $this->item->extraFields->e_loc_state->value; $itemGSD->name = $this->item->title; $itemGSD->startDate = $this->item->extraFields->e_start_date->value; $itemGSD->endDate = $this->item->extraFields->e_end_date->value; $itemGSD->offers = new stdClass; $itemGSD->offers->{'@type'} = 'Offer'; $itemGSD->offers->price = $this->item->extraFields->e_ticket_price->value; $itemGSD->offers->priceCurrency = 'USD'; // Use EUR or other currency here based on your needs $itemGSD->offers->url = $this->item->extraFields->e_ticket_link->rawValue; // Re-insert GSD data with new additions $itemGSD = json_encode($itemGSD, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); $document->addScriptDeclaration($itemGSD, 'application/ld+json'); } }
7. Now start filling up the event data in the K2 items' extra fields of yours "Events" category.
In the end you'll see something like this on each event K2 item's page source: https://jmp.sh/qUvDXud (wherever you see "null" is where I just didn't add data for these demo purposes).
8. Finally test one of your K2 items on: https://search.google.com/structured-data/testing-tool - this tool will tell you if you need to change anything or if some property is missing.
And you're ready!
The code above will work on all Joomla versions that K2 supports by default.