Skip to content

Search WPDesignVault

Try "image", "json", "schema" or "contrast". Use arrow keys to move through results.

SEO

How to Add LocalBusiness Schema to a WordPress Site

Build LocalBusiness JSON-LD for a WordPress site: the right subtype, Google's required and recommended properties, awkward opening hours, a tested must-use plugin and how to check the result.

Visual guide for local business schema wordpress Complete walkthrough and best practices.
On this page

To add LocalBusiness schema to a WordPress site, write a JSON-LD block for the business and output it on the home page, the contact page or both. The block uses the most specific business type that fits, such as Dentist or Plumber. Google requires two properties: name and address. It recommends telephone, url, geo, openingHoursSpecification and priceRange. You can add the block through your SEO plugin, a schema plugin or a small must-use plugin, but use only one source. Then check it with Google's Rich Results Test.

This post walks through building the markup, choosing the right type, writing opening hours for awkward cases and adding it to WordPress without duplicates. It also covers testing the result. We checked every example against the Schema.org vocabulary (release 30.0). We also ran the WordPress code on a test site (WordPress 7.1.3) to confirm it outputs one valid block on the right pages and none elsewhere.

What LocalBusiness markup does

LocalBusiness structured data describes a business with a physical location or service area: its name, address, phone number, hours and location on a map. Google's documentation says it can help Google show business details in Search and Maps. As with all structured data, it makes a page eligible for these features but does not guarantee them, and it must match what the page shows.

If you are new to structured data, our guide to what schema markup is explains JSON-LD, types and properties first. This post assumes that background and concentrates on LocalBusiness.

<h2
Visual guide for local business schema wordpress Complete walkthrough and best practices.
Three-phase workflow architecture diagram for generating, deploying, and testing local business schema wordpress.

Before you start

  • Collect the exact business details as they appear on your contact page and any business listings: name, street address, postcode, phone with country code, opening hours and holiday closures.
  • Get map coordinates. Google asks for latitude and longitude with at least five decimal places. Most map apps give six or more when you drop a pin.
  • Check what your site already outputs. Run your home page through the structured data checker. Many SEO plugins output an Organization block; some themes add their own markup.
  • Decide where it goes. Google says you can add LocalBusiness markup to any page, but a page about the business, usually the home or contact page, is the natural home.

Step 1: choose the most specific type

Google recommends using the most specific LocalBusiness subtype available. Schema.org has dozens, grouped by sector:

Table: Examples of LocalBusiness subtypes

Business Type to use
Dental practice Dentist
Plumber, electrician, roofer Plumber, Electrician, RoofingContractor
Restaurant or café Restaurant, CafeOrCoffeeShop
Hair salon HairSalon
Accountant or lawyer AccountingService, LegalService
Shop Store or a subtype such as BookStore
Nothing specific fits LocalBusiness

Search the type's name on schema.org to confirm it exists. Making one up, such as DentalClinic, produces markup search engines do not recognise.

<h2
Comparison chart detailing best practices versus common mistakes in local business schema wordpress.
Implementation checklist comparing recommended best practices against common errors in local business schema wordpress.

Step 2: write the JSON-LD

This illustrative example is for a fictional dental practice. Every value must be replaced with your own.

{
  "@context": "https://schema.org",
  "@type": "Dentist",
  "@id": "https://example.com/#dentist",
  "name": "Riverside Dental Studio",
  "url": "https://example.com/",
  "logo": "https://example.com/wp-content/uploads/riverside-logo.png",
  "image": "https://example.com/wp-content/uploads/reception.jpg",
  "telephone": "+1-416-555-0142",
  "priceRange": "$$",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "120 Example Avenue, Suite 4",
    "addressLocality": "Toronto",
    "addressRegion": "ON",
    "postalCode": "M5V 0A0",
    "addressCountry": "CA"
  },
  "geo": {
    "@type": "GeoCoordinates",
    "latitude": 43.64251,
    "longitude": -79.38709
  },
  "openingHoursSpecification": [
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday"],
      "opens": "08:30",
      "closes": "18:00"
    },
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Friday",
      "opens": "08:30",
      "closes": "15:00"
    }
  ],
  "sameAs": [
    "https://www.facebook.com/example-riverside-dental",
    "https://www.instagram.com/example_riverside_dental"
  ]
}

Table: What each part does

Property Google's status Notes
name Required The business name exactly as customers see it
address Required A PostalAddress with as many fields as apply; use a two-letter country code
telephone Recommended Google says to include the country code and area code
url Recommended The business's main page
geo Recommended Latitude and longitude, at least five decimal places
openingHoursSpecification Recommended One object per set of days with the same hours
priceRange Recommended A short indicator such as $$
@id Optional A stable identifier so other markup can refer to the business
sameAs Optional Links to official profiles on other sites

Leave out anything you cannot show on the page. In particular, Google lists reviews and aggregate ratings as recommended only for sites that publish reviews of other local businesses. Do not add star ratings to your own business's markup.

