define_constants();
add_action('plugins_loaded', [$this, 'init_plugin']);
}
/**
* Define the required plugin constants.
*
* @return void
*/
public function define_constants() {
define('ADMO_VERSION', self::VERSION);
define('ADMO_FILE', __FILE__);
define('ADMO_PATH', __DIR__);
define('ADMO_URL', plugins_url('', ADMO_FILE));
define('ADMO_ASSETS', ADMO_URL . '/assets');
}
/**
* Initialize the plugin.
*
* @return void
*/
public function init_plugin() {
add_action('admin_menu', [$this, 'add_admin_menu']);
add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts']);
add_action('wp_ajax_admo_save_order', [$this, 'save_order']);
add_filter('custom_menu_order', '__return_true');
add_filter('menu_order', [$this, 'apply_custom_order']);
// Hook the AJAX handler.
add_action('wp_ajax_admo_save_title', [$this, 'save_title']);
add_action('admin_menu', [$this, 'apply_custom_titles'], 100);
}
/**
* Add a top-level menu for the plugin.
*
* @return void
*/
public function add_admin_menu() {
add_menu_page(
__('Admin Menu Optimizer', 'admin-menu-optimizer'),
__('Menu Optimizer', 'admin-menu-optimizer'),
'manage_options',
'admin-menu-optimizer',
[$this, 'settings_page'],
'dashicons-menu',
);
}
/**
* Display the settings page.
*/
public function settings_page() {
global $menu;
?>
admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('admo_nonce'),
]);
}
}
/**
* Save menu order via AJAX.
*
* @return void
*/
public function save_order() {
// Verify nonce first
check_ajax_referer('admo_nonce', 'nonce');
// Sanitize the entire $_POST['order'] input
$order = isset($_POST['order']) ?
array_map('sanitize_text_field', wp_unslash($_POST['order'])) :
null;
// Additional validation
if (!is_array($order) || empty($order)) {
wp_send_json_error(esc_html__('Invalid order data.', 'admin-menu-optimizer'));
exit;
}
// Validate that all items are strings or numeric
$validated_order = array_filter($order, function($item) {
return is_string($item) || is_numeric($item);
});
// Ensure the filtered array matches the original
if (count($validated_order) !== count($order)) {
wp_send_json_error(esc_html__('Invalid order items.', 'admin-menu-optimizer'));
exit;
}
// Save the sanitized order
update_option('admo_menu_order', $validated_order);
wp_send_json_success(esc_html__('Menu order saved.', 'admin-menu-optimizer'));
exit;
}
/**
* Save menu item title via AJAX.
*
* @return void
*/
public function save_title() {
// Verify nonce first
check_ajax_referer('admo_nonce', 'nonce');
// Sanitize and validate inputs in one step
$slug = isset($_POST['slug']) ?
sanitize_text_field(wp_unslash($_POST['slug'])) :
null;
$new_title = isset($_POST['new_title']) ?
sanitize_text_field(wp_unslash($_POST['new_title'])) :
null;
// Comprehensive input validation
if (empty($slug) || empty($new_title)) {
wp_send_json_error(esc_html__('Invalid data. Slug and title are required.', 'admin-menu-optimizer'));
exit;
}
// Additional validation for slug and title
if (strlen($slug) > 100 || strlen($new_title) > 100) {
wp_send_json_error(esc_html__('Slug or title is too long.', 'admin-menu-optimizer'));
exit;
}
// Retrieve and update stored titles
$stored_titles = get_option('admo_menu_titles', []);
$stored_titles[$slug] = $new_title;
// Update option with sanitized data
update_option('admo_menu_titles', $stored_titles);
wp_send_json_success(esc_html__('Menu title updated.', 'admin-menu-optimizer'));
exit;
}
/**
* Apply custom menu titles.
*
* @return void
*/
public function apply_custom_titles() {
global $menu;
$stored_titles = get_option('admo_menu_titles', []);
foreach ($menu as &$item) {
$slug = $item[2];
if (!empty($stored_titles[$slug])) {
$item[0] = $stored_titles[$slug];
}
}
}
/**
* Apply custom menu order.
*
* @param array $menu_order The current menu order.
*
* @return array
*/
public function apply_custom_order($menu_order) {
$stored_order = get_option('admo_menu_order', []);
if (!empty($stored_order)) {
return $stored_order;
}
return $menu_order;
}
/**
* Run the plugin.
*
* @return Admo_Admin_Menu_Optimizer
*/
public static function init() {
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
}
/**
* Initialize the plugin.
*
* @return Admo_Admin_Menu_Optimizer
*/
function admo_admin_menu_optimizer() {
return Admo_Admin_Menu_Optimizer::init();
}
// Kick-off the plugin.
admo_admin_menu_optimizer();