Add tool-catalog patch: show guarded tools from absent plugins as locked groups with install note (per-group, collapsed)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q8t9GEyyLZbUQu26na1JQg
This commit is contained in:
@@ -0,0 +1,185 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Idempotent patch — "catalog" view for the Tools tab.
|
||||||
|
*
|
||||||
|
* Any tool that belongs to a guarded integration batch (WPBakery, WooCommerce,
|
||||||
|
* Yoast, Wordfence, LiteSpeed, WP Rocket, WPML, Elementor, ...) whose plugin is
|
||||||
|
* NOT installed/active on this site is normally inert and absent from the Tools
|
||||||
|
* tab. This patch makes those tools visible anyway — rendered LOCKED, grouped by
|
||||||
|
* the plugin that provides them, with an "install & activate it" note — so the
|
||||||
|
* admin can see the full catalog and knows exactly what to install.
|
||||||
|
*
|
||||||
|
* The catalog is derived at runtime from the Batch*.php sources (guard symbol +
|
||||||
|
* $def('name','desc') pairs), so it stays correct automatically as new guarded
|
||||||
|
* families are added. Nothing here touches the live enable/disable logic or the
|
||||||
|
* "X of Y tools enabled" counts — locked tools aren't real tools on this site.
|
||||||
|
*
|
||||||
|
* Usage: php patch-tool-catalog.php [ABS_PATH_TO/includes]
|
||||||
|
* Safe to run repeatedly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$base = $argv[1] ?? '/var/www/html/wp-content/plugins/advanced-mcp-plugin/includes';
|
||||||
|
$admin = $base . '/Core/AdminMenu.php';
|
||||||
|
$css = dirname($base) . '/assets/css/admin.css';
|
||||||
|
|
||||||
|
$changed = [];
|
||||||
|
|
||||||
|
/* ── 1. AdminMenu.php ─────────────────────────────────────────────────────── */
|
||||||
|
$src = file_get_contents($admin);
|
||||||
|
if ($src === false) { fwrite(STDERR, "cannot read $admin\n"); exit(1); }
|
||||||
|
|
||||||
|
if (strpos($src, 'getUnavailableGrouped') === false) {
|
||||||
|
|
||||||
|
$methods = <<<'PHP'
|
||||||
|
/* amp-tool-catalog: guarded tools whose plugin isn't active here, shown locked */
|
||||||
|
public function getUnavailableGrouped(): array {
|
||||||
|
$dir = defined('ASKTAM_MCP_DIR') ? ASKTAM_MCP_DIR . 'includes/Extensions/' : __DIR__ . '/../Extensions/';
|
||||||
|
$files = glob($dir . 'Batch*.php') ?: [];
|
||||||
|
$live = [];
|
||||||
|
foreach ((new \AskTamMCP\MCP\Registry())->getAllToolsRaw() as $t) { if (!empty($t['name'])) $live[$t['name']] = true; }
|
||||||
|
$labels = $this->ampPluginLabels();
|
||||||
|
$groups = [];
|
||||||
|
foreach ($files as $f) {
|
||||||
|
$code = @file_get_contents($f);
|
||||||
|
if ($code === false || $code === '') continue;
|
||||||
|
if (!preg_match('/if\s*\(\s*!\s*(?:defined|class_exists)\s*\(\s*[\'"]\\\\?([A-Za-z0-9_\\\\]+)[\'"]\s*\)[^;\n]*\breturn\b/', $code, $gm)) continue;
|
||||||
|
$guard = ltrim($gm[1], '\\');
|
||||||
|
if (!preg_match_all('/\$def\(\s*\'([a-z0-9_]+)\'\s*,\s*\'((?:\\\\.|[^\'\\\\])*)\'/', $code, $mm, PREG_SET_ORDER)) continue;
|
||||||
|
foreach ($mm as $m) {
|
||||||
|
$name = $m[1];
|
||||||
|
if (isset($live[$name])) continue; // plugin active → already a real tool
|
||||||
|
$desc = str_replace(["\\'", "\\\\"], ["'", "\\"], $m[2]);
|
||||||
|
$info = $labels[$guard] ?? [$this->ampHumanizeGuard($guard), ''];
|
||||||
|
$gid = 'unavail_' . strtolower(preg_replace('/[^A-Za-z0-9]+/', '_', $guard));
|
||||||
|
if (!isset($groups[$gid])) $groups[$gid] = ['label' => $info[0], 'plugin' => $info[0], 'tools' => []];
|
||||||
|
$groups[$gid]['tools'][$name] = ['label' => $this->prettyLabel($name), 'description' => $desc];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($groups as $gid => $g) { if (empty($g['tools'])) { unset($groups[$gid]); continue; } ksort($groups[$gid]['tools']); }
|
||||||
|
uasort($groups, fn($a, $b) => strcmp($a['label'], $b['label']));
|
||||||
|
return $groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function ampPluginLabels(): array {
|
||||||
|
return [
|
||||||
|
'WPB_VC_VERSION' => ['WPBakery Page Builder', 'js_composer'],
|
||||||
|
'ELEMENTOR_VERSION' => ['Elementor', 'elementor'],
|
||||||
|
'WooCommerce' => ['WooCommerce', 'woocommerce'],
|
||||||
|
'WOOCOMMERCE_VERSION' => ['WooCommerce', 'woocommerce'],
|
||||||
|
'ICL_SITEPRESS_VERSION' => ['WPML', 'wpml'],
|
||||||
|
'WPSEO_VERSION' => ['Yoast SEO', 'wordpress-seo'],
|
||||||
|
'WORDFENCE_VERSION' => ['Wordfence Security', 'wordfence'],
|
||||||
|
'LSCWP_V' => ['LiteSpeed Cache', 'litespeed-cache'],
|
||||||
|
'LSCWP_CUR_V' => ['LiteSpeed Cache', 'litespeed-cache'],
|
||||||
|
'WP_ROCKET_VERSION' => ['WP Rocket', 'wp-rocket'],
|
||||||
|
'RANK_MATH_VERSION' => ['Rank Math SEO', 'seo-by-rank-math'],
|
||||||
|
'AIOSEO_VERSION' => ['All in One SEO', 'all-in-one-seo-pack'],
|
||||||
|
'SEOPRESS_VERSION' => ['SEOPress', 'wp-seopress'],
|
||||||
|
'GFCommon' => ['Gravity Forms', 'gravityforms'],
|
||||||
|
'FLUENTFORM_VERSION' => ['Fluent Forms', 'fluentform'],
|
||||||
|
'ACF' => ['Advanced Custom Fields', 'advanced-custom-fields'],
|
||||||
|
'TRP_PLUGIN_VERSION' => ['TranslatePress', 'translatepress-multilingual'],
|
||||||
|
'POLYLANG_VERSION' => ['Polylang', 'polylang'],
|
||||||
|
'ET_CORE_VERSION' => ['Divi', 'divi'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function ampHumanizeGuard(string $g): string {
|
||||||
|
$g = preg_replace('/_(VERSION|VER|PLUGIN|CORE)$/i', '', $g);
|
||||||
|
$g = trim(str_replace(['_', '\\'], ' ', $g));
|
||||||
|
return $g !== '' ? ucwords(strtolower($g)) : 'Add-on';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PHP;
|
||||||
|
|
||||||
|
$anchor = " private function prettyLabel(string \$n): string {";
|
||||||
|
$n = substr_count($src, $anchor);
|
||||||
|
if ($n !== 1) { fwrite(STDERR, "prettyLabel anchor count=$n; aborting\n"); exit(2); }
|
||||||
|
$src = str_replace($anchor, $methods . $anchor, $src);
|
||||||
|
|
||||||
|
$renderAnchor = " <?php endforeach; ?>\n <?php submit_button('Save Changes'); ?>";
|
||||||
|
$n = substr_count($src, $renderAnchor);
|
||||||
|
if ($n !== 1) { fwrite(STDERR, "render anchor count=$n; aborting\n"); exit(3); }
|
||||||
|
|
||||||
|
$renderBlock = <<<'HTML'
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php $amp_unavail = $this->getUnavailableGrouped(); if (!empty($amp_unavail)): ?>
|
||||||
|
<div class="asktam-mcp-unavail-intro">
|
||||||
|
<h2 class="asktam-mcp-unavail-title">Available with other plugins</h2>
|
||||||
|
<p class="description">These tools stay off because the plugin that drives them isn’t active on this site. Install & activate it and they switch on automatically — listed here so you can see the full catalog.</p>
|
||||||
|
</div>
|
||||||
|
<?php foreach ($amp_unavail as $amp_cid => $amp_cat): $amp_total = count($amp_cat['tools']); ?>
|
||||||
|
<div class="asktam-mcp-category asktam-mcp-category--locked" data-category="<?php echo esc_attr($amp_cid); ?>">
|
||||||
|
<h2 class="asktam-mcp-category-header">
|
||||||
|
<?php echo esc_html($amp_cat['label']); ?>
|
||||||
|
<span class="asktam-mcp-category-count asktam-mcp-count-locked"><?php echo esc_html($amp_total); ?> locked</span>
|
||||||
|
<span class="asktam-mcp-locked-flag">Not installed</span>
|
||||||
|
</h2>
|
||||||
|
<p class="asktam-mcp-install-note">Requires <strong><?php echo esc_html($amp_cat['plugin']); ?></strong> — install & activate it to enable these tools.</p>
|
||||||
|
<div class="asktam-mcp-tools-grid">
|
||||||
|
<?php foreach ($amp_cat['tools'] as $amp_slug => $amp_tool): ?>
|
||||||
|
<div class="asktam-mcp-locked-card">
|
||||||
|
<span class="asktam-mcp-lock" aria-hidden="true">🔒</span>
|
||||||
|
<span class="asktam-mcp-tool-info">
|
||||||
|
<span class="asktam-mcp-tool-name"><?php echo esc_html($amp_tool['label']); ?></span>
|
||||||
|
<span class="asktam-mcp-tool-desc"><?php echo esc_html($amp_tool['description']); ?></span>
|
||||||
|
<code class="asktam-mcp-tool-slug"><?php echo esc_html($amp_slug); ?></code>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php submit_button('Save Changes'); ?>
|
||||||
|
HTML;
|
||||||
|
|
||||||
|
$src = str_replace($renderAnchor, $renderBlock, $src);
|
||||||
|
|
||||||
|
if (file_put_contents($admin, $src) === false) { fwrite(STDERR, "write failed $admin\n"); exit(4); }
|
||||||
|
$changed[] = 'AdminMenu.php (methods + render block)';
|
||||||
|
} else {
|
||||||
|
$changed[] = 'AdminMenu.php already patched (skipped)';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── 2. admin.css ─────────────────────────────────────────────────────────── */
|
||||||
|
$cssSrc = @file_get_contents($css);
|
||||||
|
if ($cssSrc === false) {
|
||||||
|
fwrite(STDERR, "warning: cannot read $css\n");
|
||||||
|
} elseif (strpos($cssSrc, 'amp-tool-catalog') === false) {
|
||||||
|
$cssAdd = <<<'CSS'
|
||||||
|
|
||||||
|
|
||||||
|
/* amp-tool-catalog: locked / not-installed families */
|
||||||
|
.asktam-mcp-unavail-intro{margin:30px 0 8px;padding-top:18px;border-top:1px solid #e2e4e7}
|
||||||
|
.asktam-mcp-unavail-title{font-size:15px;margin:0 0 4px}
|
||||||
|
.asktam-mcp-category--locked{opacity:.95}
|
||||||
|
.asktam-mcp-category--locked .asktam-mcp-category-header{color:#50575e}
|
||||||
|
.asktam-mcp-locked-flag{display:inline-block;margin-left:8px;padding:1px 8px;border-radius:10px;background:#f0f0f1;color:#646970;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.02em;vertical-align:middle}
|
||||||
|
.asktam-mcp-count-locked{background:#f6f7f7;color:#646970}
|
||||||
|
.asktam-mcp-install-note{margin:2px 0 12px;padding:9px 12px;background:#fcf9e8;border:1px solid #f0e6a6;border-radius:6px;color:#674f00;font-size:12.5px}
|
||||||
|
.asktam-mcp-install-note strong{color:#674f00}
|
||||||
|
.asktam-mcp-category.is-collapsed .asktam-mcp-install-note{display:none}
|
||||||
|
.asktam-mcp-locked-card{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border:1px dashed #d5d8dc;border-radius:8px;background:#fafbfc;cursor:not-allowed}
|
||||||
|
.asktam-mcp-locked-card .asktam-mcp-lock{font-size:14px;line-height:1.5;filter:grayscale(1);opacity:.7}
|
||||||
|
.asktam-mcp-locked-card .asktam-mcp-tool-info{display:flex;flex-direction:column;gap:3px;min-width:0}
|
||||||
|
.asktam-mcp-locked-card .asktam-mcp-tool-name{font-weight:600;color:#50575e}
|
||||||
|
.asktam-mcp-locked-card .asktam-mcp-tool-desc{color:#787c82;font-size:12px}
|
||||||
|
.asktam-mcp-locked-card .asktam-mcp-tool-slug{color:#8c8f94;font-size:11px}
|
||||||
|
@media(prefers-color-scheme:dark){
|
||||||
|
.asktam-mcp-unavail-intro{border-top-color:#3c434a}
|
||||||
|
.asktam-mcp-install-note{background:#2b2718;border-color:#5a4e1f;color:#e8d98a}
|
||||||
|
.asktam-mcp-install-note strong{color:#f3e7a0}
|
||||||
|
.asktam-mcp-locked-card{background:#1f2327;border-color:#3c434a}
|
||||||
|
.asktam-mcp-locked-card .asktam-mcp-tool-name{color:#c3c4c7}
|
||||||
|
.asktam-mcp-locked-flag,.asktam-mcp-count-locked{background:#2c3338;color:#a7aaad}
|
||||||
|
}
|
||||||
|
CSS;
|
||||||
|
file_put_contents($css, $cssAdd, FILE_APPEND);
|
||||||
|
$changed[] = 'admin.css (locked styles appended)';
|
||||||
|
} else {
|
||||||
|
$changed[] = 'admin.css already patched (skipped)';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "patch-tool-catalog: " . implode('; ', $changed) . "\n";
|
||||||
Reference in New Issue
Block a user