fix: UsageMatcher reads Divi 4 shortcodes like WordPress and Divi, everywhere (ruling P24)

- G1: every decoded string value of a Divi 5 opener is scanned for shortcodes;
  outside the openers only the remaining content is.
- G2: attributes are parsed like shortcode_parse_atts() and global_module is
  cast with (int), as Divi does.
- G3: a non-empty global_module other than "0" that casts to 0 makes Divi
  render the newest layout, so it counts for every entry (fail closed).
- The prefilter LIKEs use LOWER(post_content), so they are case-insensitive
  under any collation.
- The guide describes the fail-closed rule without an absolute claim.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-27 04:53:54 +02:00
co-authored by Claude Opus 5.5
parent 8f87ec6163
commit b6d791d46a
5 changed files with 172 additions and 33 deletions
@@ -127,7 +127,7 @@ class GlobalUsages
/**
* Every post (no revision, not trashed) that shows $libraryId (ruling P23, fail closed). The
* candidates come from one query (ID, status and type only): content with "globalModule", a
* Divi 4 "global_module" or a JSON escape of a letter (an escaped key such as globalModule
* Divi 4 "global_module" (both case-insensitive) or a JSON escape of a letter (an escaped key such as globalModule
* always has one). Their content is then read in chunks of CONTENT_CHUNK and parsed by
* UsageMatcher; beyond PARSE_CAP candidates the rest counts as references unread (audit L1).
*
@@ -158,10 +158,11 @@ class GlobalUsages
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery
$rows = $db->get_results(
$db->prepare(
'SELECT ID, post_status, post_type FROM ' . $db->posts . ' WHERE (post_content LIKE %s OR '
. "post_content LIKE %s OR post_content REGEXP %s) AND post_type <> 'revision' AND "
// Ruling P24: LOWER() keeps the LIKEs case-insensitive under any column collation.
'SELECT ID, post_status, post_type FROM ' . $db->posts . ' WHERE (LOWER(post_content) LIKE %s OR '
. "LOWER(post_content) LIKE %s OR post_content REGEXP %s) AND post_type <> 'revision' AND "
. self::LISTED . ' ORDER BY ID ASC',
'%' . $db->esc_like('globalModule') . '%',
'%' . $db->esc_like('globalmodule') . '%',
'%' . $db->esc_like('global_module') . '%',
$escapedLetter
),