Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal to add support for explicit identification of price categories such as sale price #2712

Closed
alex-jansen opened this issue Sep 17, 2020 · 11 comments · Fixed by #2716
Closed
Assignees

Comments

@alex-jansen
Copy link
Contributor

Context - This is a proposal from Google based on our experience consuming schema.org Offer markup and working with similar data from online merchants. If it were accepted, it would make it easier for us and others to understand the different prices related to an offer.

Introduction

Many products advertised and sold on the web have different categories of prices, for example:

  • invoice price,
  • list price,
  • sale price,
  • manufacturer-suggested retail price (MSRP)
  • minimum advertised price (MAP)
  • price by standardized weight or volume

Currently, schema.org does not provide a structured way of differentiating the categories of prices associated with an offer. The closest option is the /priceType property, but this field is intended to identify different price components, for example cleaning fee, service fee, downpayment, monthly installment payment, recycling fee, airport surcharge, etc. Several price components are combined together to make up a single price category.

See also issues #829 and more recently #2689 for a discussion on Compound pricing.

Proposal

We believe allowing an explicit and structured way of expressing the category of a /priceSpecification would benefit the ecosystem.

This design builds on the approach explored in #2689 which introduced an enumeration (e.g. /PriceTypeEnumeration) for the existing /priceType property. Alongside this we propose another enumeration (e.g., _/PriceCategoryEnumeration) _for different categories of prices, and a property /priceCategory to reference these. Example 2 below shows both of these dimensions being used in a single scenario.

New property /priceCategory would then be added to types /UnitPriceSpecification and /CompoundPriceSpecification to allow specification of a price category for singular prices as well as compound prices.

Example 1

The following example illustrates how to specify three different price categories (MSRP, list price, and sale price) for an offer using the proposed new enumeration

{
  "@context": "https://schema.org/",
  "@type": "Product",
  "sku": "coffeemaker-12345",
  "image": "https://www.example.com/coffeemaker.jpg",
  "name": "Coffee maker",
  "description": "Fast coffee maker, large",
  "gtin14": "12345678905678",
  "brand": {
    "@type": "Thing",
    "name": "SomeCoffeeBrand"
  },
  "offers": {
    "@type": "Offer",
    "url": "https://www.example.com/coffeemaker",
    "itemCondition": "https://schema.org/NewCondition",
    "availability": "https://schema.org/InStock",
    "priceSpecification": [
      {
          "@type": "UnitPriceSpecification",
          "priceCategory": "https://schema.org/MSRP",
          "price": 150.00,
          "priceCurrency": "EUR"
      },
      {
          "@type": "UnitPriceSpecification",
          "priceCategory": "https://schema.org/ListPrice",
          "price": 119.95,
          "priceCurrency": "EUR"
      },
      {
          "@type": "UnitPriceSpecification",
          "priceCategory": "https://schema.org/SalePrice",
          "price": 99.95,
          "priceCurrency": "EUR",
          "validFrom": "2020-10-01",
          "validThrough": "2020-10-14"
      }
      ]
    }
  }
}

Note that the sale price specification in this example has an explicit date range to indicate when the sale price is valid. Also note the absence of properties /price and /priceCurrency at the offer level.

Example 2

The following example, building on the example given in issue #2689, illustrates a combination of price categories and price types.

{
  "@context": "https://schema.org/",
  "@type": "Product",
  "sku": "GZDU23L/B",
  "image": "https://www.example.com/phone_5_32_slvr.jpg",
  "name": "Phone 5" 32GB Silver",
  "description": "New phone 5" screen in silver with 32GB + contract",
  "gtin14": "00821793049157",
  "mpn": "G-2PW4100-021-B",
  "brand": {
    "@type": "Thing",
    "name": "PhoneBrand"
  },
  "color": "Silver",
  "offers": {
    "@type": "Offer",
    "url": "http://www.example.com/GZDU23LB",
    "itemCondition": "https://schema.org/NewCondition",
    "availability": "https://schema.org/InStock",
    "priceSpecification": [
      {
        "@type": "CompoundPriceSpecification",
        "priceComponent": [
          {
            "@type": "UnitPriceSpecification",
            "priceType": "https://schema.org/Downpayment",
            "price": 215,
            "priceCurrency": "GBP"
          },
          {
            "@type": "UnitPriceSpecification",
            "priceType": "https://schema.org/Installment",
            "price": 38.65,
            "priceCurrency": "GBP",
            "billingIncrement": 1,
            "unitCode": "MON",
            "eligibleQuantity": {
              "@type": "QuantitativeValue",
              "value": 12,
              "unitCode": "MON"
            }
          },
          {
            "@type": "UnitPriceSpecification",
            "priceType": "https://schema.org/Subscription",
            "price": 15,
            "priceCurrency": "GBP",
            "billingIncrement": 1,
            "unitCode": "MON",
            "eligibleQuantity": {
              "@type": "QuantitativeValue",
              "minValue": 24,
              "unitCode": "MON"
            }
          }
        ]
      },
      {
        "@type": "CompoundPriceSpecification",
        "priceCategory": "https://schema.org/SalePrice",
        "validFrom": "2020-10-01",
        "validThrough": "2020-10-14",
        "priceComponent": [
          {
            "@type": "UnitPriceSpecification",
            "priceType": "https://schema.org/Downpayment",
            "price": 0,
            "priceCurrency": "GBP"
          },
          {
            "@type": "UnitPriceSpecification",
            "priceType": "https://schema.org/Installment",
            "price": 29.99,
            "priceCurrency": "GBP",
            "billingIncrement": 1,
            "unitCode": "MON",
            "eligibleQuantity": {
              "@type": "QuantitativeValue",
              "value": 12,
              "unitCode": "MON"
            }
          },
          {
            "@type": "UnitPriceSpecification",
            "priceType": "https://schema.org/Subscription",
            "price": 15,
            "priceCurrency": "GBP",
            "billingIncrement": 1,
            "unitCode": "MON",
            "eligibleQuantity": {
              "@type": "QuantitativeValue",
              "minValue": 24,
              "unitCode": "MON"
            }
          }
        ]
      }
    ]
  }
}

This example builds on the example in #2689 by adding a second compound sale price. The difference in this example between the default price (which comes without the /priceCategory property) and the sale price are the downpayment and installment price components. The subscription price component is unchanged.

Note that this example has modified the example in #2689 by moving the down payment under /CompoundPriceSpecification.

Consideration

Different price categories can be used under different circumstances, for example a product sold on the web could have a different sales price than a product advertised on the web. We could consider adding yet another pricing dimension to model how the price should be used, but this seems overkill and can instead be modeled by adding more enumeration values to the proposed /PriceCategoryEnumeration type.

@jvandriel
Copy link

jvandriel commented Sep 17, 2020

"Also note the absence of properties /price and /priceCurrency at the offer level."

In those cases where the /priceCurrency has the same value for all UnitPriceSpecifications wouldn't it suffice to specify it directly for the /Offer?

Seems a bit overkill to me having to specify the same value over and over again within a single /Offer.

@alex-jansen
Copy link
Contributor Author

@jvandriel Agreed that should be an option, since I would typically expect all prices to be in the same currency.

@jvandriel
Copy link

jvandriel commented Sep 17, 2020

In the comments for the second example it's mentioned that

"the default price (which comes without the /priceCategory property)"

yet in the first example https://schema.org/ListPrice has been specified as value for /priceCategory.

Aren't a /ListPrice and "default price" the same thing? And if so, shouldn't it be either one or the other (as in, you either specify /ListPrice OR you don't specify the /priceCategory property to set the standard price as opposed to both being an option)?

@alex-jansen
Copy link
Contributor Author

@jvandriel Yes, they are the same thing, I wanted to give both examples to start a discussion (I guess I succeeded :) ) on the pros and cons of absence of a /priceCategory implying that the price is the standard (or list) price, or always requiring the explicit specification of /priceCategory if there are multiple prices.

