pubvana / seo
SEO package for Pubvana — meta tags, structured data, sitemaps, Open Graph, AI/GEO optimization
Requires
- php: ^8.1
- enlivenapp/flight-school: ^0.3
- enlivenapp/flight-settings: ^0.2
- enlivenapp/flight-shield: ^0.2
- enlivenapp/migrations: ^0.2
- flightphp/active-record: ^0.7
Suggests
- pubvana/admin: Admin UI for SEO settings and content panel
README
I noticed folks downloading some of these packages. I'm super grateful, Thank You! I would like to let folks know until this notice disappears I'm doing a lot of breaking changes without worrying about them. Once versions are up around 0.5.x things should settle down.
Full SEO package for Pubvana — meta tags, structured data, sitemaps, Open Graph, AI/GEO optimization.
Requirements
- PHP 8.1+
enlivenapp/flight-school^0.3enlivenapp/flight-settings^0.2enlivenapp/flight-shield^0.2enlivenapp/migrations^0.2flightphp/active-record^0.7
Features
Meta Tags & Head Output
- Per-content meta title and description with fallback chain
- Configurable title templates with tokens (
{title} {sep} {site_name}) - Character counters (title 50–60, description 120–160)
- Self-referencing canonical URLs with per-content override
- Per-content robots directives (noindex, nofollow)
- hreflang stub (defaults to
en, ready for i18n)
Structured Data (JSON-LD)
- WebSite schema on homepage with SearchAction
- Organization schema with logo and social sameAs
- BlogPosting schema on posts with author, dates, publisher
- WebPage schema on static pages
- BreadcrumbList schema on all pages
Open Graph & Twitter Cards
- Full OG tag set: title, description, image, url, type, site_name, locale
- Twitter Card support (summary_large_image default)
- Per-content overrides for all social fields
- Fallback to featured image then site default OG image
XML Sitemap
- Auto-generated at
/sitemap.xml - Only
<lastmod>(Google ignores changefreq/priority) - Includes pages, posts, categories, tags
- Excludes noindex content automatically
AI/GEO Optimization
- llms.txt at
/llms.txt— curated content map for AI crawlers (llmstxt.org spec) - AI crawler management — per-bot allow/block toggles in admin
- Separate treatment for training bots (block by default) vs retrieval/citation bots (allow by default)
- Known bots: GPTBot, ChatGPT-User, Google-Extended, ClaudeBot, Claude-SearchBot, CCBot, PerplexityBot, Bytespider, Applebot-Extended, FacebookBot
robots.txt
- Served at
/robots.txt - Editable custom body from admin
- AI crawler directives appended automatically
- Sitemap URL always appended
Content Analysis & SEO Scoring
- Up to 5 focus keywords per content item
- 15-point analysis: title/description length and keyword presence, content length, keyword density, first paragraph, headings, internal links, URL slug, images/alt text, readability
- Score 0–100 with pass/warning/fail for each check
- Live JS widget in admin edit forms
- SERP preview with real-time updates
Admin
- Dedicated SEO nav item under Settings
- Dashboard cards: SEO coverage % and average score
- Per-content SEO panel for page/post edit forms
- Search engine verification codes (Google, Bing)
- Organization identity for schema output
Services
| Service | Access | Purpose |
|---|---|---|
| SeoService | $app->seo() |
Meta tags, head output, context, meta CRUD |
| SchemaService | $app->seoSchema() |
JSON-LD structured data generation |
| SitemapService | $app->seoSitemap() |
XML sitemap generation |
| RobotsTxtService | $app->seoRobots() |
robots.txt generation with AI bot management |
| LlmsTxtService | $app->seoLlmsTxt() |
llms.txt generation |
| ContentAnalysisService | $app->seoAnalysis() |
Content scoring and SEO checks |
Public Routes
| Route | Purpose |
|---|---|
/sitemap.xml |
XML sitemap |
/robots.txt |
robots.txt with AI crawler directives |
/llms.txt |
AI content discovery file |
Admin Routes
| Route | Purpose |
|---|---|
GET /admin/seo |
Settings page |
POST /admin/seo |
Save settings |
POST /admin/seo/meta |
Save per-content SEO meta (AJAX) |
GET /admin/seo/analyze |
Run content analysis (AJAX) |
Integration
The SEO package owns all SEO-related fields for content items. The seo_meta table stores per-content data using a polymorphic content_type + content_id pattern.
Controllers should call $app->seo()->setContext(...) before rendering to provide the SEO service with current page data. The service then assembles all meta tags, schema, and OG tags for head injection.
License
MIT