v1.9.0
Added — src:site unified site-wide source (Stage A)
- New
src:sitesource value on thetext,title,permalink,image,content,datetime_single, anddatetime_rangebase tags — one source + one mental model for site-wide data, replacing the need to remember GB Pro's separate{{site_title}}/{{site_tagline}}/{{site_logo_url}}/{{site_url}}/{{option}}tags.useis the analog-vs-option lever (uniform with every other source), not key-presence; there is nouse:optionvalue (src:siteselects the wp_options namespace the waysrc:currentselects post meta). An empty wireuseresolves to the tag's stripped first-enum value:-
text: stripped default = key-mode —{{text src:site|key:X}}reads a wp_options value;use:title→ site name; bare/no-key → empty. (Nouse:tagline— it fails the qualifying test both ways: no unique value over GB's native{{site_tagline}}, and no strong cross-source analog. Reach it there or viakey:blogdescription. Seedocs/tag-reference.md§Qualifying test.) -
title: site name (get_bloginfo('name')); nouse/key. -
permalink: site home URL (home_url()); nouse/key(the site's own URL, never an option read;site_url()is not exposed this release). -
image: stripped default = key-mode →use:key/{{image src:site|key:X}}reads an attachment-ID wp_options value; the site logo is the explicituse:featuredvalue (customizer custom-logo, fullas:/size:) — bare{{image src:site}}is key-mode and resolves empty without a key, not the logo. (featuredstays explicit/serialized so the empty wire is an unambiguous key-mode signal; a stripped-default logo would be indistinguishable from a stale key. Reliable token authority is deferred to the custom-control work — see SPEC §B6.) -
content: no site content analog — site has no long-form body datum (the site "description" is the Tagline, a short string), so thecontentdefault anduse:excerptboth resolve empty.contentis only meaningful undersrc:sitewithuse:key→ a wp_options read through thebws_render_block_contententry shipped in 1.8.0 (do_blocks+ sanitize + recursion guard, keyed'option:'.$key), so block-markup options (e.g. an ACF Extended block-editor field on an options page) execute rather than printing raw markup.The analogs parallel post→{title, content, permalink, featured} and term→{name, description, URL, —}, except: the site image analog (logo) is reached by explicit
use:featuredrather than the bare tag; and the site has no content-body analog ({{content src:site}}→ empty). The site Tagline (blogdescription) is a short string with no tag path here — use GB native{{site_tagline}}or{{text src:site|key:blogdescription}}. Seedocs/tag-reference.md§Source-analog resolution. -
datetime_single/datetime_range: read ACF options-page date fields viaget_field($key,'option')(thekey/endcontrols), recovering the field's ACF return format through the normal format chain. Primary driver: ACF options-page date fields.
-
- Link wrapping for site sources (
text,title,datetime_*): undersrc:site,linkTo:permalinkresolves tohome_url()— the site permalink-analog, matching field-unserialized{{permalink src:site}}(no separatelinkTo:sitevalue; permalink already IS the site's canonical URL).linkTo:keyreads an option-stored URL (allowlist-gated).
Added — {{email}} base tag
- New
emailbase tag — outputs a stored email address, by default wrapped in amailto:link, cross-source liketext(highest value undersrc:sitefor an org contact email in a wp_options / ACF-options field). Key-required in every source (no analog, nouseenum). Reuses the 1.8.0 field-read path, so it benefits fromsrc:sitewithout touching site code. Specific behavior:mailto:wrap is default-ON, toggled off by the inverted bare keynoLink({{email …|noLink}}→ plain text). Built as a minimal anchor — nolinkTo/ target / class (WP emits no class on mailto links either).subject— optionalmailto:?subject=line via thebws-format-inputcontrol; survives GB's tag-string round-trip (escaped editor-side, unescaped by GB server-side) and israwurlencoded into the query at render.- Obfuscation — addresses run through
antispambot()on both display and href, controlled by a new global Settings → Tag Extensions → Email toggle (default on; disable for a cleanmailto:href). - Validation + fallback —
is_email()-validated; thefallbackoption is a fallback email address (validated, wrapped like a real address). List mode (srcTermIn/src:ref) wraps each valid address individually and joins bysep; fallback fires only when no valid address resolves. visibilitygate — hidden in the tag selector ona/button/img/pictureelements (first nativevisibilityuse in the plugin, mirroring GB core'sterm_list). Seedocs/tag-reference.md§Email tag. Follow-ups:img/picturegate for text/title/datetime (#31),try_emailparity (#32).
Changed — editor labels
- The
use:keyvalue and the field-key control now read "Meta/Option Field" acrosstext,image, andcontent(was "Meta/Custom Field" / "Custom Content Field (WYSIWYG/Blocks)" / "Field Key") — the same control now reads post/term meta or a wp_options / ACF-options value undersrc:site, so the label tracks that widened scope. The WYSIWYG/Blocks rendering note moved to the field-key help text. Analogusevalues name every source: image "Featured Image/Site Logo", content "Post Content/Term Description". Link-target control + value "URL Meta Field" → "URL Meta/Option Field". (Nomenclature: field is generic; meta/option are the subtype pair.) try_multi-slot labels front-load the slot ordinal as anN:prefix (e.g.2: Meta/Option Field,2: Source) for legibility — was a trailingNsuffix /Source N:prefix mix.- Spaced slashes normalized to tight slashes in user-facing labels (
Title / Name→Title/Name,Date / Time→Date/Time, etc.). - Field-key controls now carry "Key" in the label to distinguish them from the selector options they sit beside: field-key control "Meta/Option Field Key" (was "Meta/Option Field"), relationship-field control "Relationship Field Key", link-URL control "URL Meta/Option Field Key", and the datetime field keys "Date/Time Field Key" / "Start Date/Time Field Key" / "End Date/Time Field Key" (+ "… Time Field Key (optional)" variants). The
src/use/linkToselector option labels are unchanged (e.g.use:keystays "Meta/Option Field",linkTo:keystays "URL Meta/Option Field") — only the key-entry fields gained "Key".try_per-slot equivalents follow (N: Meta/Option Field Key,N: Relationship Field Key).
Security — site option reads gated by a GB-Pro-parity allowlist
- All site option reads (site option key-mode, site
linkTo:key, and the datetimeget_field(…,'option')read) pass through thegenerateblocks_dynamic_tags_allowed_optionsfilter, seeded to GB Pro parity: the six WP defaults (siteurl,blogname,blogdescription,home,time_format,user_count) plus every registered ACF options-page field (registration is the opt-in — ACF option fields read with no manual filter).GenerateBlocks_Meta_Handler::get_option()enforces a blocklist only (not this allowlist), so the gate is the resolver's responsibility — seedocs/adr/0001-site-option-read-allowlist.md. Mirrors GB Pro's{{option}}behavior sosrc:siteis not gratuitously stricter than the tag it replaces.
Fixed
limit/sep(list-mode controls on basetextandtitle) were shown unconditionally, including for scalar sources that can only ever return one value. They now carryshow_if_any => { srcTermIn: not_empty, src: ref }— visible only when the final traversal step can yield multiple results (terms viasrcTermIn, or related posts atsrc:ref). Pre-existing over-exposure; surfaced and broadened bysrc:site, which hides bothrefandsrcTermInand so now also hideslimit/sep. Seedocs/tag-reference.md§List mode.bws_parse_combined_date_timepassed the numeric-coerced id to the field value read, so a non-numeric ACF object-id sentinel ('option') was lost before reachingbws_read_field. The value read now threads the'option'sentinel independently of the format-lookup object-id. (Prerequisite for site-datetime; no effect on existing post/term/loop callers.)- Site
linkTo:key({{… src:site|linkTo:key|linkKey:…}}) read the option through a rawget_option()instead of the reader the value path uses, so it lacked dot-path traversal and the ACFget_fieldfilter — ACF options-group subfields (e.g.organization_social.facebook) resolved as a value but failed when used as a link target. Both site wp_options reads (key-mode value +linkTo:key) now share one canonical reader (bws_site_read_option), so the value and the link always agree.