Managing organic visibility for one physical location is a fairly simple job. When a company grows to 50, 100 or 500 branches, offices or clinics, it runs into a governance problem: how do you keep central control of the brand without losing the local relevance that “near me” searches depend on?
Many multi-location brands use WordPress Multisite as the platform that joins the national authority of one domain with the specifics of each physical location. This guide walks through the architecture and, at each step, what the Google and WordPress documentation actually says, because much of what circulates about local SEO at scale is folklore.
Learn more about SEO and GEO optimization services for multi-region enterprise architectures.
1. Why use WordPress multisite for multiple locations
Large chains often pick one of two bad extremes: putting every store on one static listing page, or running dozens of completely separate WordPress installs. The first has no depth to rank for specific geographic queries; the second turns into a security and maintenance problem with hundreds of databases and isolated dashboards.
WordPress Multisite solves this with one platform that runs a network of sub-sites from a single codebase:
- Central theme and plugin management: security updates, the corporate theme and analytics tools are installed once at network level by the Super Admin.
- Separate data tables: each sub-site has its own set of tables (
wp_X_posts,wp_X_options), so local settings and posts stay strictly apart. - Granular permissions: local managers get limited editing access to update special opening hours or publish local news, without the risk of breaking the portal.
The WordPress Multisite documentation sums up the data model in one sentence: “The content in a Multisite has its own unique tables in the database, only the user table is shared between the instances.” The same page notes that rewrites must be enabled to use Multisite.
2. Subdirectories or subdomains for location pages
The URL structure decides where each branch lives and what it costs to maintain. The table below follows the comparison Google publishes in Managing multi-regional and multilingual sites, applied to city pages:
| Model | URL structure | Pros according to Google | Cons according to Google |
|---|---|---|---|
| Subdirectories | brand.com/leeds/ | Easy to set up; low maintenance (same host) | Single server location; separating sites is harder |
| Subdomains | leeds.brand.com | Easy to set up; allows different server locations; easy separation | Users might not recognize from the URL what the prefix means |
| Separate domains | brand-leeds.com | Full separation, useful for franchisees with their own identity | More infrastructure and a domain to build from zero for each store |
| URL parameters | brand.com?store=leeds | None | Google says they are not recommended |
Google gives none of these models a ranking advantage. For a store network in one country, subdirectories usually win on operations: one certificate, one host, one cache configuration. Subdomains make sense when there are technical reasons to serve regions from different servers.
On the WordPress side, Create a network explains that the choice between subdomains and subdirectories is made when the network is installed, and that you can reconfigure the network to use the other choice afterwards, although the switch takes work. The same page says wildcard DNS is only needed for on-demand domain-based sites, whatever the install screen suggests.
3. How to add LocalBusiness schema for each store location
Structured data tells search engines explicitly what each location’s name, address and hours are. According to the LocalBusiness structured data documentation, people searching for businesses on Google Search or Maps may see a knowledge panel with those details.
Each sub-site in the Multisite network should generate its own complete JSON-LD block. The example uses a fictional brand:
<!-- Example LocalBusiness JSON-LD generated for one location (fictional brand) -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Store",
"name": "Example Brand Leeds",
"url": "https://example.com/leeds/",
"telephone": "+44 113 000 0000",
"address": {
"@type": "PostalAddress",
"streetAddress": "100 Example Street",
"addressLocality": "Leeds",
"postalCode": "LS1 0AA",
"addressCountry": "GB"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 53.80076,
"longitude": -1.54908
},
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"opens": "09:00:00",
"closes": "18:00:00"
}
]
}
</script>The Google rules this example follows:
- Required: only
nameandaddress, with as many address properties as possible. - Coordinates: in
geo, latitude and longitude need a precision of “at least 5 decimal places”. - Hours:
opensandclosesin hh:mm:ss format;openingHoursSpecificationaccepts a single object or an array. - Telephone: the primary contact method for customers, with country code and area code.
- URL: the fully qualified URL of the specific location, and it must be a working link. In a Multisite network that is the branch page, not the brand home page.
- Subtype: Google asks for the most specific LocalBusiness subtype possible (
Storein the example). - Departments: a branch with a pharmacy counter or a workshop can describe each part with
department.
One point many guides skip: Google recommends aggregateRating and review only for sites that capture reviews about other local businesses. A chain marking up reviews of its own stores is not in that position.
Through custom fields (for example Advanced Custom Fields) or the REST API, this data is filled in once per location in the database and injected into the HTML automatically, with no manual coding by local staff.
4. How to sync NAP data with Google Business Profile
Mismatched NAP data (name, address, phone) between the website, the structured data and the Google Business Profile leaves open which version is correct. If the address on the site shows a different postcode from the one in the profile, users and search engines get two versions of the same store.
To keep them aligned, WordPress acts as the master record:
- Central database: address, opening hours and contact data for every store are kept in one canonical format in WordPress.
- API connectors: scheduled jobs (WP-Cron or a server crontab) push changes to the Google Business Profile APIs, for organisations that have access to them.
- Exceptions: when a manager changes closing time for a local public holiday, the change starts in one place and reaches the site, the structured data and the profile.
5. What Google Business Profile guidelines require from a store network
The guidelines for representing your business on Google define what each WordPress record must contain before it goes to the profile:
- One profile per location: Google says “Do not create more than one page for each location of your business, either in a single account or multiple accounts.”
- Name: it “should reflect your business’s real-world name”, without unnecessary information. For a chain, “All locations must have the same name unless the business’s real world representation consistently varies from location to location.” A per-branch public name field, with the brand name locked at network level, stops a manager from adding keywords.
- Address: it must be the actual physical location; P.O. boxes and virtual offices are not eligible.
- Phone: under the direct control of the business; Google prefers a local number over a central call center helpline whenever possible.
- Website: it should represent the individual business location. In a Multisite network that points naturally to the branch URL.
- Departments: publicly facing departments that operate as distinct entities can have their own profile, with a name different from the main business.
- Service-area businesses: one profile for the central office with a designated service area, and the address hidden from customers.
For verification, the bulk verification page applies “If you have 10 or more locations of the same business”. The request uses a spreadsheet of all profiles you manage, is not available to service-area businesses and may require video verification with an authorized representative at the location. An export generated from the Multisite network tables is the most direct way to produce that spreadsheet without copy errors.
6. How to build location pages without duplicate content
Creating 100 city pages by swapping the town name in a static text (“Best IT services in Leeds”, “Best IT services in Bristol”) produces low-value pages.
Google’s spam policies describe this pattern directly. Among the examples of doorway abuse is “Having multiple domain names or pages targeted at specific regions or cities that funnel users to one page”. The same page defines scaled content abuse as generating many pages for the primary purpose of manipulating search rankings and not helping users. A Multisite network with 500 near-identical sub-sites fits both definitions. Programmatic templates are only safe when each page is filled with data that belongs to that location.
Each local sub-site needs real substance:
- Team on site: photo, name and specialism of the people working at the branch.
- Projects and case studies from the area: short references to work done for local organisations, where they exist and can be published.
- Access and transport: concrete information about nearby stations, bus stops or car parks.
- Local involvement: participation in local fairs, talks or sports partnerships.
The practical test: if the branch page disappeared, would the user lose information they cannot find on the national page? If not, the page should not exist.
7. How to create new locations with WP-CLI
Creating hundreds of branches by hand in the dashboard takes hundreds of hours and multiplies configuration mistakes. Network administrators should use the command line through WP-CLI.
Enable Multisite with subdirectories in wp-config.php
The first step is define( 'WP_ALLOW_MULTISITE', true );. After you create the network, the install screen shows the final lines, customised for your installation; for a subdirectory network they look like this:
/* Multisite network configuration with subdirectories */
define('WP_ALLOW_MULTISITE', true);
define('MULTISITE', true);
define('SUBDOMAIN_INSTALL', false);
define('DOMAIN_CURRENT_SITE', 'brand.com');
define('PATH_CURRENT_SITE', '/');
define('SITE_ID_CURRENT_SITE', 1);
define('BLOG_ID_CURRENT_SITE', 1);Clone new locations with Bash and WP-CLI
The script starts from a template site (ID 2, at brand.com/template/). After copying the template tables, the siteurl and home options still point to the template, so step 3 fixes them with a search-replace limited to the new site:
#!/usr/bin/env bash
# Automated provisioning script for new WordPress locations
CITY_SLUG="leeds"
CITY_NAME="Leeds"
MANAGER_EMAIL="[email protected]"
# 1. Create a new sub-site in the Multisite network
NEW_BLOG_ID=$(wp site create --slug="$CITY_SLUG" --title="Brand $CITY_NAME" --email="$MANAGER_EMAIL" --porcelain)
# 2. Clone settings and blocks from the standard template (site_id 2)
wp db export /tmp/template.sql --tables=$(wp db tables "wp_2_*" --format=csv)
sed -i "s/wp_2_/wp_${NEW_BLOG_ID}_/g" /tmp/template.sql
wp db import /tmp/template.sql
rm /tmp/template.sql
# 3. Fix URLs inherited from the template and set location metadata
wp search-replace "brand.com/template/" "brand.com/$CITY_SLUG/" --url="brand.com/$CITY_SLUG/"
wp option update blogname "Brand $CITY_NAME" --url="brand.com/$CITY_SLUG/"
wp post update 1 --post_title="Branch $CITY_NAME" --url="brand.com/$CITY_SLUG/"
echo "Sub-site live at brand.com/$CITY_SLUG/ with ID $NEW_BLOG_ID"Test the script on staging before production: copying tables bypasses WordPress hooks, and plugins that store data in their own tables need separate handling.
8. Who controls what in WordPress multisite network administration
The division of powers in the network administration documentation is what makes the model safe for hundreds of local managers:
- Super Admin: only the network administrator installs themes and plugins. In the documentation’s words, “Site admins cannot install new themes or plugins.”
- Plugins: the Super Admin can Network Activate a plugin, for example the one that outputs LocalBusiness JSON-LD, so no branch runs without it.
- Themes: a theme must be network activated or enabled in the Themes tab of the specific site. The corporate theme is available to all; alternative themes never appear to branches.
- Plugins menu: whether site administrators see the Plugins screen is an option in Network Settings. For a store chain it makes sense to leave it off.
- Files: the first site stores uploads in
/wp-content/uploads/and later sites in/wp-content/uploads/sites/, which allows per-branch backups and clean-ups.
Because the user table is shared, a regional director can hold the Editor role on ten sub-sites with one account, and a store manager on their own site only.
9. How to give franchisees their own domain with domain mapping
Not every location lives under the main domain. A franchisee with its own brand may need its own domain. According to the domain mapping page, “In WordPress 4.5+, domain mapping is a native Multisite feature”: in the network admin, under Sites, you edit the sub-site and enter the full URL in the Site Address (URL) field.
The practical requirements, all from the same page:
- DNS: additional domains should point to the main network domain before mapping.
- SSL: a certificate on the primary domain and SNI for the others; every domain should have SSL so the admin login is encrypted.
- Cookies: if login fails on a mapped sub-site, the documentation says to add
define( 'COOKIE_DOMAIN', $_SERVER['HTTP_HOST'] );to wp-config.php, after the network code.
The trade-off is the one in the table in section 2: each separate domain builds its presence from zero, so mapping serves brand identity, not SEO.
10. How to set up hreflang when the network covers several countries
A network with branches in the United Kingdom, Ireland and the United States often has the same service page in British, Irish and American English. This is where hreflang comes in, described by Google in Tell Google about localized versions of your page:
- Three methods:
linktags in the HTML, HTTP headers or the XML sitemap. In a Multisite network, the sitemap generated by each sub-site is the easiest method to maintain. - Reciprocity: “Each language version must list itself as well as all other language versions.” If the Irish sub-site points to the British one and the British one does not point back, the annotation fails.
- x-default: the reserved value used when no other language or region matches the user’s browser setting, for example a country selector page.
- Codes: only ISO 639-1 language codes and ISO 3166-1 Alpha 2 region codes are supported, such as
en-GB,en-IEoren-US. Google is explicit: “You can’t specify the country code by itself.” - Language detection: Google does not use hreflang or the HTML
langattribute to detect the language of a page; the visible text has to be in that language.
City pages in the same country and language do not get hreflang between them: Leeds and Bristol are not language versions of each other.
11. Why not adapt content by IP or browser language
A common temptation in large networks is to redirect visitors automatically to the nearest branch. The same Google page on multi-regional sites advises against it for two reasons:
- The crawler sends HTTP requests without setting
Accept-Languagein the request header, so content that changes with browser language may never be found. - “Don’t use IP analysis to adapt your content”, because IP location analysis is difficult and generally not reliable.
Google recommends different URLs for each version and ignores locational meta tags such as geo.position. In practice: a visible store selector with crawlable links to each sub-site, not a silent redirect. Among the signals Google uses to understand a site’s audience are local addresses and phone numbers on the page, one more reason to show NAP data in the HTML of every branch.
12. How to speed up multisite with edge caching and Redis
A WordPress install with hundreds of sub-sites in production needs some architectural care:
- Edge caching via CDN: serve cached pages from the points of presence of a CDN such as Cloudflare or Fastly, closer to users in each region.
- Object cache with Redis: a persistent object cache keeps option and metadata lookups from hundreds of network tables in memory.
- Database housekeeping: keep the
wp_blogsandwp_sitetables in good shape so request routing stays fast.
Server location is one of the audience signals Google lists, but Google itself says it is not a definitive signal. The CDN delivers speed; geographic targeting comes from page data and hreflang.
13. Enterprise local SEO maturity model
| Level | Technical architecture | Editorial strategy | Main risk |
|---|---|---|---|
| Level 1: Initial | One page with a list of addresses | Generic text, no dedicated pages | No page that answers searches for a city |
| Level 2: Basic | Manual pages per city | Duplicate content with the town name swapped | Doorway pages under Google’s spam policies |
| Level 3: Enterprise Multisite | WordPress Multisite with a sub-site template | Structured fields, local data and JSON-LD schema | NAP data out of line with Google Business Profile |
| Level 4: Multinational | Multisite with hreflang between countries and API sync | Local content tied into the CRM | Non-reciprocal hreflang annotations |
Building the company’s network on WordPress Multisite gives the brand the governance of a corporate portal with local pages that answer people looking for each store, as long as every page has its own content and data that match the Google profile.







