Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/wpextended/modules/disk-usage-widget/Bootstrap.php
+++ b/wpextended/modules/disk-usage-widget/Bootstrap.php
@@ -173,6 +173,10 @@
*/
public function addDashboardWidget(): void
{
+ if (!current_user_can('manage_options')) {
+ return;
+ }
+
wp_add_dashboard_widget(
'dashboard_disk_usage',
esc_html__('Server Disk Usage', WP_EXTENDED_TEXT_DOMAIN),
--- a/wpextended/modules/menu-editor/Bootstrap.php
+++ b/wpextended/modules/menu-editor/Bootstrap.php
@@ -138,15 +138,7 @@
return $allcaps;
}
- // Part 1: Dashboard / profile — always grant the caps needed to load these pages
- if ($this->isDashboardOrProfileRequest()) {
- $allcaps['read'] = true;
- $allcaps['manage_options'] = true;
- $allcaps['edit_posts'] = true;
- $allcaps['edit_pages'] = true;
- }
-
- // Part 2: Menu-access grants derived from saved settings
+ // Menu-access grants derived from saved settings
$virtualCaps = $this->buildVirtualCapMap($user->ID, (array) $user->roles);
foreach ($caps as $cap) {
if ($cap === 'do_not_allow') {
@@ -206,14 +198,11 @@
*/
private function isDashboardOrProfileRequest(): bool
{
- $current_file = basename($_SERVER['PHP_SELF'] ?? '');
- $request_uri = $_SERVER['REQUEST_URI'] ?? '';
+ $script_name = basename($_SERVER['SCRIPT_NAME'] ?? '');
return (
- $current_file === 'index.php' ||
- $current_file === 'profile.php' ||
- strpos($request_uri, '/wp-admin/index.php') !== false ||
- strpos($request_uri, '/wp-admin/profile.php') !== false
+ $script_name === 'index.php' ||
+ $script_name === 'profile.php'
);
}
--- a/wpextended/modules/menu-editor/includes/SettingsManager.php
+++ b/wpextended/modules/menu-editor/includes/SettingsManager.php
@@ -143,7 +143,7 @@
'type' => 'text',
'title' => __('Required Capability', WP_EXTENDED_TEXT_DOMAIN),
'description' => __(
- 'The WordPress capability required to access this menu item. This is automatically detected from the menu registration.',
+ 'The WordPress capability required to access this menu item. This is automatically detected from the menu registration. <br><br><span style="color: #ea0000;">Users who do not have this capability will be temporarily granted it when given access below.</span><br><br>High-privilege capabilities such as <code>manage_options</code> will grant users full administrative-level permissions.',
WP_EXTENDED_TEXT_DOMAIN
),
'attributes' => array(
@@ -175,18 +175,6 @@
),
),
array(
- 'id' => 'capability_notice',
- 'type' => 'custom',
- 'callback' => array($this, 'showCapabilityNotice'),
- 'show_if' => array(
- array(
- 'field' => 'menu_slug',
- 'operator' => '!==',
- 'value' => 'index.php',
- ),
- ),
- ),
- array(
'id' => 'access_users',
'type' => 'select',
'title' => __('User-Specific Access', WP_EXTENDED_TEXT_DOMAIN),
@@ -530,25 +518,4 @@
{
return WpextendedIncludesModules::isModuleEnabled('disable-blog');
}
-
- /**
- * Show capability notice
- *
- * @param mixed $value Current field value (optional)
- * @param array $field Field configuration (optional)
- * @param array $item Current item data (optional)
- */
- public function showCapabilityNotice()
- {
- ?>
- <div class="notice notice-info inline" style="margin: 10px 0;">
- <p style="margin-block: .5em;">
- <?php echo esc_html__(
- 'Users who do not have the required capability will be granted it to access this menu item.',
- WP_EXTENDED_TEXT_DOMAIN
- ); ?>
- </p>
- </div>
- <?php
- }
}
--- a/wpextended/vendor/autoload.php
+++ b/wpextended/vendor/autoload.php
@@ -14,7 +14,10 @@
echo $err;
}
}
- throw new RuntimeException($err);
+ trigger_error(
+ $err,
+ E_USER_ERROR
+ );
}
require_once __DIR__ . '/composer/autoload_real.php';
--- a/wpextended/vendor/composer/InstalledVersions.php
+++ b/wpextended/vendor/composer/InstalledVersions.php
@@ -27,23 +27,12 @@
class InstalledVersions
{
/**
- * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
- * @internal
- */
- private static $selfDir = null;
-
- /**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
- * @var bool
- */
- private static $installedIsLocalDir;
-
- /**
* @var bool|null
*/
private static $canGetVendors;
@@ -320,24 +309,6 @@
{
self::$installed = $data;
self::$installedByVendor = array();
-
- // when using reload, we disable the duplicate protection to ensure that self::$installed data is
- // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
- // so we have to assume it does not, and that may result in duplicate data being returned when listing
- // all installed packages for example
- self::$installedIsLocalDir = false;
- }
-
- /**
- * @return string
- */
- private static function getSelfDir()
- {
- if (self::$selfDir === null) {
- self::$selfDir = strtr(__DIR__, '\', '/');
- }
-
- return self::$selfDir;
}
/**
@@ -351,27 +322,19 @@
}
$installed = array();
- $copiedLocalDir = false;
if (self::$canGetVendors) {
- $selfDir = self::getSelfDir();
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
- $vendorDir = strtr($vendorDir, '\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
- self::$installedByVendor[$vendorDir] = $required;
- $installed[] = $required;
- if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
- self::$installed = $required;
- self::$installedIsLocalDir = true;
+ $installed[] = self::$installedByVendor[$vendorDir] = $required;
+ if (null === self::$installed && strtr($vendorDir.'/composer', '\', '/') === strtr(__DIR__, '\', '/')) {
+ self::$installed = $installed[count($installed) - 1];
}
}
- if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
- $copiedLocalDir = true;
- }
}
}
@@ -387,7 +350,7 @@
}
}
- if (self::$installed !== array() && !$copiedLocalDir) {
+ if (self::$installed !== array()) {
$installed[] = self::$installed;
}
--- a/wpextended/vendor/composer/installed.php
+++ b/wpextended/vendor/composer/installed.php
@@ -3,7 +3,7 @@
'name' => 'wpextended/wpextended',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
- 'reference' => 'f050eff960d6f4df76ab34c85d9618511d1206ad',
+ 'reference' => '05b2c28b3a9f04a1f4587e7f9f721e7a256cb072',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -13,7 +13,7 @@
'wpextended/wpextended' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
- 'reference' => 'f050eff960d6f4df76ab34c85d9618511d1206ad',
+ 'reference' => '05b2c28b3a9f04a1f4587e7f9f721e7a256cb072',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
--- a/wpextended/wpextended.php
+++ b/wpextended/wpextended.php
@@ -16,7 +16,7 @@
* Plugin Name: WP Extended
* Plugin URI: https://wpextended.io
* Description: WP Extended is a modular plugin designed to enhance the core WordPress experience by adding many of the tools you need without having to install multiple plugins.
- * Version: 3.2.4
+ * Version: 3.2.5
* Author: WP Extended
* Author URI: https://wpextended.io/
* License: GPL-2.0+
@@ -61,7 +61,7 @@
/**
* Define constants for the plugin.
*/
-define('WP_EXTENDED_VERSION', '3.2.4');
+define('WP_EXTENDED_VERSION', '3.2.5');
define('WP_EXTENDED_TEXT_DOMAIN', 'wp-extended');
define('WP_EXTENDED_PATH', plugin_dir_path(__FILE__));
define('WP_EXTENDED_URL', plugin_dir_url(__FILE__));