Add GTIN to WooCommerce Product Schema

In this WordPress & WooCommerce tutorial, we’re going to fix the “No global identifier provided (e.g. GTIN)” warning in Google Search Console. To do this, we need to be able to store the GTIN, GTIN12, GTIN13 (or whatever) against the WooCommerce product. Then we need to hook into WooCommerce when it creates the structured data (schema). We’re only going to cover Simple product types here. If there is demand, we’ll consider revising the tutorial to cover variable products too.

infoThis is very similar to our tutorial that adds Brand Name to a product’s schema. In fact, this tutorial works quite happily alongside it.

We’ll need to do three things here:

  1. Add some text input boxes in the back-end so we can edit GTIN, GTIN13, MPN, EAN13, etc. at product-level.
  2. Write some back-end code that captures these fields when the product is saved, then store these values in the product’s post_meta.
  3. Hook WooCommerce when it outputs the product schema and inject our fields into the structured data.

Scaffold the Code

To get things started, go in to your WordPress child theme, create a text file called “wpt-product-identifiers.php” and paste the following into it.

<?php

/**
 * WP Tutorials : Product identifiers GTIN13 EAN, ISBN (WPTPIDS)
 *
 * https://wp-tutorials.tech/refine-wordpress/add-gtin-to-product-schema/
 */

defined('WPINC') || die();

const WPTPID_META_PRODUCT_GTIN = 'product_gtin';
const WPTPID_META_PRODUCT_GTIN13 = 'product_gtin13';
const WPTPID_META_PRODUCT_MPN = 'product_mpn';

function wptpid_get_product_id_types() {
	global $wptpid_product_id_types;

	if (is_null($wptpid_product_id_types)) {
		$wptpid_product_id_types = array(
			WPTPID_META_PRODUCT_GTIN => array(
				'label' => 'GTIN',
				'description' => 'Global Trade Item Number',
				'schema_key' => 'gtin',
			),
			WPTPID_META_PRODUCT_GTIN13 => array(
				'label' => 'GTIN 13',
				'description' => 'Global Trade Item Number (13)',
				'schema_key' => 'gtin13',
			),
			WPTPID_META_PRODUCT_MPN => array(
				'label' => 'MPN',
				'description' => 'Manufacturer Part Number',
				'schema_key' => 'mpn',
			),
			// Add your own idintifiers in here...
			// ...
		);
	}

	return $wptpid_product_id_types;
}

/**
 * When editing a WooCommerce product, render HTML inputs fields for our
 * product identifiers.
 */
function wptpid_render_simple_product_unique_ids() {
	// Render the <input type="text" /> controls on the product page.
}
add_action('woocommerce_product_options_general_product_data', 'wptpid_render_simple_product_unique_ids');

/**
 * Hook into WooCommerce save product action, look for GTIN/etc in the $_POST
 * data and save it in the product's post meta.
 */
function wptpid_save_simple_product_unique_ids($product_id) {
	// Analyse the $_POST data and save GTIN, MPN, etc in the product's post meta.
}
add_action('woocommerce_process_product_meta', 'wptpid_save_simple_product_unique_ids', 10, 1);

/**
 * Add GTIN/etc to the product's schema (structured data).
 */
function wptid_add_unique_ids_to_product_schema($data) {
	// Adjust the product schema.

	return $data;
}
add_filter('woocommerce_structured_data_product', 'wptid_add_unique_ids_to_product_schema');

We’ve created a function called wptpid_get_product_id_types() that returns an array with all our info in it. This is so we can add new global product identifiers if we want to. For now, we’ll keep things simple.

Next, open your child theme’s functions.php and add the following couple of lines:

// WP Tutorials Product identifiers GTIN13 MPN, etc.
require_once dirname(__FILE__) . '/wpt-product-identifiers.php';

Edit and Save Product Settings

Let’s get product-editing sorted out first. This is what we’re aiming for when editing a simple product:

Edit the GTIN on a WooCommerce product
Edit the GTIN for a WooCommerce product

To render the input boxes, we need to grab the result from wptpid_get_product_id_types(), loop through the fields and call woocommerce_wp_text_input() to render each one. Paste the following into the wptpid_render_simple_product_unique_ids() function:

function wptpid_render_simple_product_unique_ids() {
	$unique_id_types = wptpid_get_product_id_types();

	if (empty($product = wc_get_product())) {
		// ...
	} elseif ($product->is_type('variable')) {
		// Variable products work differently.
	} else {
		echo '<div class="options_group">';
		foreach ($unique_id_types as $field_name => $meta) {
			woocommerce_wp_text_input(
				array(
					'id' => $field_name,
					'label' => $meta['label'],
					'description' => $meta['description'],
					'desc_tip' => true,
					'default' => '',
				)
			);
		}
		echo '</div>'; // .options_group
	}
}

There’s nothing magic in here. All we do is verify that we can get a handle to the current WooComemrce product, and it’s not a variable product. Then we just loop through our custom fields.

Next, paste the following into wptpid_save_simple_product_unique_ids() to capture and save the product’s meta data when we save a product:

function wptpid_save_simple_product_unique_ids($product_id) {
	$unique_id_types = wptpid_get_product_id_types();

	foreach ($unique_id_types as $field_name => $meta) {
		$field_value = array_key_exists($field_name, $_POST) ? sanitize_text_field($_POST[$field_name]) : '';

		if (!empty($field_value)) {
			update_post_meta($product_id, $field_name, $field_value);
		} else {
			delete_post_meta($product_id, $field_name);
		}
	}
}

Save all your changes to “wpt-product-identifiers.php” and edit a product to check that the fields are displayed.

Hook the Product Schema

According to the Product schema specification, we need to add the new fields to the structured data like this:

{
	"@context": "https://schema.org/",
	"@type": "Product",
	...
	...
	...
	"gtin": "AAAABBBBCCCC",
	"gtin13": "aaaabbbbcccc",
	"mpn": "000011112222"
}

So all we need to do is loop through the fields from wptpid_get_product_id_types() again and use get_post_meta( $product_id, $field_name, true ) to grab the GTIN/MPN and add it to the schema array.

Paste the following into the wptid_add_unique_ids_to_product_schema() function:

function wptid_add_unique_ids_to_product_schema($data) {
	if (!is_array($data)) {
		// If $data isn't an array, don't do anything.
	} elseif (empty($product = wc_get_product())) {
		// Don't do anything.
	} elseif ($product->is_type('variable')) {
		// Variable products work differently.
	} else {
		$product_id = $product->get_id();
		$unique_id_types = wptpid_get_product_id_types();
		foreach ($unique_id_types as $field_name => $meta) {
			$field_value = strval(get_post_meta($product_id, $field_name, true));
			$schema_key = $meta['schema_key'];

			if (!empty($field_value)) {
				$data[$schema_key] = $field_value;
			}
		}
	}

	return $data;
}

Deploy and Test

That’s about it – now we just need to test it.

infoIf you’re using a page caching plugin on your site, flush your page cache before testing changes.

Go to the Schema Structured Data Testing Tool and run a test against your product’s URL. When you expand the Product section, you should see something like this (with more sensible data, of course):

GTIN, GTIN13 and MPN in a WooCommerce product schema
GTIN and MPN in a WooCommerce product schema

When you’re happy with how your product schema looks, prompt Google Search Console to re-index your page(s) and your warning should be fixed in a few days ๐Ÿ˜Ž๐Ÿ‘

Like This Tutorial?

loading

Let us know

5 thoughts on “Add GTIN to WooCommerce Product Schema”

  1. Avatar

    Your stuff is trully useful and incredible. Still waiting for tooltip glossary like popup on words!

    Popper.js (boostrap tooltip style) or floating-ui would be awesome!

    Many thanksโ˜บ๏ธ

    1. Avatar

      Cheers!

      Popper.js looks quite fun.

      I guess… using a Custom Post Type to build the glossary, then doing some analysis in JavaScript to split the rendered paragraphs into words and compare them against an array of glossary-terms… yes. I think it could be a neat tutorial without too much work. I wonder if we could add some SEO value too? I’ll have a think.

      Watch this space…

      1. Avatar

        Oh yeah.. ๐Ÿ˜Ž
        Fyi: Popper is included into boostrap, and btw its powering 80% of Microsoft teams. Just incredible how a js library can hold an entire software.. Waiting for your goldweight tutorial!

Leave a Comment

Your email address will not be published.