DC37 Block Variations¶
web/app/plugins/dc37-block-variations
This plugin registers all custom block variations, editor plugins, and server-side render filters for the DC37 site. Variations extend core WordPress blocks with pre-configured attributes, inner block templates, and custom inspector controls. Server-side PHP filters add interactivity directives and runtime logic that cannot be handled in JS alone.
The single compiled editor script (build/dc37-block-variations-editor.js) is enqueued on every admin screen via enqueue_block_assets. PHP includes are auto-loaded from src/*/*.php at plugin boot.
Plugin-level PHP hooks¶
Registered in dc37-block-variations.php.
dc37_post_selector_add_rest_order¶
Adds post__in as a valid orderby value to the REST API collection params for all public post types. Required to allow the curated Query Loop variations (news-feature, curated-single-post, legislative-priorities, page-embed) to order results by a manually specified ID list.
dc37_render_query_block¶
A pre_render_block filter that attaches a query_loop_block_query_vars filter when any of the curated Query Loop namespaces are about to render (dc37/news-feature, dc37/news-list, dc37/legislative-priorities, dc37/page-embed). The inner filter sets post__in and orderby: post__in from the block's include context, ensuring the front-end query respects the manually selected post order.
Block binding render filters (dc37_modify_block_local_bindings)¶
A render_block_core/paragraph filter that post-processes bound paragraphs for three local post meta keys, converting raw stored values into properly formatted HTML:
| Binding key | Transform applied |
|---|---|
dc37_local_website |
Wraps the URL in <a href="…" target="_blank">Local Website</a> |
dc37_local_telephone |
Formats as <a href="tel:+1…"> with E.164 normalisation for 10/11-digit US numbers |
dc37_local_email |
Wraps a valid email in <a href="mailto:…"> |
A companion render_block_data filter (dc37_prevent_oembed_for_bound_blocks) clears the innerHTML of website-bound paragraphs before render to prevent WordPress auto-linking the raw URL as an oEmbed embed.
Block variations¶
Home page hero carousel¶
Source: src/home-hero-carousel/index.js
Three tightly coupled variations that make up the home page hero:
| Variation | Extends | Name |
|---|---|---|
Hero Carousel (dc37-splide-carousel) |
cloudcatch/splide-carousel |
dc37-splide-carousel |
Hero Carousel Item (dc37/splide-carousel-item) |
cloudcatch/splide-carousel-item |
dc37/splide-carousel-item |
Hero Slide Image (dc37/slide-image) |
core/cover |
dc37/slide-image |
The Hero Carousel pre-populates two slides on insert with wide alignment. Each slide is a Hero Carousel Item containing a Hero Slide Image (a locked Cover block used as the background). Hero Slide Image is constrained to appear only inside cloudcatch/splide-carousel-item and is locked against move and removal.
Depends on the Splide Carousel third-party plugin (cloudcatch/splide-carousel).
See the Hero pattern for the full home page hero composition.
Home page — News and Wins¶
News Feature (dc37/news-feature)¶
Source: src/news-feature/index.js | Extends: core/query
Displays a single featured post as a large card with featured image (large_three_two size), title, date, and excerpt. Supports both post and news-release post types, selectable via inspector controls with a searchable combobox. The selected post can be switched using a dropdown menu on the selected item.
Curated Single Post (dc37/curated-single-post)¶
Source: src/curated-single-post/index.js + src/curated-single-post/query-vars.php | Extends: core/query
Displays a single post of any REST-enabled post type. Inspector controls offer a post type selector and a searchable post combobox. You can only select one post per block — insert additional blocks to show more. Reorder blocks using the toolbar arrows or the block outline panel.
The query-vars.php filter (query_loop_block_query_vars) enforces the correct post_type on the front end when a non-default post type (e.g. news-release) is selected, since the core Query block does not carry non-default types through to WP_Query reliably.
Legislative Priorities (dc37/legislative-priorities)¶
Source: src/legislative-priorities/index.js | Extends: core/query
Manually curate up to three posts. Inspector controls show the current selection as a sortable list; items can be reordered with up/down buttons and removed individually. Renders using the is-style-teaser-card style with a small featured image column alongside title and excerpt.
Page Embed (dc37/page-embed)¶
Source: src/page-embed/index.js | Extends: core/query
Embeds the full content of a single selected page inside a scrollable is-style-scrollable container. Uses core/post-content as the inner template. Inspector controls offer a searchable page combobox. Useful for pulling shared content pages into other templates without duplicating them.
All four of these variations extend core/query with inherit: false, fixed perPage, and allowedControls: [] (the standard query inspector controls are hidden — post selection is entirely through the custom inspector panel). Post ordering via post__in is enabled site-wide by the dc37_post_selector_add_rest_order hook, and applied on the front end by the dc37_render_query_block / query_loop_block_query_vars filter chain.
Home page — Find Your Local¶
Source: src/local-search/index.js + render.php + view.js
Four variations that together make up the "Find Your Local" interactive feature:
| Variation | Extends | Name |
|---|---|---|
| Find Your Local (Group Wrapper) | core/group |
dc37/find-local-group-wrapper |
| Find Your Local (Search Group) | core/group |
dc37/find-local-group |
| Local Search | core/search |
dc37/local-search |
| Local Search Loop | core/query |
dc37/local-search-loop |
The Local Search block is a search form that filters union locals by name or number using an autocomplete combobox. The Local Search Loop is a Query Loop querying the local post type (perPage: 1) rendered alongside it, which updates via the WP Interactivity Router as the search param changes to show a preview card of the matched local.
The render.php filter transforms the core search form into an interactive combobox: it fetches all published locals, serialises them into WP Interactivity state, rewrites the <form> and <input> with ARIA combobox attributes and data-wp-* directives, and injects a <ul role="listbox"> of local names. The front-end store (view.js, namespace dc37/local-search) handles input filtering, listbox click selection, keyboard navigation (arrow keys, Enter, Escape), and router navigation to ?find={value}.
See the Local Search pattern for the full component composition.
Union Locals listing page — Local Filter¶
Source: src/local-filter/index.js + render.php + view.js
| Variation | Extends | Name |
|---|---|---|
| Local Filter Group | core/group |
dc37/local-filter-group |
| Local Filter Search | core/search |
dc37/local-filter |
A client-side filter for the Union Locals listing page. As the user types (minimum 3 characters), matching .details--local elements are shown and non-matching ones are hidden. Entire .section-division containers are hidden when all their locals are filtered out.
Unlike the home page Local Search, this filter makes no server requests — it operates entirely against a search index built from the data-local-name attributes already present in the rendered page DOM.
The render.php filter adds data-wp-interactive and data-wp-context directives to the group wrapper and rewrites the <form> and <input> with data-wp-on--submit and data-wp-on--input directives. The front-end store uses namespace dc37/local-filter.
See the Local Filter pattern for the full component composition.
Union Locals post meta bindings¶
Source: src/union-locals/index.js + meta.js
Local Info settings panel¶
A PluginDocumentSettingPanel sidebar panel, visible only on local post type pages, that provides editor-friendly form controls for all local meta fields. Editors use this panel instead of the generic Custom Fields interface.
Fields: Local Number (integer), Local Name, Local is an Association (toggle), President, Telephone, Email, Website, We Work As, We Work In.
Paragraph meta binding variations¶
Six core/paragraph variations that use the WordPress Block Bindings API (core/post-meta) to display local post meta fields inline in the block template. All are scoped to block (available in the block variation picker, not the main inserter). Used within the Local post type template.
| Variation | Name | Bound meta key | Front-end output |
|---|---|---|---|
| Local Number | dc37/local-number |
dc37_local_number |
Plain text |
| Local Name | dc37/local-name |
dc37_local_name |
Plain text |
| Local President | dc37/local-president |
dc37_local_president |
Plain text |
| Local Telephone Number | dc37/local-telephone |
dc37_local_telephone |
<a href="tel:+1…"> |
| Local Email | dc37/local-email |
dc37_local_email |
<a href="mailto:…"> |
| Local Website | dc37/local-website |
dc37_local_website |
<a href="…" target="_blank">Local Website</a> |
Telephone, email, and website values are post-processed by the PHP render filter in the main plugin file — see Block binding render filters.
Other union locals variations¶
| Variation | Extends | Name | Purpose |
|---|---|---|---|
| Local Post Title | core/post-title |
dc37/local-post-title |
Post title linking to the Union Locals page with a #{localNumber} hash anchor (href rewritten by dc37_arch_local_post_title_block in the architecture plugin) |
| Conditional Post Meta Group | core/group |
dc37/conditional-post-meta-group |
Group containing a heading and bound paragraph — hides itself when the bound meta value is empty, suppressing empty field rows |
| Scroll Watcher | core/group |
dc37/group-scroll-watcher |
Utility wrapper for scroll position observation on local pages |
Benefits Nav¶
Source: src/benefits-nav/index.js + render.php
| Variation | Extends | Name |
|---|---|---|
| Benefits Nav | core/buttons |
dc37/benefits-nav |
| Benefits Nav Button | core/button |
dc37/benefits-nav-button |
A pair of navigation buttons (Public Sector / Private Sector) used in the benefit page banner. The render.php filter (render_block_core/buttons) dynamically sets the button href values at render time: the current page's button gets aria-current="page" and links to the current URL; the other button links to the sibling page (derived from the parent page URL + the opposite slug). Both buttons are locked against removal.
Notice (Alert)¶
Source: src/notice-alert/index.js | Extends: core/group | Name: dc37/notice-alert
A styled alert banner with a custom circular-exclamation SVG icon, bold green heading text, and a paragraph for the message body. Scoped to the inserter. Identified by className: is-style-notice-alert.
Editor plugins¶
Editor Title Hider¶
Source: src/editor-title/index.js
Registered as a @wordpress/plugins plugin (not a block variation). For local and news-release post types, injects a <style> tag into the editor <head> that hides the .editor-post-title element. Prevents editors from seeing or interacting with the WP post title field on post types where the displayed title is generated automatically from meta (locals) or managed within the block template (news releases).
Deprecated¶
Deprecated variations have been superseded and will be removed in a future release. Do not use.
In Action (dc37/in-action)¶
Source: src/in-action/ | Extends: core/gallery
Deprecated Instagram-style gallery variation. Use the standard core/gallery block instead.
News List (dc37/news-list)¶
Source: src/news-list/ | Extends: core/query
Manually curated list of up to three posts or news releases. Superseded by dc37/curated-single-post and dc37/legislative-priorities.
