WP Manifestindependent plugin directory
manifest / unclassified / wm-gutenberg-assessment

WM Gutenberg Assessment

WordPress Gutenberg assessment plugin with filterable, paginated posts grid and REST-powered inter-block communication.

by WM · github.com/innaplx/wm-gutenberg-assessment

★ 0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/innaplx/wm-gutenberg-assessment/archive/refs/heads/main.zip

WordPress plugin for a take-home Gutenberg assessment: a filterable, paginated posts grid with inter-block communication via URL query parameters and REST-powered updates without full page reloads.

Overview

The plugin registers three dynamic blocks:

  • Posts Filter — category and tag chip controls
  • Posts Grid — server-rendered post cards (featured image, title, excerpt) with configurable columns and posts per page
  • Posts Pagination — nested inside Posts Grid as an InnerBlock

On activation, the plugin seeds demo categories, tags, posts, and a demo page that combines the filter and grid blocks.

Requirements

  • WordPress with the block editor (Gutenberg)
  • PHP compatible with your Local/site environment (WordPress 6.x recommended)
  • Node.js and npm (for building block assets)

Installation

  1. Copy this folder into wp-content/plugins/wm-gutenberg-assessment.
  2. From the plugin directory, run npm install.
  3. Run npm run build to compile blocks into build/blocks/.
  4. In Plugins, activate WM Gutenberg Assessment.
  5. Open the seeded demo page The Internet Survival Guide (created on first activation).

Development

  • npm run start — watch mode for block JavaScript/CSS during development.
  • npm run build — production build; required before testing PHP-rendered pages that load scripts from build/blocks/.

Blocks

Block name Purpose
wm/posts-filter Toggle categories/tags; Reset clears filters
wm/posts-grid Displays filtered posts; provides postsPerPage to inner blocks
wm/posts-pagination Previous / numbered pages / Next; InnerBlock of Posts Grid only

Pagination is not a standalone sibling on the demo page—it lives inside the grid block in the editor and in saved markup.

Inter-block communication

Filter and Grid are independent sibling blocks on the page. They do not nest inside each other. Shared state is the URL query string:

Parameter Meaning
wm_categories Comma-separated category term IDs
wm_tags Comma-separated tag term IDs
wm_page Current page (omitted when page 1)

Filter semantics (implemented in WM_Query):

  • OR among selected categories
  • OR among selected tags
  • AND between the category group and the tag group

The URL is the source of truth for filters and pagination. Server-side rendering on first load reads the same parameters from $_GET.

REST API

Endpoint: GET /wp-json/wm/v1/posts

Used by the filter block’s frontend script to refresh the grid and pagination after filter or pagination interactions without reloading the page.

Parameter Description
categories Comma-separated category IDs (optional)
tags Comma-separated tag IDs (optional)
page Page number (default 1)
per_page Posts per page (1–20, should match grid attribute)
context_url Required. Current page URL without wm_* params; used to build correct pagination links

Response (JSON):

  • grid_html — server-rendered post cards
  • pagination_html — server-rendered pagination markup (empty when one page)
  • current_page, total_pages

HTML fragments are returned so post cards and pagination reuse the same PHP rendering and escaping as the initial page (WM_Posts_Render), instead of duplicating WordPress template logic in JavaScript.

The endpoint is read-only, returns published posts only, and uses a public permission_callback appropriate for that scope.

History / AJAX behavior

  • Filter changes and pagination clicks fetch the REST endpoint and swap grid/pagination HTML.
  • Successful updates use history.pushState so the address bar matches the new filters/page.
  • Browser Back and Forward use popstate to fetch the state implied by the URL.
  • The first paint is fully server-rendered; JavaScript enhances behavior after load.

If a REST request fails, the visible grid and URL stay aligned with the last successful state (see limitations in tradeoffs).

Seeder

On plugin activation (WM_Seeder):

  • Creates demo categories and tags (idempotent by slug)
  • Creates 12 demo posts with excerpts, categories/tags, and featured images (idempotent by wm-demo-* slugs)
  • Creates demo page The Internet Survival Guide with filter + grid (including pagination InnerBlock)
  • Stores wm_demo_page_id and wm_seeder_version

Re-activation does not duplicate posts or terms. Existing demo page content is not rewritten if the page already exists.

Architecture

WM_Query          → filter state, tax_query, WP_Query args (SSR + REST)
WM_Posts_Render   → grid cards + pagination HTML
Block render.php  → Gutenberg composition and attributes
WM_REST_API       → AJAX transport; returns HTML fragments
posts-filter/view.js → REST fetch, History API, DOM updates

Frontend interaction logic is enqueued with the Posts Filter block (viewScript); it also drives grid and pagination on pages that include both filter and grid (as on the demo page).

Tradeoffs / limitations

  • Filter script dependency — AJAX filtering/pagination requires the filter block (and its script) on the same page as the grid.
  • REST returns HTML fragments — avoids duplicating rendering in JS; tradeoff is replacing innerHTML rather than fine-grained DOM diffing.
  • Server-rendered first load — good for progressive enhancement; crawlers that do not run JS see the initial filter/page state only.
  • Filter UI requires JavaScript — no non-JS fallback for chip toggles.
  • SSR pagination count — grid and pagination inner block each run a query on full page load (pagination runs before the grid render callback in the block tree); REST reuses max_num_pages from the main query to avoid a duplicate count query.