The local business schema generator builds this structure from a form, including opening hours rules and map coordinates, so you do not have to type the JSON by hand.

Step 3: handle awkward opening hours

Google's documentation gives patterns for the cases that trip people up:

Table: Opening hours patterns

Situation How to write it
Closed all day "opens": "00:00", "closes": "00:00", or leave that day out
Open 24 hours "opens": "00:00", "closes": "23:59"
Open past midnight One object with a closing time after the opening time wraps to the next day, for example opens 18:00, closes 03:00
Seasonal or holiday hours Add validFrom and validThrough dates in YYYY-MM-DD format
Different hours on different days One object per group of days that share the same hours

For example, a holiday closure from 24 to 26 December is a separate object:

{
  "@type": "OpeningHoursSpecification",
  "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
  "opens": "00:00",
  "closes": "00:00",
  "validFrom": "2026-12-24",
  "validThrough": "2026-12-26"
}

Step 4: add it to WordPress

Pick one method. Two sources of LocalBusiness markup with different details are worse than none.

Option A: your SEO or schema plugin

Some SEO plugins and dedicated schema plugins offer local business settings, sometimes in a paid add-on. If yours does, fill in the fields there so the markup connects to the rest of the plugin's schema graph. Check the output afterwards: plugins vary in which properties they include.

Option B: a small must-use plugin

If your plugin has no local business option, or you want full control, a must-use plugin can output the block. Save this as wp-content/mu-plugins/local-business-schema.php and replace the details:

<?php
/**
 * Plugin Name: LocalBusiness schema
 * Description: Outputs LocalBusiness JSON-LD on the home and contact pages.
 */
add_action( 'wp_head', function () {
    if ( ! is_front_page() && ! is_page( 'contact' ) ) {
        return;
    }
    $data = array(
        '@context'   => 'https://schema.org',
        '@type'      => 'Dentist',
        '@id'        => home_url( '/#dentist' ),
        'name'       => 'Riverside Dental Studio',
        'url'        => home_url( '/' ),
        'telephone'  => '+1-416-555-0142',
        'priceRange' => '$$',
        'address'    => array(
            '@type'           => 'PostalAddress',
            'streetAddress'   => '120 Example Avenue, Suite 4',
            'addressLocality' => 'Toronto',
            'addressRegion'   => 'ON',
            'postalCode'      => 'M5V 0A0',
            'addressCountry'  => 'CA',
        ),
        'geo'        => array(
            '@type'     => 'GeoCoordinates',
            'latitude'  => 43.64251,
            'longitude' => -79.38709,
        ),
        'openingHoursSpecification' => array(
            array(
                '@type'     => 'OpeningHoursSpecification',
                'dayOfWeek' => array( 'Monday', 'Tuesday', 'Wednesday', 'Thursday' ),
                'opens'     => '08:30',
                'closes'    => '18:00',
            ),
            array(
                '@type'     => 'OpeningHoursSpecification',
                'dayOfWeek' => 'Friday',
                'opens'     => '08:30',
                'closes'    => '15:00',
            ),
        ),
    );
    echo '<script type="application/ld+json">' . wp_json_encode( $data ) . '</script>' . "n";
} );

On our test site, this produced exactly one JSON-LD block on the home page and one on the page with the slug contact, and none on a blog post. The output passed our Schema.org vocabulary check. Building the data as a PHP array and encoding it with wp_json_encode() avoids the most common hand-written JSON errors: missing commas, trailing commas and unescaped quotes.

Option C: a block in the page content

You can paste a <script type="application/ld+json"> block into a Custom HTML block or a page builder's HTML widget. It works, but it is easy to forget when details change, and editors without the unfiltered_html capability cannot save script tags. Prefer Option A or B on sites with several editors.

Worked example: a service-area business

A plumber who visits customers rather than receiving them still needs an address for Google's required properties, usually the registered business address. Use areaServed to describe where it works. This fictional example also shows a 24-hour service:

{
  "@context": "https://schema.org",
  "@type": "Plumber",
  "name": "Northgate Plumbing",
  "url": "https://example.com/",
  "telephone": "+44 161 496 0000",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "Unit 7, Example Trade Park",
    "addressLocality": "Manchester",
    "postalCode": "M1 1AA",
    "addressCountry": "GB"
  },
  "areaServed": [
    { "@type": "City", "name": "Manchester" },
    { "@type": "City", "name": "Salford" },
    { "@type": "City", "name": "Stockport" }
  ],
  "openingHoursSpecification": {
    "@type": "OpeningHoursSpecification",
    "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
    "opens": "00:00",
    "closes": "23:59"
  }
}

If the address is a home and should not be public, think carefully before publishing it in markup, because structured data must match visible content. In that case, publishing the business details without a street address on the page may mean the page is not eligible for the feature. That is a reasonable trade-off for privacy.

Keep every copy of your details consistent

