Skip to content

feat: G4b — re-enable core/archives, core/categories, core/tag-cloud - #426

Merged
ViewFromTheBox merged 2 commits into
release/1.0from
enhancement/401-re-enable-archives-categories-tag-cloud
Apr 30, 2026
Merged

ViewFromTheBox merged 2 commits into
release/1.0from
enhancement/401-re-enable-archives-categories-tag-cloud

Conversation

@ViewFromTheBox

@ViewFromTheBox ViewFromTheBox commented Apr 30, 2026 •

Copy link
Copy Markdown
Member

Description

Re-enable the three taxonomy/feed widgets the M5 audit deferred to "empty-state — disabled by default" until cms-framework landed. Each block ships as a DynamicBlock subclass under src/Blocks/Core/ that reads from cms-framework's PostCategory, PostTag, and Post models respectively. Registration is gated on class_exists(BlogManager::class) so the package still boots standalone — without cms-framework the blocks stay deferred and the deny-list keeps them out of the inserter.

Closes: #401

Type of Change

  • Enhancement (improves existing functionality)

Related Issue

Issue: #401

Motivation and Context

#401 is Wave 4 of the V1 ship plan (plan 12 §2.5). G4a verified core/post-* against G3 entities; this is the matching wire-up for the three taxonomy/feed widgets the audit had been holding in the deny-list.

Changes Made

  • Three DynamicBlock subclasses (src/Blocks/Core/{Categories,TagCloud,Archives}Block.php). Each isolates the data fetch in a protected function fetch*() method so tests can override the data source without exercising the database.
  • Service provider registers them under class_exists(BlogManager::class) in a new registerTaxonomyAndArchiveBlocks() boot step.
  • config/visual-editor.php: moved the three blocks from disabled_blocks to enabled_blocks; updated the explanatory comment.
  • D2_DISABLED_BLOCKS in site-editor-app.tsx mirrors the PHP change.
  • EnabledBlockNamesTest snapshot updated.

Editor surface

The upstream core/categories, core/tag-cloud, and core/archives Edit components depend on shim surface that does not exist in V1 (getTaxonomies, getTaxonomy('category').labels, and the wp/v2/block-renderer/{name} route). A new taxonomy-archive-block-overrides.tsx module registers a blocks.registerBlockType filter (BEFORE registerCoreBlocks()) that swaps each block's edit with a thin wrapper using the existing ServerSideRender shim, plus a minimal InspectorControls panel for the toggles each block actually persists. Block save() shape stays untouched so attribute round-trip is unaffected.

Wired into both editor-app.tsx (post editor) and site-editor-app.tsx (site editor); idempotent across HMR via a global Symbol guard.

Renderer integration

Editor preview, Blade renderer, React renderer, and Vue renderer all resolve through the same DynamicBlock::render() path. Renderers post to /visual-editor/api/blocks/preview, the controller routes through the dynamic-block registry, and the registered block emits HTML. One implementation, all four surfaces.

Documented deviation

The taxonomy entity registration called for in #401's implementation notes ({kind: 'taxonomy', name: 'category', baseURL: '/post-categories', …}) is intentionally not added in V1. The upstream Edit components all render through ServerSideRender (and our overrides do the same), so they never query useEntityRecords('taxonomy', 'category'). Adding entities pointing at non-existent endpoints would be dead code in V1; PostCategory/PostTag are not HasBlockContent models so they do not fit WpEntityController either. The audit doc captures this — entities can be layered in cheaply later if a future block needs them.

How Has This Been Tested?

Testing Environment:

  • macOS 25.4.0
  • Safari (dev app via Laravel Herd)
  • PHP 8.4.3
  • Branch: release/1.0

Tests Performed:

  1. Full PHP suite (./vendor/bin/pest): 484 passed (1 pre-existing skip), 1519 assertions.
  2. Full JS suite (npm test): 970 passed (1 pre-existing skip).
  3. Manual smoke flow in dev app:
    • Insert each of the three blocks in the post editor.
    • Flip the InspectorControls toggles (post counts, hierarchy, dropdown, etc.) and verify the preview re-renders.
    • Save the post and view the rendered output via the front-end Blade renderer — same HTML as the editor preview.

