Skip to content

Commit dd9c09d

Browse files
authored
Fixes
1 parent 1921698 commit dd9c09d

File tree

4 files changed

+55
-37
lines changed

4 files changed

+55
-37
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Security
11+
12+
- Hardened singleton pattern with private constructor and clone/wakeup prevention
13+
- Fixed missing input sanitization in settings update notification check
14+
- Added `function_exists()` guard for `wc_get_customer_order_count()` to prevent fatal errors if WooCommerce is deactivated
15+
16+
### Fixed
17+
18+
- Replaced incorrect `sanitize_text_field()` with proper `esc_html()` for store category term output context
19+
- Removed broken order count column sorting (no query handler existed to support it)
20+
- Removed redundant `is_admin()` and `current_user_can()` checks in column render callbacks already guarded at hook registration
21+
- Scoped admin CSS classes to prevent collisions with WordPress core `.card` styles and other plugins
22+
- Fixed FAQ to accurately state that all features are disabled by default
23+
1024
## [1.0.7] - 2025-09-15
1125

1226
### Added

class-optimizations-ace-mc.php

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,22 @@ public static function instance() {
5555
return self::$instance;
5656
}
5757

58+
/**
59+
* Prevent cloning.
60+
*/
61+
private function __clone() {}
62+
63+
/**
64+
* Prevent unserializing.
65+
*/
66+
public function __wakeup() {
67+
_doing_it_wrong( __METHOD__, __( 'Unserializing is not allowed.', 'optimizations-ace-mc' ), '1.0.7' );
68+
}
69+
5870
/**
5971
* Constructor.
6072
*/
61-
public function __construct() {
73+
private function __construct() {
6274
// Load settings.
6375
$this->load_settings();
6476

@@ -120,7 +132,6 @@ private function init_woocommerce_optimizations() {
120132
if ( $this->get_setting( 'woocommerce_user_order_count_column' ) && is_admin() && current_user_can( 'list_users' ) ) {
121133
add_filter( 'manage_users_columns', array( $this, 'add_user_order_count_column' ) );
122134
add_filter( 'manage_users_custom_column', array( $this, 'display_user_order_count_column' ), 10, 3 );
123-
add_filter( 'manage_users_sortable_columns', array( $this, 'make_user_order_count_sortable' ) );
124135
}
125136
}
126137

@@ -176,29 +187,13 @@ public function add_user_order_count_column( $columns ) {
176187
* @return string
177188
*/
178189
public function display_user_order_count_column( $output, $column_name, $user_id ) {
179-
// Security check - only for admins with list_users capability.
180-
if ( ! is_admin() || ! current_user_can( 'list_users' ) ) {
181-
return $output;
182-
}
183-
184-
if ( 'user_order_count' === $column_name ) {
190+
if ( 'user_order_count' === $column_name && function_exists( 'wc_get_customer_order_count' ) ) {
185191
$order_count = wc_get_customer_order_count( absint( $user_id ) );
186192
return esc_html( number_format_i18n( $order_count ) );
187193
}
188194
return $output;
189195
}
190196

191-
/**
192-
* Make order count column sortable.
193-
*
194-
* @param array $columns Sortable columns.
195-
* @return array
196-
*/
197-
public function make_user_order_count_sortable( $columns ) {
198-
$columns['user_order_count'] = 'user_order_count';
199-
return $columns;
200-
}
201-
202197
/**
203198
* Add store categories to store meta.
204199
*
@@ -215,12 +210,12 @@ public function add_store_categories_to_meta( $store_meta, $store_id ) {
215210
$location_terms = array();
216211
foreach ( $terms as $term ) {
217212
if ( ! empty( $term->name ) ) {
218-
$location_terms[] = sanitize_text_field( $term->name );
213+
$location_terms[] = esc_html( $term->name );
219214
}
220215
}
221216
$store_meta['terms'] = implode( ', ', $location_terms );
222217
} elseif ( ! empty( $terms[0]->name ) ) {
223-
$store_meta['terms'] = sanitize_text_field( $terms[0]->name );
218+
$store_meta['terms'] = esc_html( $terms[0]->name );
224219
}
225220
}
226221

@@ -285,11 +280,6 @@ public function add_user_registration_date_column( $columns ) {
285280
* @return string
286281
*/
287282
public function display_user_registration_date_column( $output, $column_name, $user_id ) {
288-
// Security check - only for admins with list_users capability.
289-
if ( ! is_admin() || ! current_user_can( 'list_users' ) ) {
290-
return $output;
291-
}
292-
293283
if ( 'registration_date' === $column_name ) {
294284
$registration_date = get_the_author_meta( 'registered', absint( $user_id ) );
295285
if ( $registration_date ) {
@@ -524,7 +514,7 @@ public function settings_page() {
524514
// Display success message if settings were updated.
525515
$this->display_admin_notices();
526516
?>
527-
<div class="wrap">
517+
<div class="wrap optimizations-ace-mc-wrap">
528518
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
529519

530520
<?php $this->display_plugin_info(); ?>
@@ -552,8 +542,8 @@ public function settings_page() {
552542
private function display_admin_notices() {
553543
// Note: Form submission is handled automatically by WordPress Settings API.
554544
// The settings_fields() function handles CSRF protection via nonces.
555-
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
556-
if ( isset( $_GET['settings-updated'] ) && wp_unslash( $_GET['settings-updated'] ) ) {
545+
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
546+
if ( isset( $_GET['settings-updated'] ) && sanitize_text_field( wp_unslash( $_GET['settings-updated'] ) ) ) {
557547
echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Settings saved successfully!', 'optimizations-ace-mc' ) . '</p></div>';
558548
}
559549
}
@@ -582,7 +572,7 @@ private function display_plugin_info() {
582572
*/
583573
private function display_dependencies_info() {
584574
?>
585-
<div class="card">
575+
<div class="optimizations-ace-mc-card">
586576
<h2><?php esc_html_e( 'Plugin Dependencies', 'optimizations-ace-mc' ); ?></h2>
587577
<p><?php esc_html_e( 'This plugin is designed to work with the following plugins:', 'optimizations-ace-mc' ); ?></p>
588578
<ul>
@@ -617,7 +607,7 @@ private function display_dependencies_info() {
617607
*/
618608
private function display_support_info() {
619609
?>
620-
<div class="card">
610+
<div class="optimizations-ace-mc-card">
621611
<h2><?php esc_html_e( 'Support & Documentation', 'optimizations-ace-mc' ); ?></h2>
622612
<p>
623613
<?php esc_html_e( 'For support, bug reports, or feature requests:', 'optimizations-ace-mc' ); ?>
@@ -635,26 +625,26 @@ private function display_support_info() {
635625
private function output_admin_styles() {
636626
?>
637627
<style>
638-
.card {
628+
.optimizations-ace-mc-card {
639629
background: #fff;
640630
border: 1px solid #ccd0d4;
641631
border-radius: 4px;
642632
padding: 15px;
643633
margin: 20px 0;
644634
max-width: 100%;
645635
}
646-
.card h2 {
636+
.optimizations-ace-mc-card h2 {
647637
margin-top: 0;
648638
}
649-
.form-table th {
639+
.optimizations-ace-mc-wrap .form-table th {
650640
width: 200px;
651641
}
652-
.form-table td label {
642+
.optimizations-ace-mc-wrap .form-table td label {
653643
display: flex;
654644
align-items: flex-start;
655645
gap: 10px;
656646
}
657-
.form-table td label input[type="checkbox"] {
647+
.optimizations-ace-mc-wrap .form-table td label input[type="checkbox"] {
658648
margin-top: 2px;
659649
flex-shrink: 0;
660650
}

languages/optimizations-ace-mc.pot

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ msgstr ""
1414
"X-Generator: WP-CLI 2.8.1\n"
1515
"X-Domain: optimizations-ace-mc\n"
1616

17+
#: class-optimizations-ace-mc.php
18+
msgid "Unserializing is not allowed."
19+
msgstr ""
20+
1721
#: class-optimizations-ace-mc.php:170
1822
msgid "Order Count"
1923
msgstr ""

readme.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Optimizations ACE MC is a comprehensive WordPress optimization plugin that provi
5252

5353
= Do I need to configure anything? =
5454

55-
The plugin comes with default settings enabled, but you can customize which optimizations to use via the **Settings > Optimizations ACE MC** admin page. Each feature can be individually enabled or disabled.
55+
All features are disabled by default. Navigate to **Settings > Optimizations ACE MC** to enable the optimizations you need. Each feature can be individually enabled or disabled.
5656

5757
= What happens if I don't have WooCommerce or WP Store Locator installed? =
5858

@@ -68,6 +68,16 @@ Yes, this plugin focuses on specific admin and functionality enhancements rather
6868

6969
== Changelog ==
7070

71+
= Unreleased =
72+
* Security: Hardened singleton pattern with private constructor and clone/wakeup prevention
73+
* Security: Fixed missing input sanitization in settings update notification check
74+
* Security: Added function_exists() guard for wc_get_customer_order_count() to prevent fatal errors
75+
* Fixed: Replaced incorrect sanitize_text_field() with proper esc_html() for store category output
76+
* Fixed: Removed broken order count column sorting that had no query handler
77+
* Fixed: Removed redundant capability checks in column render callbacks
78+
* Fixed: Scoped admin CSS classes to prevent collisions with WordPress core and other plugins
79+
* Fixed: FAQ now accurately states all features are disabled by default
80+
7181
= 1.0.7 - 2025-09-15 =
7282
* Added: AI-powered code analysis workflow using Google Gemini for automated security scanning
7383
* Added: Comprehensive WordPress coding standards compliance checking in CI/CD

0 commit comments

Comments
 (0)