Your business details now exist in several places: the visible contact page, the JSON-LD, your footer, and listings on other sites such as map services and directories. When one of them changes and the others do not, people and search engines see conflicting information. A short routine prevents that:

  • Keep one master record of the name, address, phone number and hours, for example in a shared document, and update it first.
  • Use the same format everywhere. If the page says "Suite 4", the markup should not say "Unit 4".
  • Update the page and the markup together. If the markup is hard-coded in a plugin file, add a note to your change process so it is not forgotten.
  • Plan holiday hours in advance. Add the validFrom and validThrough entry when you announce the closure, and remove it afterwards.
  • Re-test after theme or plugin changes. A new SEO plugin may start outputting its own business markup alongside yours.

Consistency will not guarantee any search feature, but inconsistency is an avoidable reason for search engines to distrust the details.

Several locations

  • Give each location its own page with its own LocalBusiness block, and its own address, phone and hours.
  • Give each block a different @id, such as https://example.com/locations/leeds/#location.
  • On the home page, describe the parent organisation with Organization rather than listing every branch as a LocalBusiness.

Step 5: test and monitor

  • Check the JSON if you wrote it by hand: paste it into the JSON validator. Our guide to fixing JSON syntax errors covers the usual causes.
  • Check the live page with the structured data checker. You should see one LocalBusiness-type block, not two.
  • Run Google's Rich Results Test on the URL and fix any errors. Warnings about missing recommended properties are not blocking, but add the information if the page shows it.
  • Check the Schema Markup Validator at validator.schema.org for vocabulary problems, such as a misspelled type.
  • Keep it current. When hours, phone numbers or addresses change, update the markup on the same day as the page.

Common mistakes

  • Using the generic LocalBusiness type when a specific subtype exists.
  • Adding self-written star ratings to your own business.
  • Hours in the markup that differ from the hours on the page.
  • A phone number without the country code.
  • Coordinates rounded to two or three decimal places.
  • The same business marked up twice, by a plugin and by hand, with different details.
  • Inventing a type name that does not exist on schema.org.
  • Copying an example and forgetting to replace every value.

Troubleshooting

Table: LocalBusiness markup problems

Symptom Likely cause Fix
Rich Results Test detects no items JSON syntax error, or the block is not on the page Validate the JSON; view source to confirm it is output
"Missing field 'address'" No address, or it is a plain string Use a PostalAddress object
Two LocalBusiness items detected Plugin and custom code both output markup Remove one source
"Unknown type" in the Schema Markup Validator Misspelled or invented type Check the type name on schema.org
Markup missing on the contact page The page slug is not contact Change the condition to the real slug or page ID
Old hours still show in tests Page cache serving an old copy Purge the cache and test again

Frequently asked questions

What is LocalBusiness schema?

It is Schema.org structured data that describes a business with a location or service area: its name, address, phone, hours and coordinates. Google can use it to show business details in Search and Maps.

Which properties does Google require?

Only name and address. Google also recommends telephone, url, geo, openingHoursSpecification and priceRange, among others.

Which page should the markup go on?

Google says any page can carry it, but the home page or contact page, where the business details are shown, is the most natural place.

Do I need a plugin to add LocalBusiness schema?

No. A short must-use plugin can output it, as shown above. An SEO or schema plugin with local business settings is easier to maintain for non-developers.

Should I add star ratings to my own business markup?

No. Google recommends review and rating properties only for sites that capture reviews of other local businesses.

How precise should the coordinates be?

Google asks for at least five decimal places of latitude and longitude. Drop a pin in a map app and copy the full coordinates.

How do I mark up a business that is closed on some days?

Leave the closed day out, or set both opens and closes to 00:00. Use validFrom and validThrough for holiday closures.

Can a service-area business use LocalBusiness schema?

Yes. Include the required address and describe the area covered with areaServed. If the address must stay private, the page may not be eligible for the feature.

Does LocalBusiness schema help local rankings?

Google does not describe structured data as a ranking factor. It helps Google understand and display business details accurately.

How do I handle several locations?

Create a page for each location with its own LocalBusiness block and a unique @id, and describe the parent brand on the home page with Organization markup.

Next step

Generate your block with the local business schema generator, add it with one of the methods above, and confirm the live page with the structured data checker and Google's Rich Results Test.

WordPress Snippet Generator

Generate clean, escaped WordPress code for the tasks developers repeat most: enqueueing scripts and styles, shortcodes, widget areas,…

wp-config.php Generator

Generate a complete wp-config.php with database details, newly generated security keys, debug settings and useful constants. Keys are…

HTTP Headers Checker

View the HTTP response headers of any URL and check caching, compression and common security headers such as…

Related articles

Comprehensive guide and visual tutorial explaining keyword density for WordPress websites.
SEO

Does Keyword Density Still Matter?

Google gives no target keyword density, but unnatural repetition counts as keyword stuffing. How density is calculated, what Yoast's check uses, and…

9 min read

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *