Skip to content

v1.7.1 - #91

Merged
tacoverdo merged 26 commits into
mainfrom
develop
Nov 2, 2026
Merged

tacoverdo merged 26 commits into
mainfrom
develop

Conversation

@ilicfilip

Copy link
Copy Markdown
Collaborator

Release 1.7.1: merges develop into main.

After merging, publish the GitHub release v1.7.1 from main. Publishing it runs deploy.yml, which pushes the plugin and the .wordpress-org/ assets to WordPress.org.

🤖 Generated with Claude Code

ilicfilip and others added 26 commits May 6, 2026 14:36
W3TC's DbCache wrapper reads `$wpdb->col_info` after each cacheable
query, which triggers `wpdb::load_col_info()` -> `mysqli_num_fields()`.
For non-SELECT queries the result is `true` (bool), so this fatals
with "Argument #1 ($result) must be of type mysqli_result, true given".

W3TC bypasses caching for write queries via a regex that matches
`START TRANSACTION`, `INSERT`, `COMMIT`, etc. — but not `BEGIN`.
Switching `BEGIN` to `START TRANSACTION` (semantically identical in
MySQL) lets W3TC's regex catch it and skip the col_info path.

Reproduced locally with W3TC 2.9.4: identical stack trace with `BEGIN`,
no fatal with `START TRANSACTION`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Filip Ilić <ilic.filip@gmail.com>
Fix W3 Total Cache DbCache fatal in batch_insert
Updates wp-coding-standards/wpcs to 3.4.1, which fixes a security issue
in the WordPress.WP.EnqueuedResourceParameters sniff where running PHPCS
over untrusted PHP code could lead to arbitrary command execution on the
scanning host (GHSA-3pwp-g2mj-5p3v).

Also bumps the required transitive dependencies:
- phpcsstandards/phpcsutils to 1.2.3
- phpcsstandards/phpcsextra to 1.5.1

Lock-file only; composer.json constraints already allowed 3.4.1.
Verified locally with PHPCS: no new violations.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Signed-off-by: Filip Ilic <ilic.filip@gmail.com>
Every request writes the options it read to wp_option_optimizer_tracked
on shutdown with INSERT ... ON DUPLICATE KEY UPDATE. InnoDB locks rows in
VALUES order, which followed per-request access order, so concurrent
requests locked the same rows in different orders and deadlocked
("Deadlock found when trying to get lock"), losing that request's counts.

Sort the options before writing so all writers lock in one order. On a
failed insert, ROLLBACK instead of sending COMMIT (which also hid the
error by clearing $wpdb->last_error), and retry once on a deadlock; the
deadlock rolls back the whole transaction, so the retry can't double count.

Reproduced locally with 20 parallel writers x 50 batch_insert() calls of
200 shuffled options: ~920/1000 deadlocks before, 0/1000 after with all
200000 increments landed. Retry path verified with a forced deadlock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PHPStan 1.12 to 2.3, with szepeviktor/phpstan-wordpress 1.3 to 2.0 (which brings WordPress stubs 6.9 to 7.1). The code needed no changes. Two config entries did:

- excludePaths: tests does not exist in this repository, which PHPStan 2 refuses; marked optional as tests (?).
- The ignore for missingType.generics matched nothing on PHPStan 2 and is reported as unused; removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Signed-off-by: Filip Ilic <ilic.filip@gmail.com>
Fix deadlocks when concurrent requests write tracked options
* Bump version to 1.6.2

- Version 1.6.2 in the plugin header, readme Stable tag and package.json.
- Changelog: deadlock fix, W3 Total Cache DbCache fix, readme improvements.
- Restore "Requires at least: 6.7". The readme rework lowered it to 6.4, but
  the plugin calls wp_autoload_values_to_autoload() (WP 6.6+) unguarded, so
  WP 6.4/6.5 sites would be offered an update that fatals.
- "Tested up to: 7.1" (current WordPress; Plugin Check flags 7.0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Add 1.6.2 upgrade notice

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Rename plugin to AAA Autoload Optimizer and release as 1.7.0

- Plugin name, readme title and all user-facing strings: "AAA Autoload
  Optimizer". #76 had renamed the headers to "Autoload Optimizer"; the admin
  page, README.md, known-plugins.json and docblocks still said "AAA Option
  Optimizer". The Tools menu label is now "Autoload Optimizer".
- Slug, text domain, option names and PHP namespaces are unchanged.
- Version 1.6.2 -> 1.7.0 (plugin header, Stable tag, package.json,
  changelog, upgrade notice). The rename is a minor-version change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- New WordPress.org banners (772x250, 1544x500) with the new name.
- Add Dutch banners as banner-*-nl_NL.png, the locale naming WordPress.org
  uses for localized assets.
- Replace github_banner_aaaoo_pp.png with github_banner_aaaao_pp.png and
  point README.md at it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Update banners for the AAA Autoload Optimizer rename
When the table is too narrow, DataTables Responsive moves the Autoload
and Actions cells into a child row. updateRowOnSuccess only patched the
parent <tr>, so the child row kept showing the old status and button and
looked broken. Update the row data and redraw instead, so Responsive
re-renders child rows too (server-side tables re-fetch the page).

Rows are now looked up by DataTables row ID ('#id') instead of a jQuery
'tr#…' selector, so option names with characters like '.' or ':' match.
This also fixes bulk delete, which never converted '.' in names.

Reported at https://wordpress.org/support/topic/changing-row-status-or-deleting-it-wont-work-after-changing-the-table-order/

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Tables initialised inside a hidden tab could not measure their
  columns, so Responsive never collapsed them and they overflowed the
  panel ("table loads broken, missing columns"). Recalculate visible
  tables whenever a tab is opened.
- The tab panel was width: 100% plus 60px padding, so it always
  overflowed its container by 60px. Use box-sizing: border-box, and bump
  the stylesheet version so browsers pick it up.
- The All options table showed "Remove autoload" for options stored as
  'off' or 'auto-off' (WordPress 6.6+ values), because only 'no' was
  treated as not autoloaded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Option names and values shown in the admin tables are arbitrary strings
that may contain HTML metacharacters. Render them through
DataTable.render.text() and an escapeHtml() helper, and build element
ids/attribute targets from the sanitised row id rather than the raw name,
so a crafted name cannot break out of the generated markup. Drop the
now-redundant server-side htmlentities() on the value field to avoid
double-encoding.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Legacy tracking treats every hook starting with 'option_' as an option read,
including 'option_page_capability_{option_page}', which wp-admin/options.php
builds from request data and fires before its capability check. That let any
logged-in user store an arbitrary string as a tracked option name.

- Skip the 'option_page_capability_' hook in legacy tracking; it is a
  capability filter, not an option read.
- Reject names that are empty, longer than 191 characters (the column width),
  or contain whitespace, quotes, backslashes or angle brackets, in both
  tracking modes. Filterable via aaa_option_optimizer_is_trackable_option_name,
  except the length limit.
- Keep dots in generated row ids so names like foo.bar and foo_bar no longer
  collide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The same option can be listed in more than one table (e.g. "Used, but not
autoloaded" and "All options"). Both rendered the same popover and checkbox
ids, so the "Show" button in the second table targeted the popover in the
first, hidden table and nothing opened. Prefix these ids with the table id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
generateRowId() replaced every character outside the allow-list with '_',
so distinct names like 'foo:bar' and 'foo_bar' got the same row, checkbox and
popover id, and an action on one could update the other row's display.
Encode each character outside [A-Za-z0-9_] as '-<hex code point>-' instead;
'-' never appears literally, so every option name maps to a unique id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Options API accepts whitespace, quotes and backslashes in option names,
so rejecting them stopped tracking real options, which then showed up as
"Unused, but autoloaded" and were offered for deletion. Only reject empty
names and names over 191 characters, counted with mb_strlen() to match the
VARCHAR(191) column. The option_page_capability_ skip and output escaping
still cover the reported injection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…update

Fix table actions and layout when columns are collapsed
…er-ids

Make popover and checkbox ids unique across tables
…output

Merge admin table escaping and id fixes into develop
- Version 1.7.1 in the plugin header, readme Stable tag, package.json and package-lock.json.
- Changelog for the admin table fixes and hardening merged since 1.7.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main's tree at v1.7.0 is identical to develop at c0b331f, so develop's
content is kept as is. This only records main as merged so the 1.7.1
release PR from develop to main has no conflicts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

Test on Playground
Test this pull request on the Playground
or download the zip

@tacoverdo
tacoverdo self-requested a review November 2, 2026 12:12

@tacoverdo tacoverdo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

@tacoverdo
tacoverdo merged commit e09489e into main Nov 2, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants