Skip to main content

SEO-Friendly Markup

SEO starts with what your theme outputs: headings, landmarks, navigation, and link structure. GeneratePress is a strong baseline because it favors semantic HTML and minimal, predictable markup.

The Concept: "SEO-Friendly" Is Mostly "Unambiguous"

Search engines do not need fancy HTML. They need HTML that is:

  • Semantic (landmarks like header, nav, main, footer)
  • Consistent (one primary H1 per page, logical H2/H3 hierarchy)
  • Crawlable (links are links, content is not hidden behind scripts)
  • Fast to parse (avoid excessive wrappers and inline scripts)

GeneratePress helps because its templates are intentionally lean. Your job is to keep your customizations lean too.

Where Markup Usually Goes Wrong

Common theme + editor pitfalls:

  • Multiple H1s (often from a hero block plus the post title)
  • Skipping heading levels (H2 -> H4) because of visual styling choices
  • Navigation built with div + click handlers instead of actual <a> links
  • Important content placed inside sliders/tabs that are hidden by default
  • Duplicate breadcrumbs (theme + SEO plugin + page builder)
caution

Avoid adding "SEO helpers" in multiple places. A single breadcrumb trail, a single schema source, and a single canonical URL source is the safe default.

GeneratePress Basics That Help SEO

Use HTML5 + correct landmarks

GeneratePress outputs semantic structures by default. The key is to keep your custom templates and Elements aligned with that structure.

Keep your headings intentional

Treat headings as document structure, not as a styling tool.

Quick rule of thumb:

  • Pages: one H1 (usually the page title)
  • Sections: H2
  • Subsections: H3

Make navigation "real" navigation

Menus should be <nav> containing <a> links, not interactive blocks that require JS to navigate.

Internal linking is markup + content strategy:

  • Use descriptive anchor text (not "click here")
  • Link up (child -> parent) and across (related pages)
  • Keep key pages reachable within a few clicks

Practical Checklist (Do This Per Page Type)

Use this table as a recurring QA pass when you create layouts with the Customizer, Elements, and blocks.

AreaWhat to look forGeneratePress-friendly approach
Title + H1Exactly one H1, matches page intentLet WordPress output the title; avoid extra H1 hero blocks
Landmarksheader, nav, main, footer presentAvoid wrapping everything in extra divs via Elements
Nav linksLinks are <a href>Use WP Menus + GP navigation; don't use JS-only buttons
Imagesalt describes purposeUse descriptive alt for content images; empty alt for purely decorative
Above-the-foldContent visible without JSAvoid hiding primary copy in tabs/accordions by default
PaginationCrawlable next/prev linksUse archive pagination; avoid infinite scroll for SEO-critical archives

How To Inspect Your Markup Quickly (Server-Side)

On an Ubuntu server (including an OpenLiteSpeed VPS), you can spot-check output without needing browser devtools.

Fetch HTML and preview key areas
SITE_URL="https://example.com"
curl -sL "$SITE_URL/about/" | sed -n '1,160p'

If you want more targeted checks, look for headings and landmarks:

Quick grep for common structure issues
SITE_URL="https://example.com"
curl -sL "$SITE_URL/" | rg -n "<(h1|h2|main|nav|header|footer)" | sed -n '1,120p'
tip

If a page is built with blocks, your content structure is often fine but the hero section introduces an extra H1. Make the hero headline an H2 and style it, rather than upgrading it to H1.

Adding Breadcrumbs Without Mess

Breadcrumbs can help users and can reinforce internal linking, but they must be consistent and non-duplicated.

If you use an SEO plugin that provides breadcrumbs, prefer that single source. If you are intentionally implementing a simple breadcrumb trail yourself, add it once, close to the title, using a Hook Element.

Hook Element: simple breadcrumb wrapper (example)
<?php
/**
* Place this in a GeneratePress Hook Element (PHP enabled),
* or in a child theme where appropriate.
*/

if ( is_front_page() ) {
return;
}

echo '<nav class="breadcrumbs" aria-label="Breadcrumbs">';
echo '<a href="' . esc_url( home_url( '/' ) ) . '">Home</a>';
echo ' <span aria-hidden="true">/</span> ';
echo '<span class="breadcrumbs__current">' . esc_html( wp_get_document_title() ) . '</span>';
echo '</nav>';

Best Practices

  • Prefer semantic structure over wrapper divs
  • Use CSS to style headings instead of changing heading levels
  • Keep a single source of truth for: breadcrumbs, schema, canonicals
  • Don't hide primary content behind interactions by default
  • Validate templates when you add Elements or custom hooks

Troubleshooting

SymptomLikely causeFix
Two H1s on a pageHero block is H1 + post title is H1Change hero headline to H2; keep only the title as H1
Breadcrumbs appear twiceSEO plugin + custom Hook ElementRemove the custom breadcrumb hook or disable plugin breadcrumbs
Nav links not crawlableMenu built with buttons/JSUse WP Menu + <a> links; avoid click handlers
Archives look thinExcerpts too short + no taxonomy contextAdd helpful intro content to category/tag archives

Hands-On: Markup QA Pass

  1. Pick one important page (Home, Services, or a core landing page).
  2. Fetch the HTML and confirm landmarks/headings exist.
  3. Fix any H1 duplication and heading skips.
  4. Confirm the primary navigation uses real links.
  5. Re-test.
Run a repeatable QA check for a page
PAGE_URL="https://example.com/services/"
curl -sL "$PAGE_URL" > /tmp/page.html
rg -n "<h1" /tmp/page.html
rg -n "<main" /tmp/page.html
rg -n "<nav" /tmp/page.html

Quick Reference

  • One page, one H1
  • Landmarks: header, nav, main, footer
  • Navigation: real <a href> links
  • Avoid duplicate breadcrumbs/schema sources

What's Next