Hold back updates where mbstring lacks mbregex - #467
Draft
KevinBatdorf wants to merge 10 commits into
Draft
Conversation
The next major renders code server-side and needs mb_ereg_*. mbstring built with --disable-mbregex has no ini switch and no add-on package to fix it — only a different PHP build — and wordpress.org can gate updates on PHP version but not on extensions. Left alone, those sites would auto-update into a version they cannot render. So the plugin holds itself back: a capability check behind the blocks.codeBlockPro.canHighlight filter, and a site_transient_update_plugins filter that drops this plugin's own entry when the check fails. Verified on a playground site — with the check forced false the Plugins screen offers no update, the Updates screen doesn't list the plugin, and the menu bubble reads 0; other plugins are untouched. Note that playground's PHP does have mbregex, so the editor-facing phases have to drive the filter seam rather than the real capability. Reading, not writing, is filtered on purpose. The stored transient still carries the update, so nothing is lost if a later release can run here and the gate comes off. CI runs the suite twice, once with mb_ereg_search_init taken away by disable_functions. No prebuilt PHP offers mbstring without mbregex, and that ini setting reproduces the only part that matters: function_exists returns false while the rest of mbstring keeps working. So one test covers the unfiltered path for real in both directions, rather than trusting the filter seam to stand in for a build nobody can install. This also stands up composer and phpunit, which the repo had neither of — tests run against a WordPress checkout named by WP_ABSPATH, with a dedicated database so they never touch a working install. Requires PHP stays at 7.0: bumping it would stop this release reaching the very sites it exists for. Co-Authored-By: Claude <noreply@anthropic.com>
Hiding mb_ereg_search_init with disable_functions made the capability check false, but it was still a stand-in: mbstring kept the rest of the mb_ereg family, and nothing proved the plugin behaves on the build this release exists for. No prebuilt PHP ships mbstring without mbregex, so the only way to get one is to compile it. The Dockerfile builds PHP with --enable-mbstring --disable-mbregex and without libonig, so a build that quietly keeps mbregex fails instead of passing. Confirmed locally on 8.4.24: mbstring loads, mb_substr works, the whole mb_ereg family is gone, and phpinfo no longer reports an oniguruma version. WordPress installs and the suite passes, and with the transient filter removed the unfiltered test fails — so it is reading the build, not a filter. The image is pushed to GHCR and the second job runs inside it. Public packages cost nothing and don't expire, unlike Actions cache entries, which are evicted after a week idle and would silently recompile. Both jobs live in one workflow so the image is built before the job that pulls it, and the database now comes from the service's own MYSQL_DATABASE rather than a client call, since the image carries no mysql client. The mbregex-absent job talks to the service by hostname because a job running in a container can't reach it on 127.0.0.1. Co-Authored-By: Claude <noreply@anthropic.com>
The gate makes the plugin go quiet on servers without mbregex, which on its own reads as a plugin that simply stopped getting updates. The capability now rides along with the editor's inline script, next to pluginUrl, and the Theme panel carries a notice naming mbregex and the mbstring extension so a site owner has something concrete to take to their host. The check stays in PHP — the editor is told the answer rather than working it out, so the notice can't disagree with the update gate. The notice states a requirement and offers nothing to click. Letting the update through anyway would leave every new code block rendering without colors, which is a broken site rather than a choice worth putting in front of someone; and hiding the notice would take away the only explanation the site has for a plugin that no longer updates. It stays until the server can highlight. Playground's PHP has mbregex and no build without it can run there, so the spec installs an mu-plugin that turns the capability off for requests carrying cbp_no_mbregex — the filter seam the gate left for exactly this. The absence case waits for the Manage themes button first, since the panel is empty until the settings store hydrates and a missing notice would prove nothing. Confirmed the other direction is real: with the component left out of the bundle, the notice test failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dropping our entry from the update transient only removes the offer. wp-cli and the update screens hand a package straight to the upgrader, which never reads that transient, so `wp plugin update code-block-pro` would still put a version this server cannot render onto the site. upgrader_pre_install returns a WP_Error for our own basename when the capability is missing, which aborts install_package before anything is copied over the live plugin. wp-cli prints the message and the update screen shows it in place of a success line, so the refusal is visible rather than a silent no-op. Two paths stay open, because the upgrader can't be told what they carry: an install action names no plugin in hook_extra, so `wp plugin install --force` and files copied in over SFTP both look like any other install. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The notice only knew about mbregex, so a site running PHP 8.1 with mbregex present was told nothing at all: wordpress.org quietly stops offering a version whose Requires PHP it can't meet, and the editor stayed silent about it. The editor now receives hasNextPhp and nextPhp alongside canHighlight, and the notice picks between three messages so it names what this particular server lacks — mbregex, the PHP version, or both. 8.2 is written once, in code_block_pro_next_php, and reaches the copy through a placeholder. The gates themselves stay mbregex-only. Core reads Requires PHP out of the package and refuses the install on its own, wp-cli included, so holding 1.x back over a version would take away updates core would have allowed through. Two tests pin that separation. Playground runs 8.5 with mbregex, so the mu-plugin the spec installs now fakes both, one request parameter each. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The messages opened on the requirement and read like a failure report. They now open on version 2 arriving and keep one sentence for what this server lacks, which is the part a site owner repeats to their host. The wrapper carries vertical margin so the notice isn't wedged between the panel header and the theme search. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The wrapper carried my-6 while the utilities in this build are emitted as `.code-block-pro-editor .my-6`, so the class only styles descendants and the computed margin came out 0. Moved onto an inner div, which measures 24px top and bottom. An emoji goes with the announcement of version 2. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
KevinBatdorf
force-pushed
the
feature/mbregex-gate
branch
from
August 22, 2026 03:53
028f5b8 to
ba14f1c
Compare
The editor fell back to a hardcoded 8.2 when the localised value was missing, so a later bump would have left the notice quoting a version the check no longer used. The version now only ever comes from PHP, and a notice with no version to name treats the PHP requirement as unmet rather than guessing at it. Splitting the three messages apart drops the flag-shaped argument that decided between them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An install action carries no plugin in hook_extra, so uploading the zip or `wp plugin install --force` walked straight past the refusal that covers updates. upgrader_source_selection sees the unpacked directory instead, so the package can be identified from its own headers: any php file in its root declaring our text domain means it is us, whatever the file or folder is called. The test builds a package named entry.php for that reason. Files copied in over SFTP still can't be caught — no WordPress code runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mbregex compiles in or out as a unit, so one probe answers for the family on any normal build. disable_functions doesn't work that way: a host can hide mb_ereg_search_getregs and leave mb_ereg_search_init in place, and the gate would wave the update through to a site that fatals on render. The check now covers all four functions phiki calls, and a test pins the list so a narrowing goes noticed. Blocking a capable site wrongly only leaves it on 1.x. Letting an incapable one through breaks its pages. The announcement draft names the same four. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Some servers run PHP without a piece of text-matching that the next big release needs to colour code. Site owners can't add it — that takes a different PHP build — and WordPress.org can't hold an update back over it. So the plugin looks at the server it's on, stops offering itself an update when it wouldn't be able to render, and says so in the editor. Sites that are fine see no difference.
wp plugin updateand the update screens hand a package straight to the installer without consulting that list, so the installer is told no as well, with a message saying why. Files copied in by hand still can't be stopped.wp plugin updateincluded, so this release only gates on the piece core can't see. Two tests hold that line.PR description generated by Claude.