security = $security;
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_init', array($this, 'register_settings'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
// AJAX handlers
add_action('wp_ajax_synthseo_generate_key', array($this, 'ajax_generate_api_key'));
add_action('wp_ajax_synthseo_save_settings', array($this, 'ajax_save_settings'));
}
/**
* Add admin menu pages
*/
public function add_admin_menu() {
// Check capabilities first
if (!current_user_can('manage_options')) {
return;
}
// Main settings page
add_menu_page(
'SynthSEO Publisher',
'SynthSEO',
'manage_options',
'synthseo',
array($this, 'render_settings_page'),
'dashicons-admin-generic',
80
);
// Status/monitoring submenu
add_submenu_page(
'synthseo',
'Status & Monitoring',
'Status',
'manage_options',
'synthseo-status',
array($this, 'render_status_page')
);
// Debug submenu (only show in development mode)
if (defined('WP_DEBUG') && WP_DEBUG && defined('SYNTHSEO_DEVELOPMENT') && SYNTHSEO_DEVELOPMENT) {
add_submenu_page(
'synthseo',
'Debug Information',
'Debug',
'manage_options',
'synthseo-debug',
array($this, 'render_debug_page')
);
}
}
/**
* Register settings
*/
public function register_settings() {
register_setting('synthseo_settings', 'synthseo_api_key', array(
'sanitize_callback' => array($this, 'sanitize_api_key')
));
register_setting('synthseo_settings', 'synthseo_rate_limit', array(
'default' => 100,
'sanitize_callback' => 'absint'
));
register_setting('synthseo_settings', 'synthseo_enable_logging', array(
'default' => false,
'sanitize_callback' => 'rest_sanitize_boolean'
));
}
/**
* Get the correct build file name (handles hashed filenames in production)
*/
private function get_build_file($name) {
$build_dir = SYNTHSEO_PUBLISHER_PATH . 'build/';
// First check for non-hashed file (development)
if (file_exists($build_dir . $name . '.js')) {
return $name . '.js';
}
// Check for hashed files (production)
$files = glob($build_dir . $name . '.*.js');
if (!empty($files)) {
return basename($files[0]);
}
return false;
}
/**
* Get the asset file for a build
*/
private function get_asset_file($name) {
$build_dir = SYNTHSEO_PUBLISHER_PATH . 'build/';
// Check for non-hashed asset file
if (file_exists($build_dir . $name . '.asset.php')) {
return include($build_dir . $name . '.asset.php');
}
// Check for hashed asset files
$files = glob($build_dir . $name . '.*.asset.php');
if (!empty($files)) {
return include($files[0]);
}
return array('dependencies' => array(), 'version' => SYNTHSEO_VERSION);
}
/**
* Enqueue admin scripts and styles
*/
public function enqueue_admin_scripts($hook) {
// Only load on our admin pages
if (strpos($hook, 'synthseo') === false && strpos($hook, 'toplevel_page_synthseo') === false) {
return;
}
// Load React bundle (required, no fallback)
$admin_build = $this->get_build_file('admin');
if (!$admin_build) {
// If build doesn't exist, show error in admin
add_action('admin_notices', function() {
?>
get_asset_file('admin');
// Enqueue WordPress packages (these are core scripts from WordPress 5.0+)
// Note: wp-element is the WordPress React wrapper introduced with Gutenberg
if (wp_script_is('wp-element', 'registered')) {
wp_enqueue_script('wp-element');
}
if (wp_script_is('wp-components', 'registered')) {
wp_enqueue_script('wp-components');
}
if (wp_script_is('wp-i18n', 'registered')) {
wp_enqueue_script('wp-i18n');
}
if (wp_script_is('wp-api-fetch', 'registered')) {
wp_enqueue_script('wp-api-fetch');
}
wp_enqueue_script(
'synthseo-admin-react',
SYNTHSEO_PUBLISHER_URL . 'build/' . $admin_build,
array('wp-element', 'wp-components', 'wp-i18n', 'wp-api-fetch'),
$asset_file['version'],
true
);
// Ensure WordPress styles are loaded
wp_enqueue_style('wp-components');
// Check for CSS file
$css_file = str_replace('.js', '.css', $admin_build);
if (file_exists(SYNTHSEO_PUBLISHER_PATH . 'build/' . $css_file)) {
wp_enqueue_style(
'synthseo-admin-react',
SYNTHSEO_PUBLISHER_URL . 'build/' . $css_file,
array('wp-components'),
$asset_file['version']
);
}
// Pass data to React
wp_localize_script('synthseo-admin-react', 'synthseoAdmin', array(
'nonce' => wp_create_nonce('wp_rest'),
'apiUrl' => rest_url('synthseo/v2/'),
'ajaxUrl' => admin_url('admin-ajax.php'),
'adminUrl' => admin_url(),
'pluginUrl' => SYNTHSEO_PUBLISHER_URL,
'currentPage' => $hook,
'settings' => array(
'apiKey' => get_option('synthseo_api_key', ''),
'rateLimit' => get_option('synthseo_rate_limit', 100),
'enableLogging' => get_option('synthseo_enable_logging', false)
),
'version' => SYNTHSEO_VERSION,
'debugMode' => defined('WP_DEBUG') && WP_DEBUG && defined('SYNTHSEO_DEVELOPMENT') && SYNTHSEO_DEVELOPMENT
));
}
/**
* Render main settings page
*/
public function render_settings_page() {
// Security check
if (!current_user_can('manage_options')) {
wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'synthseo'));
}
// Handle form submissions
if (isset($_POST['submit']) && check_admin_referer('synthseo_settings_nonce')) {
$this->handle_settings_form();
}
// Generate API key if it doesn't exist
if (!get_option('synthseo_api_key')) {
update_option('synthseo_api_key', $this->security->generate_api_key());
}
// Always use React version - no jQuery fallback
?>
false, 'data' => 'Unauthorized')));
}
// Generate new API key
$new_key = $this->security->generate_api_key();
update_option('synthseo_api_key', $new_key);
wp_die(json_encode(array(
'success' => true,
'data' => array('api_key' => $new_key)
)));
}
/**
* AJAX handler for saving settings
*/
public function ajax_save_settings() {
// Check nonce and permissions
if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'wp_rest') || !current_user_can('manage_options')) {
wp_die(json_encode(array('success' => false, 'data' => 'Unauthorized')));
}
// Update settings
if (isset($_POST['synthseo_rate_limit'])) {
update_option('synthseo_rate_limit', absint(wp_unslash($_POST['synthseo_rate_limit'])));
}
if (isset($_POST['synthseo_enable_logging'])) {
$enable_logging = sanitize_text_field(wp_unslash($_POST['synthseo_enable_logging']));
update_option('synthseo_enable_logging', $enable_logging === '1');
}
wp_die(json_encode(array(
'success' => true,
'data' => array('message' => 'Settings saved successfully')
)));
}
/**
* Sanitize API key
*/
public function sanitize_api_key($value) {
return preg_replace('/[^a-zA-Z0-9]/', '', $value);
}
}