Missing field "hasMerchantReturnPolicy" and "shippingDetails" in WooCommerce: what they mean and three fixes
Both are recommended properties of a merchant listing, not required ones, so the product stays valid. WooCommerce prints neither. Settle them with shipping and return settings in Search Console or Merchant Center, with markup added through a WooCommerce filter, or with an extension.
- By
- WP Ministry
- Published
- Tested on
- WordPress 7.1.3, WooCommerce 11.2.0, PHP 8.3.35
In short
- Google lists hasMerchantReturnPolicy and shippingDetails as recommended for a merchant listing. What it requires is a name, an image and an offer with a price and a currency.
- Search Console calls an issue of this kind non-critical. The item stays valid and can still appear as a rich result.
- WooCommerce's product markup contains neither property, so every product with a price gets both notices at once.
- Shipping and return settings in Search Console need no code, and Google uses them ahead of any markup on the page.
- The filter woocommerce_structured_data_product_offer adds both properties to each product's offer from one small file.
- State only the policy the store really has. The values in every example on this page are stand-ins to replace.
A notice in Search Console that the field hasMerchantReturnPolicy or shippingDetails is missing does not mean a product is broken. Google's documentation for merchant listings lists both properties as recommended, not required, so the product is still a valid item and can still be shown. The notice says that Google has not been told, in the page's markup, what the store's return policy and shipping terms are.
WooCommerce's own product markup contains neither property, which is why a store sees both notices on every product at once. There are three ways to settle them: enter shipping and return settings in Search Console or Merchant Center, add the two properties to the markup, or use an extension that does one of those for you.
What the two notices say
Search Console's help lists the common messages of its rich result reports. One has the form Missing field "property name", and the advice beside it is to add the property. This page is about that message with two names in it, in the Merchant listings report, which Search Console keeps under Shopping.
| Property | What it describes | Where Google's documentation puts it |
|---|---|---|
hasMerchantReturnPolicy | Whether a product can be returned, within how many days, how, and at what cost | In the product's offer, or once for the whole business under Organization |
shippingDetails | What shipping costs, where the store ships to, and how long delivery takes | In the product's offer |
Required or recommended
Google's page on merchant listing structured data separates the two. These are its lists for a product and for the offer inside it.
| Required | Recommended | |
|---|---|---|
Product | name, image, offers | aggregateRating, brand.name, description, a GTIN, sku and others |
Offer | price and priceCurrency, given directly or inside priceSpecification | availability, hasMerchantReturnPolicy, itemCondition, priceValidUntil, shippingDetails, url, validFrom, validThrough |
Both properties are in the recommended column. Of shipping, the same page says outright that OfferShippingDetails is not required.
What a missing recommended property costs
Google's page gives the difference in one line each. Required properties are what make a page eligible to be shown as a rich result. Recommended properties add information, which the page says could give people a better experience. Its general guidelines add that an item missing a required property is not eligible for rich results, and that the more recommended properties are provided, the higher the quality of the result is to users.
For these two properties the page is specific about what is at stake. The return properties are what make a listing eligible to show return policy information, such as the return window and the fees. The shipping properties are what make it eligible for what Google calls the shipping details enhancement: shipping cost and an estimated delivery time. So the cost of leaving them out is that part of the listing, and only when Google has no other source for it. The settings described below are another source.
How Search Console labels the two kinds of issue
Search Console's help uses two terms.
- A critical issue makes an item invalid. An invalid item cannot appear as a rich result. The report lists these in a table named "Why items are invalid".
- A non-critical issue leaves the item valid. The report lists these in a table named "Improve item appearance".
The help page for the Rich Results Test speaks of errors and warnings. Google's 2023 announcement of shipping and return information in search results says that a product without it gets "warnings in the Merchant Listings report", and a notice by email.
So look at which table your notice is in. A recommended property belongs to the second. If a product is listed in "Why items are invalid", something else is at fault, such as a required property, and that is a different job. What WooCommerce outputs for a product and how to fill the gaps covers those.
What WooCommerce prints for a product's offer
WooCommerce writes a product's structured data as JSON-LD near the end of the product page. This is the offer it printed for a simple product priced at 120.00 on WooCommerce 11.2.0 with no other plugin active. The store's name and address are swapped for examples, and line breaks are added.
{
"@type": "Offer",
"priceSpecification": [
{
"@type": "UnitPriceSpecification",
"price": "120.00",
"priceCurrency": "USD",
"validThrough": "2027-12-31"
}
],
"priceValidUntil": "2027-12-31",
"availability": "https://schema.org/InStock",
"url": "https://example.com/product/example-product/",
"seller": {
"@type": "Organization",
"name": "Example Store",
"url": "https://example.com"
},
"price": "120.00",
"priceCurrency": "USD"
}That is the whole offer: a price, a currency, a date the price is valid until, the stock status, the product's address and the store as seller. The date is WooCommerce's own assumption, the last day of next year, unless the product is on sale with an end date. It has no hasMerchantReturnPolicy and no shippingDetails, and nothing in WooCommerce's settings adds them:
- A shipping zone does not reach the markup. With a flat rate set for a zone under WooCommerce > Settings > Shipping, the offer was the same.
- The refund and returns page does not either. WooCommerce creates that page as a draft. Published, it carried no structured data at all, and the product's offer was unchanged.
The file that builds this markup in WooCommerce 11.2.0 does not contain either property's name. The development version of the same file, which is not in a release yet, adds OnlineStore data to the published refund and returns page with a hasMerchantReturnPolicy that holds a link to that page and nothing else. Its code comment marks it for 11.3.0, and it adds nothing to a product's offer.
To see what your own store prints, ask for a product page and look for the two names. Put a real product's address in place of the example.
curl -s https://example.com/product/example-product/ | grep -o -E '"(hasMerchantReturnPolicy|shippingDetails)":' | sort -uOn a store that prints neither, the command prints nothing.
A variable product whose variations differ in price gets an AggregateOffer with a lowest and a highest price in place of an Offer. Google's page says a merchant listing requires an Offer, so that product has a different matter to settle first. The page on how WooCommerce variations look to a search engine covers it.
Three ways to settle them
| Way | Where the policy is kept | What it takes |
|---|---|---|
| Settings in Search Console or Merchant Center | In your Google account | No code. Access to the Search Console property as an owner or a full user |
| Markup | In the store's pages | One PHP file, shown below |
| An extension | Depends on the extension | Reading its documentation to learn which of the first two it does |
The ways can be combined, and Google says which it believes when they are. Its merchant listing page gives this order for shipping and return policies defined in more than one place, from strongest to weakest:
- Product-level feeds submitted in Merchant Center
- Settings in the Content API for Shopping
- Settings in Merchant Center or Search Console
- Product-level merchant listing markup
- Organization-level markup
Google's page on return policy markup gives the plain case: if a site has return policy markup and return policy settings in Search Console, Google uses only what is in Search Console. So whichever ways you use, they have to say the same thing, and a setting made in a Google account outranks anything written into the page.
The way that needs no code: settings in Search Console or Merchant Center
Search Console
Google's help page for the setting says it is under Settings > Shopping > Shipping and returns. It takes a simplified version of the store's policy: delivery time, shipping cost, return window and return cost.
- Who sees it. Google shows the setting to sites it has identified as online merchants, and only to an owner or a full user of the property. The help page says a Merchant Center account is not needed. If the store already has one, it has to be associated with the Search Console property first.
- A shipping policy. On the Shipping tab, "Add shipping policy" asks for the country, a minimum and a maximum number of days for delivery, and the cost: a flat rate, free over a certain amount, free, or other. Repeat it for each country the store ships to.
- A return policy. On the Returns tab, "Add return policy" asks for the country, the address of the page where customers can read the policy, the return window in days or no returns, and the cost of a return: a flat rate, free, or a percentage of the product's price.
- How long it takes. The help page says shipping details are approved automatically, and that a return policy is verified by hand, which can take about 10 to 13 days. Until then it is marked as pending.
The return policy needs a page on the store that states the policy. WooCommerce's refund and returns page is a draft until someone writes it and publishes it.
Merchant Center
A store with a Merchant Center account can make the same settings there, with more options. Google's help says to go to "Shipping and returns" under "Products & store" in the left menu, and to use the "Return policies" tab or the "Shipping policies" tab. It says Google verifies a return policy before using it, and shows the result in a status column. A policy made in Search Console is added to Merchant Center automatically. A policy made or edited in Merchant Center can only be managed there.
What Google does not say
Google's pages say these settings are used, and that they come ahead of markup. None of them says that the Merchant listings report then stops listing the property as missing from the page's markup. The report describes the structured data Google found on the page, and settings do not change the page. If the notice stays after a policy is approved, check the policy's status on the settings screen before deciding that anything failed.
The way with markup
Google's documentation describes two places for a return policy, and recommends the first.
Once for the whole business
A standard return policy that applies to most or all products goes under Organization markup, or its more specific type OnlineStore, on one page. Google recommends the page that describes the return policy and says it does not need to be on every page.
{
"@context": "https://schema.org",
"@type": "OnlineStore",
"name": "Example Store",
"url": "https://example.com",
"hasMerchantReturnPolicy": {
"@type": "MerchantReturnPolicy",
"applicableCountry": "US",
"returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
"merchantReturnDays": 30,
"returnMethod": "https://schema.org/ReturnByMail",
"returnFees": "https://schema.org/FreeReturn"
}
}A business-wide shipping policy has a property of its own, hasShippingService, which Google documents on its page for merchant shipping policy markup. It is not the shippingDetails the notice names.
On each product's offer
Google's page says to put a policy on the offer when a product's terms differ from the standard ones, or when the business provides no standard policy. This is also the place the notice names, so it is the one the WooCommerce filter below writes to.
{
"@type": "Offer",
"price": "120.00",
"priceCurrency": "USD",
"hasMerchantReturnPolicy": {
"@type": "MerchantReturnPolicy",
"applicableCountry": "US",
"returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
"merchantReturnDays": 30,
"returnMethod": "https://schema.org/ReturnByMail",
"returnFees": "https://schema.org/FreeReturn"
},
"shippingDetails": {
"@type": "OfferShippingDetails",
"shippingRate": {
"@type": "MonetaryAmount",
"value": "5.00",
"currency": "USD"
},
"shippingDestination": {
"@type": "DefinedRegion",
"addressCountry": "US"
},
"deliveryTime": {
"@type": "ShippingDeliveryTime",
"handlingTime": {
"@type": "QuantitativeValue",
"minValue": 0,
"maxValue": 1,
"unitCode": "DAY"
},
"transitTime": {
"@type": "QuantitativeValue",
"minValue": 2,
"maxValue": 5,
"unitCode": "DAY"
}
}
}
}Where both exist, Google's page says it defaults to the product-level return policy.
What each type requires
Once a property is present, Google checks what is inside it. These are the properties its pages list as required for each type.
| Type | Required by Google | Notes from the same pages |
|---|---|---|
MerchantReturnPolicy on an offer | applicableCountry, returnPolicyCategory | merchantReturnDays is required when the category is MerchantReturnFiniteReturnWindow. The country is a two-letter ISO 3166-1 code, and up to 50 can be given |
MerchantReturnPolicy under Organization | Either applicableCountry and returnPolicyCategory, or merchantReturnLink alone | merchantReturnLink is the address of the page that describes the policy. It is not among the properties listed for an offer |
OfferShippingDetails | deliveryTime, shippingDestination, shippingRate | The rate needs currency and either value or maxValue. The currency must be the offer's own. A value of 0 means free shipping |
DefinedRegion, inside shippingDestination | addressCountry | A two-letter ISO 3166-1 code |
QuantitativeValue, inside handlingTime and transitTime | minValue, maxValue, unitCode | Whole days, with a unit of DAY or d |
returnFees and returnMethod are recommended. A store that takes no returns states that too: returnPolicyCategory has the value https://schema.org/MerchantReturnNotPermitted for it, and then no number of days is needed.
Add both properties in WooCommerce
WooCommerce passes each product's offer through a filter, woocommerce_structured_data_product_offer, before printing it. The filter hands over the offer as an array and the product it belongs to. A function attached to it can add the two properties to every product in one place.
The smallest place for that function is a must-use plugin: a single PHP file in wp-content/mu-plugins/ that WordPress loads on every request, with nothing to activate.
Step 1: Create the mu-plugins folder if it is not there
Look in
wp-content. If there is no folder namedmu-plugins, create one. A fresh WordPress does not have it.Step 2: Add the file
Save this as
offer-policies.phpin that folder. A mistake in a PHP file can stop the site from loading, so copy it exactly and keep SFTP or the host's file manager open. If the site shows a critical error afterwards, delete the file and the site comes back.wp-content/mu-plugins/offer-policies.php<?php /** * Plugin Name: Product offer policies * Description: Adds this store's return policy and shipping details to the structured data of each product's offer. */ add_filter( 'woocommerce_structured_data_product_offer', function ( $offer, $product ) { // A price range (AggregateOffer) is left as WooCommerce wrote it. if ( ! is_array( $offer ) || 'Offer' !== ( $offer['@type'] ?? '' ) ) { return $offer; } $offer['hasMerchantReturnPolicy'] = array( '@type' => 'MerchantReturnPolicy', 'applicableCountry' => 'US', 'returnPolicyCategory' => 'https://schema.org/MerchantReturnFiniteReturnWindow', 'merchantReturnDays' => 30, 'returnMethod' => 'https://schema.org/ReturnByMail', 'returnFees' => 'https://schema.org/FreeReturn', ); // Shipping is stated only for a product that is shipped. if ( $product instanceof WC_Product && $product->needs_shipping() ) { $offer['shippingDetails'] = array( '@type' => 'OfferShippingDetails', 'shippingRate' => array( '@type' => 'MonetaryAmount', 'value' => '5.00', 'currency' => get_woocommerce_currency(), ), 'shippingDestination' => array( '@type' => 'DefinedRegion', 'addressCountry' => 'US', ), 'deliveryTime' => array( '@type' => 'ShippingDeliveryTime', 'handlingTime' => array( '@type' => 'QuantitativeValue', 'minValue' => 0, 'maxValue' => 1, 'unitCode' => 'DAY', ), 'transitTime' => array( '@type' => 'QuantitativeValue', 'minValue' => 2, 'maxValue' => 5, 'unitCode' => 'DAY', ), ), ); } return $offer; }, 10, 2 );Step 3: Change the values to your store's
Line What it tells Google Put in its place applicableCountry,addressCountryThe country the policy applies to and the country the store ships to Your country's two-letter code returnPolicyCategory,merchantReturnDaysReturns are accepted for 30 days after delivery Your window in days, or MerchantReturnNotPermittedwith the days line removedreturnMethodReturns go back by mail ReturnInStoreorReturnAtKioskif that is how yours workreturnFeesReturning a product costs the customer nothing ReturnFeesCustomerResponsibilityif the customer arranges and pays for the returnshippingRateShipping costs 5.00 in the store's currency The rate checkout charges, or 0for free shippinghandlingTime,transitTimeUp to 1 day to dispatch, then 2 to 5 days in transit Your own shortest and longest, in whole days Each of those values is one Google's pages list for the property. A fee the store charges for a return has a third
returnFeesvalue with an amount beside it, and Google's page shows how to write it.Step 4: Read the product page again
Clear any page cache, then run the command from earlier on this page against a product's address. It now prints both names.
text"hasMerchantReturnPolicy": "shippingDetails":
What the file does to each kind of product on WooCommerce 11.2.0:
- A simple product that is shipped gets both properties, with the values exactly as written in the file.
- A virtual product gets the return policy and no
shippingDetails. The file asks WooCommerce whether the product needs shipping, and WooCommerce answers no for a virtual product. - A variable product with a price range gets neither, because its offer is an
AggregateOfferand the file leaves that alone.
The file reads the currency from the store's settings, so the shipping rate is always in the currency of the price, which Google requires. The file shows on the Plugins screen under "Must-Use" and cannot be switched off there. With WooCommerce deactivated it does nothing and the site loads as before. To undo the change, delete the file.
One file states one policy for the whole store. If a few products ship or return on other terms, the function has the product in hand and can decide by it, and that is work for a developer. WP Ministry's WordPress SEO audit covers WooCommerce stores, and the fixes on the WordPress side are part of the job, up to the hours it includes.
The way with an extension
An extension settles the notices in one of the two ways above, and its documentation says which. Read it for two things before installing anything: whether it sends shipping and return settings to a Google account or writes properties into the page, and which properties those are.
Google for WooCommerce, the extension that connects a store to Merchant Center, is of the first kind for shipping. Its documentation says it can sync shipping rates from WooCommerce's Flat Rate method to Merchant Center, and offers a choice under Marketing > Google for WooCommerce > Settings > Shipping rates between syncing from WooCommerce and setting shipping up in Merchant Center. The pages of its documentation read for this article do not mention a return policy, so plan to enter that in Merchant Center or Search Console yourself.
An extension that writes structured data is of the second kind. After setting it up, run the command above on a product page. If a property's name is not printed, the extension is not putting it in the page, whatever its settings screen shows.
Check the result
Read the page. The command above shows what a crawler receives. Run it on two or three products of different kinds, not one.
Test one page with Google's tool. Open the Rich Results Test and give it the full address of a product page. Google's help says the test lists the rich result types it found, with any errors or warnings under each item, and that the page must be reachable by an anonymous visitor. It reports a status such as "N valid item(s) detected" or "N valid item(s) with warnings detected". Open the merchant listing item and look at whether the two names are still among its warnings.
Ask Search Console to validate. Open the issue in the Merchant listings report. Google's help says "Validate fix" on the issue's details page starts a check of a sample of pages first, then the rest, and that validation can take two weeks or more depending on how often the site is crawled. It also says Google may notice a fix during ordinary crawling without validation being started. Nobody outside Google sets that date.
Check a setting where it was made. A policy entered in Search Console or Merchant Center shows its own status on the screen it was entered on.
What not to do
- Do not state a policy the store does not offer. Google's general structured data guidelines say markup "must be a true representation of the page content", and tell sites not to use structured data to deceive or mislead users. A 30-day free return written into the markup to clear a notice is a statement to every shopper who sees it.
- Do not mark up what a visitor cannot read. The same guidelines say not to mark up content that is not visible to readers of the page. Publish the return policy and the shipping terms on the store, where a customer can find them without logging in.
- Do not let the markup and checkout disagree. Google's help for the Search Console setting says to check that the shipping cost given to Google matches the one on the website exactly, and that a listing might be rejected if Google finds a lower cost on the listing than on the site.
- Do not paste the examples unchanged. They are stand-ins.
- Do not treat the notice as an emergency. The item is valid while it is listed. A wrong policy published in a hurry does more harm than a recommended property left empty for a week.
Missing brand and a missing GTIN are notices of the same kind in the same report. They have a page of their own: the brand and GTIN notices on a WooCommerce store.
Common questions
Do these notices stop my products from appearing on Google?
No. Both properties are recommended, and Search Console's help says an item with only non-critical issues is valid and can appear as a rich result. What the properties add is eligibility for return and shipping information in the listing. Whether any rich result is shown remains Google's decision.
Should I use the settings or the markup?
It depends on the store. One policy for every product is the least to maintain as a setting, and Google uses a setting ahead of markup. A policy that differs by product needs markup on the offer, or product data in Merchant Center. If you use more than one way, make them say the same thing.
Will the notice go away once I add a policy in Search Console?
Google's documentation does not say. It says settings are used and take precedence over markup. The report lists what is in the page's markup, and a setting does not change the page. What changes the report's reading is the markup, so add the property there as well, with the same terms, if the notice itself matters to you.
My store does not accept returns. What do I put?
State that. returnPolicyCategory has a value for it, https://schema.org/MerchantReturnNotPermitted, and merchantReturnDays is then left out. In Search Console the return window offers "no returns" as a choice.
Do digital products need shippingDetails?
There is nothing to ship, so there is nothing true to put in it. The file on this page leaves the property off a virtual product. It is a recommended property, so the product stays valid without it.
Why does every product have the notice?
Because the markup comes from one template. WooCommerce builds every product's offer with the same code, and that code adds neither property. Google's help makes the same point about fixing: if an issue comes from a template, fixing the template resolves it on every page that uses it.
- ResourceWooCommerce checkout is down: a runbook
- Cost guideWooCommerce maintenance cost: why a store costs more, and what the extra should buy
- ResourceWooCommerce sale readiness checklist: Black Friday or any big sale
- Error fixHow to fix WooCommerce payment gateway errors
- Error fixHow to fix a WooCommerce checkout that is not working
- GuideWooCommerce category page SEO: what a product category tells Google, its pagination and its address

