https://github.com/public-law/schema-dot-org
Easy structured data for websites. All validated for syntax and semantics. Simple declarative-style coding.
https://github.com/public-law/schema-dot-org
google-crawler json-ld rails ruby schema-org seo structured-data validations
Last synced: 3 months ago
JSON representation
Easy structured data for websites. All validated for syntax and semantics. Simple declarative-style coding.
- Host: GitHub
- URL: https://github.com/public-law/schema-dot-org
- Owner: public-law
- License: mit
- Created: 2018-02-13T02:57:23.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2025-06-09T02:43:48.000Z (8 months ago)
- Last Synced: 2025-06-17T10:59:38.897Z (8 months ago)
- Topics: google-crawler, json-ld, rails, ruby, schema-org, seo, structured-data, validations
- Language: Ruby
- Homepage: https://rubygems.org/gems/schema_dot_org
- Size: 289 KB
- Stars: 65
- Watchers: 7
- Forks: 33
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
## Table of Contents
- [SchemaDotOrg](#schemadotorg)
- [Usage](#usage)
- [Principle: No silent failures](#principle-no-silent-failures)
- [You are prevented from creating invalid markup](#you-are-prevented-from-creating-invalid-markup)
- [Supported Schema.org Types](#supported-schemaorg-types)
- [Examples](#examples)
- [BreadcrumbList](#breadcrumblist)
- [WebSite](#website)
- [Installation](#installation)
- [Development](#development)
- [Contributing](#contributing)
- [License](#license)
# SchemaDotOrg
Easily create [Structured Data](https://developers.google.com/search/docs/guides/intro-structured-data) with **correct syntax and semantics**.
Good structured data [helps enhance a website's search result appearance](https://developers.google.com/search/docs/guides/enhance-site):
> "Google Search works hard to understand the content of a page. You can help us by providing explicit clues about the meaning of a page…"
## Usage
Let's say you have a Rails app. First write plain-ruby code in a helper or controller.
Here's what that'd look like in a controller. Instantiate
the structured data object you want in your web page:
```ruby
@my_org = Organization.new(
name: 'Public.Law',
founder: Person.new(name: 'Robb Shecter'),
founding_date: Date.new(2009, 3, 6),
founding_location: Place.new(address: 'Portland, OR'),
email: 'support@public.law',
telephone: '+1 123 456 7890',
url: 'https://www.public.law',
logo: 'https://www.public.law/favicon-196x196.png',
same_as: [
'https://twitter.com/law_is_code',
'https://www.facebook.com/PublicDotLaw'
]
)
```
...and then output it in a template:
```html
<%= @my_org %>
```
...you'll get this perfectly formatted structured data in your HTML:
```html
{
"@context": "http://schema.org",
"@type": "Organization",
"name": "Public.Law",
"email": "support@public.law",
"telephone": "+1 123 456 7890",
"url": "https://www.public.law",
"logo": "https://www.public.law/favicon-196x196.png",
"foundingDate": "2009-03-06",
"founder": {
"@type": "Person",
"name": "Robb Shecter"
},
"foundingLocation": {
"@type": "Place",
"address": "Portland, OR"
},
"sameAs": [
"https://twitter.com/law_is_code",
"https://www.facebook.com/PublicDotLaw"
]
}
```
### Principle: No silent failures
We coded the library this way because the data is embedded in the HTML - and it's a
pain in the butt to manually check for errors. In my case, I manage 500,000 unique
pages in my Rails app. There's _no way_ I could place error-free structured data in
them without automatic validation.
`SchemaDotOrg` will validate your Ruby code, and if it's correct, will generate Schema.org JSON-LD markup when `#to_s`
is called. If you, e.g., didn't add the correct attributes, you'll get a descriptive error message pointing
you to the problem.
Notice how the `foundingDate` is in the required ISO-8601 format. In the same way, the `foundingLocation` is a `Place`
which adds the proper `@type` attribute. All Ruby snake-case names have been converted to the Schema.org standard camel-case.
Etc., etc.
### You are prevented from creating invalid markup
I make mistakes. So I wanted to know that if my page loads, the markup is good. I hate "silent failures".
If you use the wrong type or try to set an unknown attribute, SchemaDotOrg will
refuse to create the incorrect JSON-LD. Instead, you'll get a message explaining
the problem:
```ruby
Place.new(address: 12345)
# => ArgumentError: Address is class Integer, not String
Place.new(
address: '12345 Happy Street',
author: 'Hemmingway'
)
# => NoMethodError: undefined method `author'
```
In my experience, I never get errors from the lib. I code it once, it works, and then
I move on to other things.
> [!NOTE]
> This automatic validation comes from my [ValidatedObject gem](https://github.com/public-law/validated_object), which in turn,
> is a thin wrapper around ActiveRecord::Validations. So there's nothing magical going on here.
## Supported Schema.org Types
See each type's RSpec for an example of how to use it.
| Name | Schema.org Page | RSpec Spec | Source Code |
| ---------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| AggregateOffer | [Schema.org](https://schema.org/AggregateOffer) | | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/aggregate_offer.rb) |
| BreadcrumbList | [Schema.org](https://schema.org/BreadcrumbList) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/breadcrumb_list_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/breadcrumb_list.rb) |
| CollegeOrUniversity | [Schema.org](https://schema.org/CollegeOrUniversity) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/college_or_university_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/college_or_university.rb) |
| Comment | [Schema.org](https://schema.org/Comment) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/comment_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/comment.rb) |
| ContactPoint | [Schema.org](https://schema.org/ContactPoint) | | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/contact_point.rb) |
| DiscussionForumPosting | [Schema.org](https://schema.org/DiscussionForumPosting) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/discussion_forum_posting_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/discussion_forum_posting.rb) |
| InteractionCounter | [Schema.org](https://schema.org/InteractionCounter) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/interaction_counter_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/interaction_counter.rb) |
| ItemList | [Schema.org](https://schema.org/ItemList) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/item_list_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/item_list.rb) |
| Language | [Schema.org](https://schema.org/Language) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/language_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/language.rb) |
| ListItem | [Schema.org](https://schema.org/ListItem) | | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/list_item.rb) |
| Offer | [Schema.org](https://schema.org/Offer) | | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/offer.rb) |
| Organization | [Schema.org](https://schema.org/Organization) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/organization_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/organization.rb) |
| Person | [Schema.org](https://schema.org/Person) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/person_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/person.rb) |
| Place | [Schema.org](https://schema.org/Place) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/place_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/place.rb) |
| PostalAddress | [Schema.org](https://schema.org/PostalAddress) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/postal_address_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/postal_address.rb) |
| Product | [Schema.org](https://schema.org/Product) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/product_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/product.rb) |
| SearchAction | [Schema.org](https://schema.org/SearchAction) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/search_action_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/search_action.rb) |
| WebSite | [Schema.org](https://schema.org/WebSite) | [RSpec](https://github.com/public-law/schema-dot-org/blob/master/spec/schema_dot_org/web_site_spec.rb) | [Source](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/web_site.rb) |
## Examples
### BreadcrumbList
The `make_breadcrumbs` convenience method creates a BreadcrumbList from a simple array of hashes:
```ruby
links = [
{ name: 'Home', url: 'https://example.com' },
{ name: 'Books', url: 'https://example.com/books' },
{ name: 'Science Fiction', url: 'https://example.com/books/sci-fi' },
{ name: 'Award Winners' } # Last item typically has no URL
]
SchemaDotOrg
.make_breadcrumbs(links)
.to_s
```
produces:
```html
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://example.com"
},
{
"@type": "ListItem",
"position": 2,
"name": "Books",
"item": "https://example.com/books"
},
{
"@type": "ListItem",
"position": 3,
"name": "Science Fiction",
"item": "https://example.com/books/sci-fi"
},
{
"@type": "ListItem",
"position": 4,
"name": "Award Winners"
}
]
}
```
URLs are automatically validated - invalid URLs will raise an `ArgumentError` with a descriptive message.
### WebSite
Example with only the required attributes:
```ruby
WebSite.new(
name: 'Texas Public Law',
url: 'https://texas.public.law',
)
```
With the optional `SearchAction` to enable a [Sitelinks Searchbox](https://developers.google.com/search/docs/data-types/sitelinks-searchbox):
```ruby
WebSite.new(
name: 'Texas Public Law',
url: 'https://texas.public.law',
potential_action: SearchAction.new(
target: 'https://texas.public.law/?search={search_term_string}',
query_input: 'required name=search_term_string'
)
)
```
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'schema_dot_org'
```
## Development
We aim to make it as easy as possible to contribute new Schema.Org types.
For example, here's a large one, [Organization]([url](https://github.com/public-law/schema-dot-org/blob/master/lib/schema_dot_org/organization.rb)).
The declarative-style coding keeps it readable:
```ruby
require 'date'
require_relative 'person'
require_relative 'place'
require_relative 'postal_address'
module SchemaDotOrg
##
# See https://schema.org/Organization
#
class Organization < SchemaType
validated_attr :address, type: PostalAddress, allow_nil: true
validated_attr :contact_points, type: union(ContactPoint, [ContactPoint]), allow_nil: true
validated_attr :email, type: String, allow_nil: true
validated_attr :founder, type: Person, allow_nil: true
validated_attr :founding_date, type: Date, allow_nil: true
validated_attr :founding_location, type: Place, allow_nil: true
validated_attr :legal_name, type: String, allow_nil: true
validated_attr :same_as, type: union(String, [String]), allow_nil: true
validated_attr :slogan, type: String, allow_nil: true
validated_attr :telephone, type: String, allow_nil: true
########################################
# Attributes that are required by Google
########################################
validated_attr :logo, type: String
validated_attr :name, type: String
validated_attr :url, type: String
end
end
```
The attributes are from the [Schema.org Organization spec](https://schema.org/Organization).
All Rails validations are available. These are just the attributes we've felt like
adding. PR's are welcome if you want to add more. Also for more Schema.org types.
## Contributing
Bug reports and pull requests are welcome on GitHub.
## License
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).