@jvandriel
Copy link

jvandriel commented Sep 17, 2020

Well if it's up for discussion... ;)

Although I like the the idea of using /ListPrice (mostly for debugging purposes during development), personally I feel it'd be best if we try to prevent having to specify it for every single /Offer. More or less the same way as was done by having http://purl.org/goodrelations/v1#Sell be the default value for /businessFunction (discussed in 2348 and #2357).

For example, I'd hate to have to write/publish the following:

{
  "@context":"https://schema.org",
  "@type": "Product",
  "sku": "GZDU23L\/B",
  "image": "https://www.example.com/phone_5_32_slvr.jpg",
  "name": "Phone 5\" 32GB Silver",
  "description": "New phone 5\" screen in silver with 32GB + contract",
  "gtin14": "00821793049157",
  "mpn": "G-2PW4100-021-B",
  "brand": {
    "@type": "Thing",
    "name": "PhoneBrand"
  },
  "color": "Silver",
  "offers": {
    "@type": "Offer",
    "url": "http://www.example.com/GZDU23LB",
    "itemCondition": "https://schema.org/NewCondition",
    "availability": "https://schema.org/InStock",
    "price": 999,
    "priceCurrency": "GBP",
    "priceSpecification": {
      "@type": "UnitPriceSpecification",
      "priceCategory": "https://schema.org/ListPrice"
    }
  }
}

@alex-jansen
Copy link
Contributor Author

@jvandriel Agreed that having a default value is the best option for the reason you indicated, it does not make much sense having to specify it when there is only one price.

@alex-jansen
Copy link
Contributor Author

alex-jansen commented Sep 23, 2020

After observing the usage and description of the existing /priceType property it appears it has the same role as the earlier proposed priceCategory, i.e., representing complete price specifications. We should therefore consider (instead of the original proposal) including /priceType also on /CompoundPriceSpecification and adding a new /PriceTypeEnumeration enumeration (instead of the earlier proposed /PriceCategoryEnumeration). The examples would then look as follows (building on the same changes proposed in #2869 as well):

Example 1

{
  "@context": "https://schema.org/",
  "@type": "Product",
  "sku": "coffeemaker-12345",
  "image": "https://www.example.com/coffeemaker.jpg",
  "name": "Coffee maker",
  "description": "Fast coffee maker, large",
  "gtin14": "12345678905678",
  "brand": {
    "@type": "Thing",
    "name": "SomeCoffeeBrand"
  },
  "offers": {
    "@type": "Offer",
    "url": "https://www.example.com/coffeemaker",
    "itemCondition": "https://schema.org/NewCondition",
    "availability": "https://schema.org/InStock",
    "priceCurrency": "EUR"
    "priceSpecification": [
      {
          "@type": "UnitPriceSpecification",
          "priceType": "https://schema.org/MSRP",
          "price": 150.00
      },
      {
          "@type": "UnitPriceSpecification",
          "priceType": "https://schema.org/ListPrice",
          "price": 119.95
      },
      {
          "@type": "UnitPriceSpecification",
          "priceType": "https://schema.org/SalePrice",
          "price": 99.95
          "validFrom": "2020-10-01",
          "validThrough": "2020-10-14"
      }
      ]
    }
  }
}

Example 2

