Skip to content

v2.1.0: listing SEO bug fixes, schema completion, search, pagination#12

Merged
ManukMinasyan merged 1 commit into
mainfrom
feat/v1.5.0-listing-seo-schema-search
May 13, 2026
Merged

v2.1.0: listing SEO bug fixes, schema completion, search, pagination#12
ManukMinasyan merged 1 commit into
mainfrom
feat/v1.5.0-listing-seo-schema-search

Conversation

@ManukMinasyan
Copy link
Copy Markdown
Collaborator

Summary

A coherent v1.5.0 release covering listing-page SEO correctness, schema completion (FAQPage + HowTo + Blog + CollectionPage), portable search, and an accessible numbered pagination view.

Driven by gaps surfaced during a 3-month blog launch on a consumer project. The work was prototyped there first and is now generalized for the package.

Fixed (bugs)

  • BlogSitemapGenerator now iterates /blog/tag/{slug} URLs when features.tags is on. The package docs document tag routes as first-class but the sitemap was silently skipping them.
  • Listing routes (/blog, /blog/category/{slug}, /blog/tag/{slug}) now emit per-page canonical URLs and page-aware titles via a new BlogListingSeo helper. Previously every paginated page canonicalized to page 1.
  • Shipped show and preview routes now call seo()->for($post) so post-attached SEO (BlogPosting + BreadcrumbList + FAQPage) actually renders in public-routes mode. Previously the schema only fired for consumers who overrode the controller.

Added (features)

  • FAQPage JSON-LD auto-emit from ## FAQ sections (default on; toggle via schema.faq_auto).
  • HowTo JSON-LD auto-emit from ## Steps sections (opt-in via schema.howto_auto).
  • Blog + CollectionPage JSON-LD on listing routes.
  • Numbered, aria-labeled pagination view at blog::pagination.blog.
  • wire:navigate on <x-blog::post-card> post-link and pagination links.
  • Post::search($term) scope (portable LIKE default, override via search.callback).
  • ?q= honored on shipped /blog route with noindex,follow on result URLs.
  • BlogSearch Livewire component (<livewire:blog::search />).
  • 3 new docs pages: search.md, schema.md, listing-seo.md.
  • ManukMinasyan\FilamentBlog\Support\BlogListingSeo helper (also usable from headless consumers).
  • ManukMinasyan\FilamentBlog\Support\SchemaExtractor helper for FAQ + HowTo HTML parsing.

Internal changes worth flagging

  • FilamentBlogServiceProvider now binds RalphJSmit\Laravel\SEO\TagManager as a singleton in packageRegistered(). Without this, seo()->for(...) in controllers does not persist to {!! seo() !!} in layouts — the singleton binding is required for the documented usage pattern but ralphjsmit/laravel-seo doesn't ship it. If you'd prefer to require consumers to bind it themselves, that's a one-line revert; flagged so you can choose.
  • A Livewire 4 quirk: <livewire:blog::search /> (with :: in the name) doesn't resolve through Livewire's standard ::component() registration. Worked around with a Livewire::resolveMissingComponent callback. If you'd prefer to rename BlogSearchSearch (canonical Livewire convention) and drop the workaround, easy follow-up.

Backward compatibility

  • All schema additions are content-conventional; no breaking changes to existing posts unless they coincidentally have an ## FAQ H2 they didn't intend as FAQ schema (set schema.faq_auto = false to opt out).
  • schema.faq_auto defaults to true. schema.howto_auto defaults to false (opt-in).
  • New listing-route SEO changes the <title> tag on paginated pages (now suffixed with — Page N) and the <link rel="canonical"> URL on pages 2+. This is SEO-correct behavior; consumers relying on the broken previous behavior will see indexing changes.

Test plan

  • vendor/bin/pest --compact — 58 passed, 118 assertions (was 23 on main)
  • vendor/bin/pint --test --format agent — clean
  • Schema spot-check: post with ## FAQ section, validate at https://search.google.com/test/rich-results
  • Schema spot-check: post with ## Steps and schema.howto_auto=true, validate HowTo
  • Sitemap spot-check: enable tags, attach a tag to a published post, regenerate sitemap, verify /blog/tag/{slug} URL appears
  • Pagination smoke: visit /blog?page=2 on a consumer with 15+ posts, verify canonical and — Page 2 title

Provenance

Implementation plan traceable at docs/superpowers/plans/2026-05-13-filament-blog-v1.5.md in the consumer project that drove this work.

The commits are individually testable — each task ships its own tests and committed together with the implementation:

b3b3106 docs: add search/schema/listing-seo pages, finalize v1.5.0 changelog, update README
bff0ff8 feat: add BlogSearch Livewire component with URL-synced query
3b2fef6 feat: add Post::search scope with config callback hook and wire it into /blog?q=
a76f6da feat: numbered aria-labeled pagination view and wire:navigate on post-card
1349a35 feat: auto-emit Blog and CollectionPage JSON-LD on listing routes
1af5e0e feat: auto-emit HowTo JSON-LD when schema.howto_auto is enabled
10fd1ce fix: call seo()->for($post) on show and preview routes
21b965c feat: auto-emit FAQPage JSON-LD from blog FAQ sections
4418f38 fix: emit per-page canonicals and titles for blog listing routes
df6bb0f fix: include tag archive URLs in BlogSitemapGenerator
a65e159 chore: open v1.5.0 changelog stub

Copilot AI review requested due to automatic review settings May 13, 2026 21:04
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prepares a v1.5.0 release focused on public blog SEO correctness, structured data, search, and accessible pagination.

Changes:

  • Adds listing SEO helpers, sitemap tag URLs, post/listing schema emission, and controller SEO wiring.
  • Adds portable post search plus a Livewire search component.
  • Adds numbered pagination views, docs, tests, and changelog updates.

Reviewed changes

Copilot reviewed 30 out of 30 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/Support/SchemaExtractor.php Adds FAQ/HowTo schema extraction helpers.
src/Support/BlogListingSeo.php Adds listing SEOData factory methods.
src/Models/Post.php Adds search scope and FAQ schema wiring.
src/Livewire/BlogSearch.php Adds Livewire search component.
src/Http/Controllers/BlogController.php Wires search, pagination query strings, and SEO calls.
src/FilamentBlogServiceProvider.php Registers SEO transformers, Livewire component, and TagManager singleton.
src/BlogSitemapGenerator.php Adds tag archive URLs to sitemap generation.
resources/views/** Adds pagination/search views and updates listing links/cards.
config/filament-blog.php Adds schema and search configuration.
docs/**, README.md, CHANGELOG.md Documents new SEO, schema, search, pagination, and release changes.
tests/** Adds coverage for sitemap tags, listing SEO/schema, FAQ/HowTo schema, search, pagination, and Livewire search.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +83 to +84
if (! $post instanceof Post && ($slug = $route?->parameter('slug')) !== null) {
$post = Post::query()->published()->where('slug', $slug)->first();
Comment on lines +67 to +68
preg_match_all(
'/<h3[^>]*>(.+?)<\/h3>\s*<p[^>]*>(.+?)<\/p>/is',
Comment on lines +19 to +22
// The shipped package controller does not call seo()->for() in show().
// Consumers override the controller to do so (see Post::getDynamicSEOData
// for the article + FAQ schema wiring). We simulate that here by binding
// a fresh TagManager and pointing it at the post we want to render.
Comment thread config/filament-blog.php Outdated
Comment on lines +42 to +44
| Set `callback` to a closure `(Builder $query, string $term): void` to
| use Postgres FTS, MySQL FULLTEXT, Scout, Meilisearch, or any other
| backend.
Comment on lines +29 to +34
'search' => [
'callback' => function (\Illuminate\Database\Eloquent\Builder $query, string $term): void {
$query->whereRaw(
"to_tsvector('english', title || ' ' || excerpt || ' ' || content) @@ plainto_tsquery('english', ?)",
[$term]
);
Ports the v1.5.0 work to the Relaticle\Ink namespace after the v2.0.0 rename
landed in main. No behavior changes vs the original v1.5.0 PR — pure namespace
adaptation.

Adds:
- BlogListingSeo helper for per-page canonicals on listing routes
- Post::search scope with config-driven callback hook
- FAQPage + HowTo + Blog + CollectionPage JSON-LD auto-emission
- Numbered, aria-labeled pagination view
- BlogSearch Livewire component
- wire:navigate on post-card

Fixes:
- Tag URLs in BlogSitemapGenerator
- Per-page canonicals on /blog?page=N
- seo()->for(\$post) called on show/preview

See CHANGELOG.md and PR description for full details.
@ManukMinasyan ManukMinasyan force-pushed the feat/v1.5.0-listing-seo-schema-search branch from b3b3106 to e77715f Compare May 13, 2026 21:17
@ManukMinasyan ManukMinasyan changed the title v1.5.0: listing SEO bug fixes, schema completion, search, pagination v2.1.0: listing SEO bug fixes, schema completion, search, pagination May 13, 2026
@ManukMinasyan ManukMinasyan merged commit 1a4a277 into main May 13, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants