justkidding96/aardvark-seo
Aardvark SEO is a Laravel package for managing on-page SEO with ease, covering meta tags, titles, descriptions, Open Graph, Twitter cards, sitemaps, and redirects through a clean fluent API, Blade directives, and sensible defaults for fast integration.
Aardvark SEO is a Statamic addon, not a standalone Laravel package — it only makes sense inside a Statamic site (Statamic 3/4/5 depending on the version you install). Treat it as the piece that generates your <head> meta: title, description, canonical, robots, Open Graph, and Twitter cards, driven by per-entry fields with site-wide fallbacks.
Minimal steps:
composer require justkidding96/aardvark-seovendor:publish --tag=aardvark-seo-config, and possibly views with --tag=aardvark-seo-views).config/aardvark-seo.php first. That's your source of truth for defaults: site name, title suffix/prefix, default social image, fallback description.pages and posts collections.<head>:
{{ aardvark_seo }}
(or a partial the addon provides — grep vendor/justkidding96/aardvark-seo/resources/views for the exact name).First use case: pick one blog post, fill in the SEO tab, view source, and confirm the title/description/OG tags come out right. That single loop tells you whether the config defaults, blueprint handles, and rendering tag are all aligned before you roll it across every collection.
Blueprint-first, layout-second. The addon is only as good as the fields you give editors. Create one shared fieldset (resources/fieldsets/seo.yaml) and import it into every collection rather than copy-pasting tabs. Keep the handles stable — renaming seo_description later silently drops content unless you migrate.
Layered fallbacks. The most useful pattern is: per-entry field → collection/site default → config default. Most Aardvark setups already do title fallback to the entry title; for description, fall back to a summary/excerpt field so editors don't have to write meta copy for every post. Do the fallback logic in the addon's config/Antlers, not in your templates.
Render once, in one layout. Put the tag in resources/views/layout.antlers.html inside <head>. If you have multiple layouts, extract a {{ partial:seo }} that wraps it, so a future swap of the addon is a one-file change.
Social images as a dedicated asset container. Point the OG image field at a social container with a fixed transformation (1200×630) rather than reusing hero images. OG scrapers are picky about aspect ratio, and pre-cropped assets avoid runtime image manipulation on every request. Verify the addon emits absolute URLs — if not, wrap with {{ image:url }} plus config:app.url.
Canonical discipline for listings and pagination. For paginated archives and filtered/sorted URLs (?page=2, ?tag=x), set canonical back to the base URL and noindex the filtered variants. This is the single highest-leverage thing you can do with an SEO addon on a content site.
Multisite. Loop sites for hreflang alternates, and make sure each site's canonical points at its own domain, not the default site's. Check whether the addon is site-aware before you trust it.
Blade/non-Antlers surfaces. If you have Laravel routes rendering Blade (a search page, an API-driven landing page), you can't use the Antlers tag. Pull the same values through the entry's augmented data or the addon's underlying class and render your own <head> partial. Keep a small Blade component so both worlds look identical.
Pair with sitemap generation. Feed noindex entries out of your sitemap and keep the two in sync; the addon's robots flags are only meaningful if your sitemap respects them.
Testing. Add HTTP tests that assert on <head> content for one page per collection:
$this->get('/blog/hello')
->assertSee('<meta property="og:title"', false)
->assertSee('content="Hello"', false);
Cheap, and it catches broken fallbacks and double-rendered tags immediately.
NOASSERTION license mean you should pin an exact version in composer.json and be ready to vendor the package. The listed release date (2026) looks like a data artifact — verify the actual tags on the repo before assuming maintenance cadence.composer.json constraint against your Statamic version before installing; a mismatch typically manifests as a blank SEO tab or an unknown tag error rather than a clean install failure.<title>, og:*, or a description, you'll get doubles — and Google picks unpredictably. Strip the theme's versions the moment you install this." and &; if the addon doesn't escape, apply | sanitize or | entities.php please stache:clear and clear the static cache. "The addon is broken" is almost always this.APP_ENV !== 'production' → noindex, nofollow) in the config so preview and staging environments never get indexed, regardless of what editors saved on entries.content="" attributes. Wrap optional tags conditionally rather than shipping empty OG fields.resources/views/vendor/...; edits inside vendor/ disappear on the next composer update.{{ aardvark_seo }} in isolation, or dd() the entry's augmented SEO array), then check the blueprint handle names, then the config. That order resolves 90% of issues.How can I help you explore Laravel packages today?