{
  "@context": "https://schema.org/",
  "@type": "Product",
  "sku": "GZDU23L/B",
  "image": "https://www.example.com/phone_5_32_slvr.jpg",
  "name": "Phone 5 inch 32GB Silver",
  "description": "New phone 5 inch screen in silver with 32GB + contract",
  "gtin14": "00821793049157",
  "mpn": "G-2PW4100-021-B",
  "brand": {
    "@type": "Thing",
    "name": "PhoneBrand"
  },
  "color": "Silver",
  "offers": {
    "@type": "Offer",
    "url": "http://www.example.com/GZDU23LB",
    "itemCondition": "https://schema.org/NewCondition",
    "availability": "https://schema.org/InStock",
    "priceCurrency": "GBP",
    "priceSpecification": [
      {
        "@type": "CompoundPriceSpecification",
        "priceComponent": [
          {
            "@type": "UnitPriceSpecification",
            "priceComponentType": "https://schema.org/Downpayment",
            "price": 215
          },
          {
            "@type": "UnitPriceSpecification",
            "priceComponentType": "https://schema.org/Installment",
            "price": 38.65,
            "billingIncrement": 1,
            "unitCode": "MON",
            "eligibleQuantity": {
              "@type": "QuantitativeValue",
              "value": 12,
              "unitCode": "MON"
            }
          },
          {
            "@type": "UnitPriceSpecification",
            "priceComponentType": "https://schema.org/Subscription",
            "price": 15,
            "billingIncrement": 1,
            "unitCode": "MON",
            "eligibleQuantity": {
              "@type": "QuantitativeValue",
              "minValue": 24,
              "unitCode": "MON"
            }
          }
        ]
      },
      {
        "@type": "CompoundPriceSpecification",
        "priceType": "https://schema.org/SalePrice",
        "validFrom": "2020-10-01",
        "validThrough": "2020-10-14",
        "priceComponent": [
          {
            "@type": "UnitPriceSpecification",
            "priceComponentType": "https://schema.org/Downpayment",
            "price": 0
          },
          {
            "@type": "UnitPriceSpecification",
            "priceComponentType": "https://schema.org/Installment",
            "price": 29.99,
            "billingIncrement": 1,
            "unitCode": "MON",
            "eligibleQuantity": {
              "@type": "QuantitativeValue",
              "value": 12,
              "unitCode": "MON"
            }
          },
          {
            "@type": "UnitPriceSpecification",
            "priceComponentType": "https://schema.org/Subscription",
            "price": 15,
            "billingIncrement": 1,
            "unitCode": "MON",
            "eligibleQuantity": {
              "@type": "QuantitativeValue",
              "minValue": 24,
              "unitCode": "MON"
            }
          }
        ]
      }
    ]
  }
}

@alex-jansen alex-jansen linked a pull request Sep 23, 2020 that will close this issue
danbri pushed a commit that referenced this issue Oct 6, 2020
* first cut at #2689

* Revert "first cut at #2712"

This reverts commit d11143e.

* first cut at #2712 (now for real)

* Add support for structured priceType values (712)

* Fix syntax error

* move new rdfs:comment for priceType

* fix another syntax error
@mfhepp
Copy link
Contributor

mfhepp commented Oct 27, 2020

+1 I am fine with this

@jsmoriss
Copy link

jsmoriss commented Sep 26, 2022

Google recently added Merchant listings results to their Rich Results Test tool, and it appears to be throwing an incorrect error: Invalid value in field "priceSpecification"

For the following markup (from https://wpsso.com/extend/plugins/wpsso/), which seems to be related to the new priceType property.

 
                   "priceSpecification": {
                        "@context": "https://schema.org",
                        "@type": "UnitPriceSpecification",
                        "price": "69.00",
                        "priceCurrency": "USD",
                        "priceType": "https://schema.org/ListPrice",
                        "eligibleQuantity": {
                            "@context": "https://schema.org",
                            "@type": "QuantitativeValue",
                            "value": "1",
                            "minValue": "1",
                            "maxValue": "1",
                            "unitText": "WordPress Site Address URL Licenses"
                        }
                    },

The Schema validator and the Google search validator are both fine with this markup - is this a bug in the Google Merchant listings validator?

js.

@alex-jansen
Copy link
Contributor Author

HI JS, since this is a Google-specific question (and not about Schema.org in general) it might be best to ask this on the Google Search forum (https://support.google.com/websearch/thread/new)

@aimeos
Copy link

aimeos commented Oct 7, 2022

Google seems to only accept this ("itemtype" attribute instead of "content") when using metatags:

<meta itemprop="priceType" itemtype="http://schema.org/SalePrice">

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants