Skip to content

v1.19.0

Choose a tag to compare

@github-actions github-actions released this 01 Sep 21:13
· 33 commits to main since this release

Highlights

  • Tags used on pages and query loop items that don't resolve to a post ID now return a context-appropriate result!

    • Current-context Title tags on archives, search results, 404 pages and the blog home return the archive label, date span, search heading, or site name, not the query's first post's title. (Fixed)
    • The Content tag now shows a post type archive's registered description. (Added)
    • On a 404 page, Title and Content borrow GeneratePress's "not found" text, falling back to WP's. (Added)
    • A Try Text tag can fall back to the page's own heading, so one tag works site-wide across custom headings and archive/search/404 titles alike. (Added)
    • Tags inside a query loop over terms or users now read that term or user, not a post that happened to share its ID. (Fixed)
  • One trade-off: Tags used in a WooCommerce product loop previously worked by coincidence, but now render nothing. We plan to address this in a future release. (Changed)

  • When another plugin registers one of this plugin's tag names, the settings page now names which plugin's version of the tag is actually active and the file it was registered in, so the report names something you can go and deactivate. (Added)

  • Calling bws_get_loop_row_context() from your own code? It is bws_get_loop_item_context() now, with no compatibility alias. Search any custom code for the old name before you update. (Changed)

Added

  • The Content tag now shows a post type's archive description. On a post type archive, {{content}} renders the description set on the post type's registration, formatted the way WordPress formats it. It had rendered whatever post led the archive's query (see Fixed below).
  • On a 404 page, the Title and Content tags borrow the theme's own "not found" text. With GeneratePress active, {{title}} renders the heading GP's 404 template shows, including any customization a site made through GP's generate_404_title filter, and {{content}} does the same with generate_404_text. Without GeneratePress, the title falls back to WordPress's own "Page not found" and the content renders nothing.
  • A Try Text tag can fall back to the page context's own heading. {{text use:title}} and a try_text attempt set to the Title field now resolve on archives, search results, 404 pages and the blog home, returning the same value as {{title}} there. A try_text tag reading a custom heading field first and the Title field second gives a site-wide header that uses an author's custom heading where one is set and the context's canonical title everywhere else, which {{title}} alone cannot express.
  • A tag name this plugin shares with another plugin is now reported, in both directions. The base tags deliberately register over a name another plugin already holds, because standing down would make {{text}} silently cease to exist on every page using it. That overwrite now announces itself through WordPress's standard incorrect-usage channel, naming the tag and the other plugin, instead of happening quietly. The other direction is the one that could not be detected at all: a plugin registering one of these names after this plugin's registration pass takes the tag over on every block already using it, and nothing anywhere said so. A late re-read now catches that and reports it the same way. Both reports need WP_DEBUG and go to the debug log; the Tag Name Conflicts subsection below is the surface that does not.
  • A documented tag of this plugin's that does not exist on your site is now reported too. The term_ and try_ tags stand down from a name another plugin already holds rather than registering over it, and until now they did it silently: the tag was simply absent from the editor's tag list, with nothing anywhere saying why, and documentation describing it did not apply on that site. It is now recorded and reported like the two directions above. A stand-down is not a guarantee that nothing changed. It is recorded on every request once the other plugin is present, including on a site whose blocks were already using this plugin's tag under that name; those blocks now render through the other plugin's code, carrying settings it never defined. What the report tells you is which plugin answers for the name, not whether your output moved. This is live on any site running GB Query Enhancements, which holds term_title.
  • Settings > Tag Extensions gains a read-only Tag Name Conflicts report, under Diagnostics. It lists any tag name that collided on that page load, which plugin's version of the tag is the one actually active, and the file that plugin registered it in. The plugin is named from that file, so it names something you can go and deactivate rather than the other tag's label. It changes no setting and no output. It exists because the developer-facing reports above need WP_DEBUG and a log file, which is not where a site owner debugging a live install will look.
  • For plugin developers: bws_loop_item_is_post_or_row() is a new published helper. It answers whether the current query-loop item is one a post-meta or repeater read can be served from: true for a post and for a repeater row, false for a term, a user, and an item whose shape is not recognized. That is the question the in_loop flag used to answer by accident, so this is what you want if you branch on in_loop alone before skipping a "no entity, give up" bail. See docs/plugin-integration.md §Field helpers.

Changed

  • Tags inside a WooCommerce product loop now render nothing. A query loop's item is now identified by its shape, and four shapes are read: a post, a term, a user and a repeater row. WooCommerce's product loop hands over a shape matching none of them, and an item this plugin cannot identify resolves to nothing rather than to whatever the surrounding page holds. Those loops had been rendering the right thing by arithmetic coincidence, since a product ID is also a post ID. That same coincidence is what made term and user loops read an unrelated post (see Fixed below), so a shape we cannot identify saying nothing is the point of the change and not collateral damage from it. Restoring product loops is planned for a future release.
  • For plugin developers: bws_get_loop_row_context() is now bws_get_loop_item_context(), and the row_post_id key it returns is now item_post_id. There is no compatibility shim, no alias and no deprecation notice, so a call to the old name is a fatal error rather than a warning. Search your own code for bws_get_loop_row_context and row_post_id before updating. The old names said "row", which stopped being true once the helper began reporting terms and users as well as posts and repeater rows.
  • bws_get_loop_item_context() reports more than it used to, and in_loop no longer means what it did. Two keys are new, item_kind and item_id, carrying the loop item's own entity. The post ID key still holds a post and only a post, so its meaning did not move; only its name did, which is the rename above. What changed is in_loop: it is now true for a term, a user and an unrecognized item, where before it meant "in a loop with a post or a repeater row behind it". Code branching on in_loop alone to decide whether a post-meta read can serve is now wrong on three item kinds. If you want the old meaning, bws_loop_item_is_post_or_row() is it, rather than a rewritten condition of your own.

Fixed

  • Bare tags on archives, search results, 404 pages and the blog home no longer read an unrelated post. On a date archive, a post type archive, a search results page, a 404 and a latest-posts blog home, WordPress leaves the query's first post where "the current post" is looked up, so {{title}} there showed that post's title and {{content}} could print that post's entire body onto the page. Each of those contexts now resolves its own answer, the same one WordPress core uses for the browser tab title: the archive label on a post type archive, the date span on a date archive, the formatted "Search Results for ..." heading on search, and the site name on the blog home. Tags with no sensible value in these contexts, a permalink or an image or a date field for instance, now render nothing rather than a wrong post's value; the same holds inside try_ tag attempts. An explicit source or a query loop still wins, exactly as before. This is the same defect class as the term and user loop fix below, reached through the page's main query instead of a loop.
    • One page may change on purpose: {{content}} on a latest-posts blog home used to render the first post's entire content through that leak. A home page built on that behavior now renders nothing there; a query loop showing the lead post is the supported way to get it back.
  • Tags in a query loop over terms or users now read the loop's own term or user. They had been reading a post instead: a third-party query extension hands the loop item's ID to a GenerateBlocks filter that cannot say what kind of thing the ID belongs to, and this plugin took it for a post ID. Term IDs and post IDs collide constantly, since every fresh install has both a term 1 and a post 1, so {{title}} in a term loop showed some post's title, plausibly and wrongly. Recognition reads the loop item's own shape, so the fix holds for any extension supplying loop items, not only the one it was found on.
  • Fields read from a TRASHED post inside a query loop no longer render. Version 1.18.0 made tag output status-aware, and one path was missed: a tag reading a meta field off a query loop's row went straight to the field, whatever the row's status was. In an ordinary GenerateBlocks query loop the effect was narrow, because GenerateBlocks already declines to run a loop over non-public posts for anyone who cannot read private posts. What got through was trashed content, shown to users who can, and trash is the one status that is meant to resolve for nobody at all. Drafts and private posts are unchanged: they still show to users who may read them and stay hidden from everyone else. A loop fed by something other than the standard query, a query extension or a filter for instance, was never covered by that narrowing, which is the case this fix is really for. If a field inside a query loop goes blank after this update, check whether the loop takes in trashed posts. Repeater row loops are unaffected, since a repeater row has no post behind it and so has no status to check.
  • A tag whose value is 0 no longer has that zero replaced by its fallback text. With a co-resident extension that re-applies a tag's fallback whenever the output looks empty to it, {{text key:stock|fallback:Sold out}} on a field holding 0 rendered Sold out. This plugin goes out of its way to stop a bare 0 being dropped, so the fallback was undoing a decision already taken here. Tag options this plugin has already consumed are no longer left on the output where another plugin's filter can read them. This reached every non-image tag carrying a fallback.
  • An image tag with a fallback no longer prints the fallback's raw text as the image source. Through the same re-application, an {{image}} tag whose fallback was an attachment ID that does not exist wrote that number into the src attribute, and one whose fallback was a word wrote whatever URL the other plugin resolved that word to. The tag had already used its own fallback and returned; the second application came from a plugin with no way of knowing that. Both now render nothing, which is what the tag itself returned.