CodeRabbit: two-pass local review (cr review --base release/1.0 --prompt-only) — flagged a hardcoded id="wp-block-archives-dropdown" collision risk, fixed in ArchivesBlock::renderDropdown() with a uniqid() suffix shared between the <select> and the label's for=. Second pass: no findings.

Accessibility Tests Run

  • ARIA labels checked
  • Keyboard navigation tested (manual smoke in Safari)
  • Screen reader tested
  • Color contrast verified

Details:

  • The dropdown variant of core/archives uses <label class="screen-reader-text" for="wp-block-archives-dropdown-{uniqid}"> paired to a matching <select id=...>. The CodeRabbit-flagged hardcoded id was replaced so multiple core/archives blocks on a page do not collide on the same for/id pair.
  • All emitted HTML escapes user-controlled term names, slugs, and labels via e() (Laravel's htmlspecialchars wrapper). XSS escape is asserted in CategoriesBlockTest + TagCloudBlockTest.

Tests Added

  • Unit tests added/updated
  • All tests passing

Test details:

  • CategoriesBlockTest (7 cases): flat list, hierarchy, post counts, empty-term filter, top-level filter, empty shell, XSS escape.
  • TagCloudBlockTest (8 cases): link rendering, font scaling, equal-count collapse, empty-tag filter, count display, numberOfTags clamp, empty paragraph, XSS escape.
  • ArchivesBlockTest (6 cases): monthly list, post counts, yearly grouping, dropdown markup, unique dropdown ids per render, empty-state notice.
  • EnabledBlockNamesTest: snapshot updated for the three new entries; comment notes G4b promotion.

Tests use anonymous-class subclasses that override the fetch methods to inject synthetic data, so the suite proves the rendering pipeline without coupling to cms-framework's models or pulling cms-framework into the dev deps.

Documentation

  • Inline code documentation added
  • Audit doc updated

Documentation details:

  • docs/block-library-audit.md removes the three blocks from the empty-state-deferred table and adds a new "G4b — re-enabled" subsection covering the architecture (DynamicBlock pathway, four-surface render, archive URL pattern, host-override path, deferred-entities deviation).
  • Inline PHPDoc + comments on each new block class explaining the supported attributes and the divergence from upstream behavior.

Pre-Submission Checklist

  • Followed contributing guidelines
  • Code passes all tests
  • Code follows project style guide
  • Self-review completed
  • Comments added for complex code
  • No new warnings generated

Summary by CodeRabbit

  • New Features

    • Re-enabled Categories, Tag Cloud, and Archives blocks with server-rendered previews and editor controls.
    • Added editor controls for Archives (list/dropdown, post counts, labels), Categories (hierarchy, post counts, top-level filtering), and Tag Cloud (font sizing, tag limits, post counts).
  • Documentation

    • Updated block-library docs to reflect taxonomy/feed widget availability and behavior.
  • Tests

    • Added unit tests for Archives, Categories, and Tag Cloud; updated enabled-blocks snapshot.

Re-enable the three taxonomy/feed widgets that the M5 audit deferred to
"empty-state — disabled by default" until cms-framework lands. Each
block ships as a `DynamicBlock` subclass under `src/Blocks/Core/` that
reads from cms-framework's `PostCategory`, `PostTag`, and `Post` models
respectively. Registration is gated on `class_exists(BlogManager::class)`
so the package still boots standalone — without cms-framework the
blocks stay deferred and the deny-list keeps them out of the inserter.

Editor preview, Blade renderer, React renderer, and Vue renderer all
resolve through the same `DynamicBlock::render()` path: the renderers
post to `/visual-editor/api/blocks/preview`, the controller routes
through the dynamic-block registry, and the registered block emits
HTML. One implementation, all four surfaces.

The upstream `core/categories`, `core/tag-cloud`, and `core/archives`
Edit components depended on shim surface that does not exist in V1
(`getTaxonomies`, `getTaxonomy('category').labels`, and the
`wp/v2/block-renderer/{name}` route). A new
`taxonomy-archive-block-overrides.tsx` module registers a
`blocks.registerBlockType` filter (BEFORE `registerCoreBlocks()`) that
swaps each block's `edit` with a thin wrapper using the existing
`ServerSideRender` shim, plus a minimal `InspectorControls` panel for
the toggles each block actually persists. Block save() shape stays
untouched so attribute round-trip is unaffected.

The taxonomy entity registration called for in #401's notes is
intentionally not added — the upstream Edit components all render
through `ServerSideRender`, so they never query
`useEntityRecords('taxonomy', 'category')`. Shim entities can be
layered in cheaply later if a future block needs them.

Tests: 484 PHP + 970 JS, all green. New coverage:
- CategoriesBlockTest: flat list, hierarchy, post counts, empty-term
  filter, top-level filter, empty shell, XSS escape.
- TagCloudBlockTest: link rendering, font scaling, equal-count
  collapse, empty-tag filter, count display, numberOfTags clamp,
  empty paragraph, XSS escape.
- ArchivesBlockTest: monthly list, post counts, yearly grouping,
  dropdown, unique dropdown ids per render, empty-state notice.

Closes #401

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 30, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Re-enables three core widget blocks (core/archives, core/categories, core/tag-cloud) by adding server-rendered DynamicBlock classes, registering those blocks conditionally in the service provider, adding editor-side overrides that use ServerSideRender previews, and moving the blocks from disabled to enabled lists; docs and tests updated accordingly.

Changes

Cohort / File(s) Summary
Configuration & Audit Docs
config/visual-editor.php, docs/block-library-audit.md
Moved core/categories, core/tag-cloud, core/archives from deny-list to enabled_blocks; updated audit docs to document DynamicBlock-based re-enablement and cms-framework gating (BlogManager).
Server-side Dynamic Blocks
src/Blocks/Core/ArchivesBlock.php, src/Blocks/Core/CategoriesBlock.php, src/Blocks/Core/TagCloudBlock.php
Added three DynamicBlock subclasses implementing validation, queries, and HTML rendering: archives (monthly/yearly list or dropdown), categories (hierarchical/flat list, optional counts), tag-cloud (font-size scaling by post count).
Service Provider Registration
src/VisualEditorServiceProvider.php
Added registerTaxonomyAndArchiveBlocks() and now conditionally registers the three dynamic blocks during boot when BlogManager exists.
Editor Overrides & Boot
resources/js/visual-editor/editor/taxonomy-archive-block-overrides.tsx, resources/js/visual-editor/editor/editor-app.tsx, resources/js/visual-editor/site-editor/site-editor-app.tsx
Introduced registerTaxonomyAndArchiveBlockOverrides() that wraps core Edit components with InspectorControls and ServerSideRender previews; invoked before registerCoreBlocks() and removed the three blocks from client-side disabled lists.
Tests & Test Mocks
resources/js/visual-editor/site-editor/__tests__/site-editor-app.test.tsx, tests/Unit/VisualEditor/Blocks/Core/*, tests/Unit/VisualEditor/EnabledBlockNamesTest.php
Added unit tests for Archives/Categories/TagCloud blocks, updated enabled-block snapshot, and mocked the new editor override module in site-editor tests.

Sequence Diagram

sequenceDiagram
    participant User as Editor User
    participant EditorUI as Editor Override<br/>(React Component)
    participant SSR as ServerSideRender
    participant BlockServer as PHP DynamicBlock<br/>(render endpoint)
    participant DB as Database

    User->>EditorUI: Change block attributes
    EditorUI->>EditorUI: setAttributes()
    EditorUI->>SSR: Request preview (attributes)
    SSR->>BlockServer: POST render request
    BlockServer->>DB: Query posts/categories/tags
    DB-->>BlockServer: Return data
    BlockServer->>BlockServer: Validate & build HTML
    BlockServer-->>SSR: Return rendered HTML
    SSR-->>EditorUI: Display preview
    EditorUI-->>User: Show live preview
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hop-hop, the tags and archives sing,

Categories bloom in spring-time ring,
Server-side previews glow and play,
Three blocks leap back into the day,
I nibble code and dance away.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 43.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically identifies the main change: re-enabling three taxonomy/feed blocks (core/archives, core/categories, core/tag-cloud) as part of feature G4b.
Linked Issues check ✅ Passed All coding objectives from issue #401 are met: three blocks implemented as DynamicBlock classes with server-side renderers [#401], registration gated on BlogManager presence [#401], config/visual-editor.php and JS disabled lists updated to remove the three blocks [#401], editor overrides wired via ServerSideRender [#401], archive data integrated via DynamicBlock::render [#401], and unit tests added [#401].
Out of Scope Changes check ✅ Passed All changes align with issue #401 scope: three block implementations, registration gating, configuration updates, editor overrides, and test additions; no custom-taxonomy support or advanced font-size features are included, consistent with stated out-of-scope items [#401].

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch enhancement/401-re-enable-archives-categories-tag-cloud

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 PHPStan (2.1.51)

PHPStan was skipped because the sandbox runner could not parse its output.


Review rate limit: 4/5 reviews remaining, refill in 12 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@ViewFromTheBox ViewFromTheBox moved this from Backlog to In Review in ArtisanPack UI Overview Apr 30, 2026
@ViewFromTheBox ViewFromTheBox linked an issue Apr 30, 2026 that may be closed by this pull request
6 tasks
@ViewFromTheBox
ViewFromTheBox marked this pull request as ready for review April 30, 2026 20:20

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
resources/js/visual-editor/site-editor/site-editor-app.tsx (1)

161-176: ⚠️ Potential issue | 🟠 Major

Filter won't apply if core blocks are already registered before site-editor boots

The registerTaxonomyAndArchiveBlockOverrides() filter is installed before the conditional registerCoreBlocks() call, but filters on blocks.registerBlockType only intercept active registrations. If core/paragraph (or other core blocks) already exist in the registry—whether pre-loaded by a host app or registered via another import—the conditional skips registerCoreBlocks() entirely, so the filter never runs for those blocks and the override edit components won't be applied.

Unlike editor-app.tsx, which calls registerCoreBlocks() unconditionally (ensuring the filter always applies), the site-editor's conditional approach creates a window where pre-registered blocks bypass the override mechanism.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@resources/js/visual-editor/site-editor/site-editor-app.tsx` around lines 161
- 176, The issue is that registerTaxonomyAndArchiveBlockOverrides() is run
before a conditional registerCoreBlocks() call so blocks already in the registry
(e.g., detected by getBlockType('core/paragraph')) never get the override; fix
by ensuring core blocks are always processed: either call registerCoreBlocks()
unconditionally (remove the getBlockType(...) guard) or, if you must keep the
guard, after registering the filter explicitly iterate existing registered
blocks and apply the same override logic to any matching core blocks (use the
same override function that targets blocks.registerBlockType). Update
references: registerTaxonomyAndArchiveBlockOverrides, registerCoreBlocks,
getBlockType, and the blocks.registerBlockType override handler so the override
always reaches already-registered core blocks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Blocks/Core/ArchivesBlock.php`:
- Around line 175-209: renderDropdown currently outputs a <select> with archive
URLs in option values but no client-side navigation, so add an inline onchange
handler on the <select> in renderDropdown (use the $dropdownId/select markup
built in renderDropdown) that navigates when a value is selected (e.g.
onchange="if(this.value) location.href=this.value"), ensuring you still escape
$dropdownId with e() and keep existing escaped option values; alternatively
document that hosts must provide their own navigation script if you prefer not
to inline.

In `@tests/Unit/VisualEditor/Blocks/Core/TagCloudBlockTest.php`:
- Around line 8-16: The test fixture function fakeTag builds a tag object with a
permalink property, but the block renderer expects a url property for anchor
hrefs; update fakeTag to set url (and optionally keep permalink for
compatibility) — replace or add $tag->url = '/blog/tag/' . $slug; (also adjust
the other occurrences around lines 25-31 where tag objects are created) so
assertions exercise the renderer's actual link field.

---

Outside diff comments:
In `@resources/js/visual-editor/site-editor/site-editor-app.tsx`:
- Around line 161-176: The issue is that
registerTaxonomyAndArchiveBlockOverrides() is run before a conditional
registerCoreBlocks() call so blocks already in the registry (e.g., detected by
getBlockType('core/paragraph')) never get the override; fix by ensuring core
blocks are always processed: either call registerCoreBlocks() unconditionally
(remove the getBlockType(...) guard) or, if you must keep the guard, after
registering the filter explicitly iterate existing registered blocks and apply
the same override logic to any matching core blocks (use the same override
function that targets blocks.registerBlockType). Update references:
registerTaxonomyAndArchiveBlockOverrides, registerCoreBlocks, getBlockType, and
the blocks.registerBlockType override handler so the override always reaches
already-registered core blocks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2424352f-a2b8-497c-b0b7-c29f759a496d

📥 Commits

Reviewing files that changed from the base of the PR and between 33d3efc and 3eb5715.

📒 Files selected for processing (14)
  • config/visual-editor.php
  • docs/block-library-audit.md
  • resources/js/visual-editor/editor/editor-app.tsx
  • resources/js/visual-editor/editor/taxonomy-archive-block-overrides.tsx
  • resources/js/visual-editor/site-editor/__tests__/site-editor-app.test.tsx
  • resources/js/visual-editor/site-editor/site-editor-app.tsx
  • src/Blocks/Core/ArchivesBlock.php
  • src/Blocks/Core/CategoriesBlock.php
  • src/Blocks/Core/TagCloudBlock.php
  • src/VisualEditorServiceProvider.php
  • tests/Unit/VisualEditor/Blocks/Core/ArchivesBlockTest.php
  • tests/Unit/VisualEditor/Blocks/Core/CategoriesBlockTest.php
  • tests/Unit/VisualEditor/Blocks/Core/TagCloudBlockTest.php
  • tests/Unit/VisualEditor/EnabledBlockNamesTest.php

Comment thread src/Blocks/Core/ArchivesBlock.php
Comment on lines +8 to +16
function fakeTag( int $id, string $name, string $slug, int $count ): object
{
$tag = new stdClass();
$tag->id = $id;
$tag->name = $name;
$tag->slug = $slug;
$tag->posts_count = $count;
$tag->permalink = '/blog/tag/' . $slug;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Tag fixture shape doesn’t match renderer link field

The test fixture sets permalink, but the block renderer reads url for anchor href. This makes link assertions brittle/failing against the actual render contract.

Proposed fix
 function fakeTag( int $id, string $name, string $slug, int $count ): object
 {
 	$tag              = new stdClass();
 	$tag->id          = $id;
 	$tag->name        = $name;
 	$tag->slug        = $slug;
 	$tag->posts_count = $count;
-	$tag->permalink   = '/blog/tag/' . $slug;
+	$tag->url         = '/blog/tag/' . $slug;
+	$tag->permalink   = '/blog/tag/' . $slug;
 
 	return $tag;
 }

Also applies to: 25-31

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Unit/VisualEditor/Blocks/Core/TagCloudBlockTest.php` around lines 8 -
16, The test fixture function fakeTag builds a tag object with a permalink
property, but the block renderer expects a url property for anchor hrefs; update
fakeTag to set url (and optionally keep permalink for compatibility) — replace
or add $tag->url = '/blog/tag/' . $slug; (also adjust the other occurrences
around lines 25-31 where tag objects are created) so assertions exercise the
renderer's actual link field.

CodeRabbit flagged that `renderDropdown()` emits a `<select>` whose
options carry archive URLs but no client-side navigation, so picking a
value did nothing. Add an inline `onchange` handler that mirrors
upstream `core/archives` behaviour:
`onchange="if(this.value)document.location.href=this.value"`.

Hosts under a strict CSP that forbids inline handlers can rebind this
block via the dynamic-block registry to emit a data-attribute hook
plus a host-supplied script instead — documented inline.

Tests:
- New "attaches an inline onchange handler so the dropdown navigates
  on select" case asserting the literal handler string survives.
- Existing dropdown-markup case tightened to require the `onchange`
  attribute on the `<select>`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Blocks/Core/ArchivesBlock.php`:
- Around line 126-137: The decorate method is building archive URLs with a
hard-coded '/blog' prefix; update it to use a configurable route prefix instead
of '/blog' so custom blog routes won't 404. Replace the literal '/blog' in the
two url(...) calls inside decorate with a value read from configuration or a
class property (e.g., use config('blog.route', 'blog') or $this->routePrefix)
and ensure padding/formatting (sprintf('/%s/%04d'...) and
sprintf('/%s/%04d/%02d'...)) preserves behavior; update any related class
property or constructor to provide the default fallback if not configured.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 605ea541-2ec5-4a7e-8c9f-f4bfad54ab0c

📥 Commits

Reviewing files that changed from the base of the PR and between 3eb5715 and 6135549.

📒 Files selected for processing (2)
  • src/Blocks/Core/ArchivesBlock.php
  • tests/Unit/VisualEditor/Blocks/Core/ArchivesBlockTest.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/Unit/VisualEditor/Blocks/Core/ArchivesBlockTest.php

Comment on lines +126 to +137
protected function decorate( array $bucket ): array
{
if ( null === $bucket['month'] ) {
$bucket['label'] = (string) $bucket['year'];
$bucket['url'] = url( sprintf( '/blog/%04d', $bucket['year'] ) );

return $bucket;
}

$bucket['label'] = Carbon::create( $bucket['year'], $bucket['month'], 1 )->translatedFormat( 'F Y' );
$bucket['url'] = url( sprintf( '/blog/%04d/%02d', $bucket['year'], $bucket['month'] ) );

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid hard-coded archive URLs; this can break links on non-default blog routes.

On Line 130 and Line 136, URLs are hard-coded to /blog/..., but the class doc says route customization should be supported via config/rebinding. On installs with custom archive routes, these links can 404.

💡 Suggested fix (fallback-safe configurable patterns)
 protected function decorate( array $bucket ): array
 {
+	$yearlyPattern  = (string) config( 'visual-editor.archive_url_pattern_yearly', '/blog/%04d' );
+	$monthlyPattern = (string) config( 'visual-editor.archive_url_pattern_monthly', '/blog/%04d/%02d' );
+
 	if ( null === $bucket['month'] ) {
 		$bucket['label'] = (string) $bucket['year'];
-		$bucket['url']   = url( sprintf( '/blog/%04d', $bucket['year'] ) );
+		$bucket['url']   = url( sprintf( $yearlyPattern, $bucket['year'] ) );

 		return $bucket;
 	}

 	$bucket['label'] = Carbon::create( $bucket['year'], $bucket['month'], 1 )->translatedFormat( 'F Y' );
-	$bucket['url']   = url( sprintf( '/blog/%04d/%02d', $bucket['year'], $bucket['month'] ) );
+	$bucket['url']   = url( sprintf( $monthlyPattern, $bucket['year'], $bucket['month'] ) );

 	return $bucket;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
protected function decorate( array $bucket ): array
{
if ( null === $bucket['month'] ) {
$bucket['label'] = (string) $bucket['year'];
$bucket['url'] = url( sprintf( '/blog/%04d', $bucket['year'] ) );
return $bucket;
}
$bucket['label'] = Carbon::create( $bucket['year'], $bucket['month'], 1 )->translatedFormat( 'F Y' );
$bucket['url'] = url( sprintf( '/blog/%04d/%02d', $bucket['year'], $bucket['month'] ) );
protected function decorate( array $bucket ): array
{
$yearlyPattern = (string) config( 'visual-editor.archive_url_pattern_yearly', '/blog/%04d' );
$monthlyPattern = (string) config( 'visual-editor.archive_url_pattern_monthly', '/blog/%04d/%02d' );
if ( null === $bucket['month'] ) {
$bucket['label'] = (string) $bucket['year'];
$bucket['url'] = url( sprintf( $yearlyPattern, $bucket['year'] ) );
return $bucket;
}
$bucket['label'] = Carbon::create( $bucket['year'], $bucket['month'], 1 )->translatedFormat( 'F Y' );
$bucket['url'] = url( sprintf( $monthlyPattern, $bucket['year'], $bucket['month'] ) );
return $bucket;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Blocks/Core/ArchivesBlock.php` around lines 126 - 137, The decorate
method is building archive URLs with a hard-coded '/blog' prefix; update it to
use a configurable route prefix instead of '/blog' so custom blog routes won't
404. Replace the literal '/blog' in the two url(...) calls inside decorate with
a value read from configuration or a class property (e.g., use
config('blog.route', 'blog') or $this->routePrefix) and ensure
padding/formatting (sprintf('/%s/%04d'...) and sprintf('/%s/%04d/%02d'...))
preserves behavior; update any related class property or constructor to provide
the default fallback if not configured.

@ViewFromTheBox
ViewFromTheBox merged commit 042d01e into release/1.0 Apr 30, 2026
1 check passed
@ViewFromTheBox
ViewFromTheBox deleted the enhancement/401-re-enable-archives-categories-tag-cloud branch April 30, 2026 21:16
@github-project-automation github-project-automation Bot moved this from In Review to Done in ArtisanPack UI Overview Apr 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

G4b — Re-enable core/archives, core/categories, core/tag-cloud

1 participant