diff --git a/admin/js/wp-allstars-admin.js b/admin/js/wp-allstars-admin.js
deleted file mode 100644
index c46ed0c..0000000
--- a/admin/js/wp-allstars-admin.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * WP Allstars Admin Script
- *
- * Handles UI interactions in the admin settings
- */
-(function($) {
- 'use strict';
-
- // Document ready handler
- $(document).ready(function() {
- // Handle toggle switches
- $('.wp-toggle-switch input[type="checkbox"]').on('change', function() {
- var $this = $(this);
- var option = $this.attr('id');
- var value = $this.is(':checked') ? 1 : 0;
-
- // Don't handle the admin color scheme toggle here - it has its own handler
- if (option === 'wp_allstars_admin_color_scheme') {
- return;
- }
-
- // Show update notification
- var $notification = $this.closest('label').find('.wp-setting-notification');
- if ($notification.length === 0) {
- $notification = $('Saving...');
- $this.closest('label').append($notification);
- } else {
- $notification.text('Saving...').removeClass('error').show();
- }
-
- // Save the option via AJAX
- $.ajax({
- url: wpAllstars.ajaxurl,
- type: 'POST',
- data: {
- action: 'wp_allstars_update_option',
- nonce: wpAllstars.nonce,
- option: option,
- value: value
- },
- success: function(response) {
- if (response.success) {
- $notification.text('Saved!');
- setTimeout(function() {
- $notification.fadeOut(300);
- }, 2000);
- } else {
- $notification.text('Error').addClass('error');
- console.error('Error saving option:', response.data);
- }
- },
- error: function(xhr, status, error) {
- $notification.text('Error').addClass('error');
- console.error('AJAX error:', error);
- }
- });
- });
-
- // Toggle expandable panels
- $('.wp-allstars-toggle-header').on('click', function() {
- var $this = $(this);
- var $settings = $this.next('.wp-allstars-toggle-settings');
- var isExpanded = $this.attr('aria-expanded') === 'true';
-
- // Toggle aria-expanded attribute
- $this.attr('aria-expanded', !isExpanded);
-
- // Toggle settings visibility
- $settings.slideToggle(200);
- });
- });
-})(jQuery);
\ No newline at end of file
diff --git a/admin/js/wp-allstars-admin-colors.js b/admin/js/wpallstars-admin-colors.js
similarity index 100%
rename from admin/js/wp-allstars-admin-colors.js
rename to admin/js/wpallstars-admin-colors.js
diff --git a/admin/js/wpallstars-admin.js b/admin/js/wpallstars-admin.js
new file mode 100644
index 0000000..c9f16d4
--- /dev/null
+++ b/admin/js/wpallstars-admin.js
@@ -0,0 +1,139 @@
+/**
+ * WP Allstars Admin Script
+ *
+ * Handles generic UI interactions in the admin settings page.
+ * Specific AJAX handlers for themes/plugins are handled in inline scripts
+ * loaded by their respective managers.
+ */
+(function($) {
+ 'use strict';
+
+ $(document).ready(function() {
+
+ // --- General UI Enhancements ---
+
+ // Toggle expandable sections/panels (using consistent class names)
+ $('.wpallstars-toggle-header').on('click', function() {
+ var $this = $(this);
+ var $content = $this.next('.wpallstars-toggle-content'); // Use a consistent content class
+ var isExpanded = $this.attr('aria-expanded') === 'true';
+
+ // Toggle ARIA attribute for accessibility
+ $this.attr('aria-expanded', !isExpanded);
+
+ // Toggle content visibility with animation
+ $content.slideToggle(200);
+
+ // Optional: Toggle an icon class on the header (e.g., dashicons-arrow-down / dashicons-arrow-up)
+ $this.find('.dashicons').toggleClass('dashicons-arrow-down dashicons-arrow-up');
+ });
+
+ // Initialize state for expandable sections (ensure icons are correct on load)
+ $('.wpallstars-toggle-header').each(function() {
+ var $this = $(this);
+ var isExpanded = $this.attr('aria-expanded') === 'true';
+ if (isExpanded) {
+ $this.find('.dashicons').removeClass('dashicons-arrow-down').addClass('dashicons-arrow-up');
+ $this.next('.wpallstars-toggle-content').show();
+ } else {
+ $this.find('.dashicons').removeClass('dashicons-arrow-up').addClass('dashicons-arrow-down');
+ $this.next('.wpallstars-toggle-content').hide();
+ }
+ });
+
+
+ // --- Settings Save Logic (Example for simple toggles/inputs via AJAX) ---
+
+ // AJAX saving for specific settings (e.g., checkboxes, selects)
+ // Add the class 'wpallstars-ajax-save' and 'data-setting-key="your_key"' to the input elements
+ $('.wpallstars-settings-wrap').on('change', 'input.wpallstars-ajax-save, select.wpallstars-ajax-save', function(e) {
+ e.preventDefault();
+
+ const $input = $(this);
+ const settingKey = $input.data('setting-key'); // Get key from data attribute
+ let settingValue;
+
+ // Determine the value based on input type
+ if ($input.is(':checkbox')) {
+ settingValue = $input.is(':checked'); // Send true/false
+ } else {
+ settingValue = $input.val(); // Get value from select or other inputs
+ }
+
+ // Find the feedback element (could be next to the input, or a general area)
+ let $feedback = $input.siblings('.wpallstars-ajax-feedback');
+ if (!$feedback.length) {
+ // Fallback to a general feedback area if specific one not found
+ $feedback = $input.closest('td, p, div').find('.wpallstars-ajax-feedback');
+ if (!$feedback.length) {
+ // If still no feedback area, maybe create one dynamically or log error
+ console.error('WPAllstars: Feedback element not found for AJAX save.', $input);
+ return; // Stop if no feedback area
+ }
+ }
+
+ // Check if settingKey is valid
+ if (!settingKey) {
+ console.error('WPAllstars: Missing data-setting-key attribute for AJAX save.', $input);
+ $feedback.removeClass('spinner success is-active').addClass('error').text('Error: Missing setting key.').show();
+ return;
+ }
+
+ // Show spinner/updating message
+ if ($feedback.hasClass('spinner')) {
+ // If it's already designed as a spinner container
+ $feedback.removeClass('success error').addClass('is-active').show();
+ // Optionally add text: $feedback.text(wpallstars.l10n.updating || 'Updating...');
+ } else {
+ $feedback.removeClass('success error').addClass('spinner is-active').text(wpallstars.l10n.updating || 'Updating...').show();
+ }
+
+ // Use localized strings and the specific nonce
+ // $feedback.text(wpallstars.l10n.updating || 'Updating...'); // Moved spinner text above
+
+
+ // Perform AJAX request
+ $.ajax({
+ url: wpallstars.ajaxurl,
+ type: 'POST',
+ data: {
+ action: 'wpallstars_update_option', // The action hook in WPALLSTARS_Admin_Manager
+ nonce: wpallstars.update_option_nonce, // Use the specific nonce
+ setting_key: settingKey, // Send the setting key
+ setting_value: settingValue // Send the setting value
+ },
+ success: function(response) {
+ if (response.success) {
+ $feedback.removeClass('spinner is-active error').addClass('success').text(response.data || wpallstars.l10n.success || 'Saved!');
+ // Optionally fade out the success message after a delay
+ setTimeout(function() {
+ // $feedback.fadeOut();
+ // Or just remove the text/class if element should stay
+ $feedback.removeClass('success').text('');
+ }, 3000);
+ } else {
+ const errorMessage = response.data || wpallstars.l10n.error || 'Error';
+ $feedback.removeClass('spinner is-active success').addClass('error').text(errorMessage);
+ console.error('WPAllstars AJAX Error:', response.data);
+ }
+ },
+ error: function(jqXHR, textStatus, errorThrown) {
+ $feedback.removeClass('spinner is-active success').addClass('error').text(wpallstars.l10n.error || 'Error');
+ console.error('WPAllstars AJAX Request Failed:', textStatus, errorThrown);
+ },
+ // Removed complete: function() { ... } as feedback is handled in success/error
+ });
+ });
+
+ // --- Tab Handling ---
+ // Basic tab switching is handled by WordPress core CSS (.nav-tab-active) and page reloads.
+ // If you need AJAX tab loading in the future, implement it here.
+
+ // --- Initialization ---
+ // Add any code that needs to run on page load after elements are ready.
+ // Example: Initialize color pickers if added via WPALLSTARS_Settings_Manager
+
+
+ }); // End document ready
+
+})(jQuery);
\ No newline at end of file
diff --git a/admin/js/wp-allstars-ui-enhancements.js b/admin/js/wpallstars-ui-enhancements.js
similarity index 100%
rename from admin/js/wp-allstars-ui-enhancements.js
rename to admin/js/wpallstars-ui-enhancements.js
diff --git a/includes/class-wp-allstars-admin-colors.php b/includes/class-wp-allstars-admin-colors.php
deleted file mode 100644
index 1c198d2..0000000
--- a/includes/class-wp-allstars-admin-colors.php
+++ /dev/null
@@ -1,169 +0,0 @@
-id) || strpos($screen->id, 'wp-allstars') === false) {
- return;
- }
-
- wp_enqueue_script(
- 'wp-allstars-color-toggle',
- plugin_dir_url(dirname(__FILE__)) . 'admin/js/wp-allstars-admin-colors.js',
- array('jquery'),
- WP_ALLSTARS_VERSION,
- true
- );
-
- wp_localize_script('wp-allstars-color-toggle', 'wpAllstarsColors', array(
- 'ajax_url' => admin_url('admin-ajax.php'),
- 'nonce' => wp_create_nonce('wp_allstars_color_nonce'),
- 'option_name' => $this->option_name,
- ));
- }
-
- /**
- * Set the admin color scheme based on user preference
- */
- public function set_admin_color_scheme() {
- // Only apply for administrators
- if (!current_user_can('manage_options')) {
- return;
- }
-
- // Get current user
- $user_id = get_current_user_id();
- if (!$user_id) {
- return;
- }
-
- // Check if our option is enabled
- $enable_modern = get_option($this->option_name, false);
-
- // Set the appropriate color scheme
- if ($enable_modern) {
- // Use modern scheme if available, otherwise use default
- $this->set_user_color_scheme($user_id, $this->modern_scheme);
- }
- }
-
- /**
- * Set a user's color scheme
- *
- * @param int $user_id The user ID
- * @param string $scheme The color scheme to set
- */
- private function set_user_color_scheme($user_id, $scheme) {
- // Check if the scheme exists
- global $_wp_admin_css_colors;
-
- // If the scheme doesn't exist, use the default
- if (!isset($_wp_admin_css_colors[$scheme])) {
- $scheme = $this->default_scheme;
- }
-
- // Update the user's color scheme
- update_user_meta($user_id, 'admin_color', $scheme);
- }
-
- /**
- * Handle AJAX request to update color scheme
- */
- public function handle_color_scheme_update() {
- // Verify nonce
- if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'wp_allstars_color_nonce')) {
- wp_send_json_error('Invalid nonce');
- }
-
- // Verify user can manage options
- if (!current_user_can('manage_options')) {
- wp_send_json_error('Insufficient permissions');
- }
-
- // Get the new value
- $enabled = isset($_POST['enabled']) ? (bool) $_POST['enabled'] : false;
-
- // Update the option
- update_option($this->option_name, $enabled);
-
- // Get current user
- $user_id = get_current_user_id();
-
- // Set the color scheme
- if ($enabled) {
- $this->set_user_color_scheme($user_id, $this->modern_scheme);
- $message = 'Modern admin colors enabled';
- } else {
- $this->set_user_color_scheme($user_id, $this->default_scheme);
- $message = 'Default admin colors restored';
- }
-
- // Send success response
- wp_send_json_success(array(
- 'message' => $message,
- 'enabled' => $enabled,
- ));
- }
-
- /**
- * Check if modern color scheme is enabled
- *
- * @return bool Whether modern color scheme is enabled
- */
- public function is_modern_color_scheme_enabled() {
- return (bool) get_option($this->option_name, false);
- }
-}
\ No newline at end of file
diff --git a/includes/class-wp-allstars-auto-upload.php b/includes/class-wp-allstars-auto-upload.php
deleted file mode 100644
index 8e37990..0000000
--- a/includes/class-wp-allstars-auto-upload.php
+++ /dev/null
@@ -1,136 +0,0 @@
- false));
- if (!$options['auto_upload_images']) {
- return $content;
- }
-
- // Regular expression to find image URLs
- $pattern = '/]+src=[\'"]([^\'"]+)[\'"][^>]*>/i';
-
- return preg_replace_callback($pattern, array($this, 'process_image_url'), $content);
- }
-
- /**
- * Process individual image URL
- *
- * @param array $matches Regex matches
- * @return string Updated img tag
- */
- private function process_image_url($matches) {
- if (empty($matches[1])) {
- return $matches[0];
- }
-
- $url = $matches[1];
-
- // Skip if already a local URL
- if ($this->is_local_url($url)) {
- return $matches[0];
- }
-
- try {
- $local_url = $this->upload_image($url);
- if ($local_url) {
- return str_replace($url, $local_url, $matches[0]);
- }
- } catch (Exception $e) {
- // Trigger error action for logging
- do_action('wp_allstars_image_upload_error', esc_url($url), $e->getMessage());
- }
-
- return $matches[0];
- }
-
- /**
- * Check if URL is local
- *
- * @param string $url URL to check
- * @return boolean
- */
- private function is_local_url($url) {
- $site_url = parse_url(get_site_url(), PHP_URL_HOST);
- $image_host = parse_url($url, PHP_URL_HOST);
- return $site_url === $image_host;
- }
-
- /**
- * Upload external image to media library
- *
- * @param string $url External image URL
- * @return string|false Local URL on success, false on failure
- * @throws Exception If download or upload fails
- */
- private function upload_image($url) {
- $file_array = array(
- 'name' => sanitize_file_name(basename($url))
- );
-
- // Download file to temp location
- $file_array['tmp_name'] = download_url($url);
-
- if (is_wp_error($file_array['tmp_name'])) {
- throw new Exception('Failed to download image: ' . $file_array['tmp_name']->get_error_message());
- }
-
- // Check file type for security
- $wp_filetype = wp_check_filetype_and_ext($file_array['tmp_name'], $file_array['name']);
- if (!$wp_filetype['type']) {
- unlink($file_array['tmp_name']);
- throw new Exception('Invalid file type');
- }
-
- // Upload the file to media library
- $attachment_id = media_handle_sideload($file_array, 0);
-
- if (is_wp_error($attachment_id)) {
- unlink($file_array['tmp_name']);
- throw new Exception('Failed to upload image: ' . $attachment_id->get_error_message());
- }
-
- return wp_get_attachment_url($attachment_id);
- }
-
- /**
- * Log errors to WordPress debug log
- *
- * @param string $url URL that failed
- * @param string $error Error message
- */
- public function log_error($url, $error) {
- if (WP_DEBUG) {
- error_log(sprintf(
- '[WP ALLSTARS] Auto Upload Images Error - URL: %s, Error: %s',
- esc_url_raw($url),
- sanitize_text_field($error)
- ));
- }
- }
-}
\ No newline at end of file
diff --git a/includes/class-wp-allstars-sync-guard.php b/includes/class-wp-allstars-sync-guard.php
deleted file mode 100644
index dcce228..0000000
--- a/includes/class-wp-allstars-sync-guard.php
+++ /dev/null
@@ -1,60 +0,0 @@
-';
- echo '
WP Allstars: Plugin files are currently syncing. The plugin functionality is temporarily disabled to prevent errors. Please try again in a moment.
';
- echo '
';
- }
-}
\ No newline at end of file
diff --git a/includes/class-wp-allstars-ui-enhancements.php b/includes/class-wp-allstars-ui-enhancements.php
deleted file mode 100644
index baed8b9..0000000
--- a/includes/class-wp-allstars-ui-enhancements.php
+++ /dev/null
@@ -1,330 +0,0 @@
-init_components();
-
- // Ensure toggle functionality works
- add_action('admin_footer', array($this, 'ensure_toggle_functionality'), 99);
- }
-
- /**
- * Enqueue CSS and JavaScript assets
- */
- public function enqueue_assets($hook) {
- // Only load on WP Allstars pages
- if (strpos($hook, 'wp-allstars') === false) {
- return;
- }
-
- // Already registered in main plugin file, but ensure they're enqueued
- wp_enqueue_style('wp-allstars-admin');
- wp_enqueue_script('wp-allstars-admin');
-
- // Add UI enhancements script
- wp_enqueue_script(
- 'wp-allstars-ui-enhancements',
- plugin_dir_url(dirname(__FILE__)) . 'admin/js/wp-allstars-ui-enhancements.js',
- array('jquery', 'wp-allstars-admin'),
- WP_ALLSTARS_VERSION,
- true
- );
-
- // Add enhanced UI styles
- wp_enqueue_style(
- 'wp-allstars-ui-enhancements',
- plugin_dir_url(dirname(__FILE__)) . 'admin/css/wp-allstars-ui-enhancements.css',
- array('wp-allstars-admin'),
- WP_ALLSTARS_VERSION
- );
-
- // Localize script with settings
- wp_localize_script('wp-allstars-ui-enhancements', 'wpAllstarsUI', array(
- 'ajaxurl' => admin_url('ajax.php'),
- 'nonce' => wp_create_nonce('wp_allstars_ui_nonce'),
- ));
- }
-
- /**
- * Add body class for enhanced UI
- */
- public function add_body_class($classes) {
- if (isset($_GET['page']) && strpos($_GET['page'], 'wp-allstars') !== false) {
- $classes .= ' wp-allstars-enhanced-ui';
- }
- return $classes;
- }
-
- /**
- * Initialize UI components
- */
- private function init_components() {
- // Add accordion functionality
- add_action('admin_footer', array($this, 'render_accordion_template'));
-
- // Add card component
- add_action('admin_footer', array($this, 'render_card_template'));
-
- // Add notification system
- add_action('admin_footer', array($this, 'render_notification_template'));
- }
-
- /**
- * Ensure toggle switch functionality
- * This adds JS to reinitialize toggle switch handlers after our enhanced UI is applied
- */
- public function ensure_toggle_functionality() {
- // Only on WP Allstars pages
- if (!isset($_GET['page']) || strpos($_GET['page'], 'wp-allstars') === false) {
- return;
- }
-
- // Get the nonce value
- $nonce = wp_create_nonce('wp-allstars-nonce');
-
- ?>
-
-
-
-
-
-
-
- id, 'wpallstars') === false) {
+ return; // Exit if not a WP Allstars page.
+ }
+
+
+ // Enqueue the specific JS file for color handling.
+ wp_enqueue_script(
+ 'wpallstars-admin-colors-script', // More specific handle
+ WPALLSTARS_URL . 'admin/js/wpallstars-admin-colors.js', // Use constant for URL
+ array('jquery'),
+ WPALLSTARS_VERSION, // Use constant for version
+ true // Load in footer
+ );
+
+ // Localize data needed by the script.
+ wp_localize_script(
+ 'wpallstars-admin-colors-script', // Must match the script handle
+ 'wpallstarsAdminColorsData', // JavaScript object name
+ array(
+ 'ajax_url' => admin_url('admin-ajax.php'),
+ 'nonce' => wp_create_nonce($this->ajax_nonce_action),
+ 'ajax_action' => 'wpallstars_update_admin_color_scheme', // The action hook name
+ 'l10n' => [ // Localization strings
+ 'saving' => __('Saving...', WPALLSTARS_TEXT_DOMAIN),
+ 'saved' => __('Saved', WPALLSTARS_TEXT_DOMAIN),
+ 'error' => __('Error', WPALLSTARS_TEXT_DOMAIN),
+ ]
+ )
+ );
+ }
+
+ /**
+ * Apply the selected admin color scheme for the current user upon admin initialization.
+ *
+ * Checks if the user has the capability and if the setting is enabled.
+ */
+ public function apply_user_admin_color_scheme() {
+ // Ensure the current user has the capability to change schemes (usually 'manage_options' or similar).
+ if (!current_user_can('manage_options')) { // Adjust capability if needed
+ return;
+ }
+
+ $user_id = get_current_user_id();
+ if (!$user_id) {
+ return; // Should not happen in admin_init, but good practice.
+ }
+
+ // Check if the modern scheme override is enabled in settings.
+ $scheme_to_apply = $this->is_modern_color_scheme_enabled()
+ ? $this->modern_scheme_slug
+ : $this->default_scheme_slug;
+
+ // Get the user's currently saved color scheme preference.
+ $current_user_scheme = get_user_meta($user_id, 'admin_color', true);
+
+ // Only update the user's meta if the desired scheme differs from their current one.
+ // This prevents unnecessary database writes on every admin page load.
+ if ($current_user_scheme !== $scheme_to_apply) {
+ $this->update_user_color_scheme_preference($user_id, $scheme_to_apply);
+ }
+ }
+
+ /**
+ * Update a user's color scheme preference in their user meta.
+ *
+ * @param int $user_id The ID of the user to update.
+ * @param string $scheme_slug The slug of the color scheme to set (e.g., 'modern', 'fresh').
+ */
+ private function update_user_color_scheme_preference($user_id, $scheme_slug) {
+ // WordPress handles validation internally, but ensure the scheme exists if crucial.
+ // global $_wp_admin_css_colors;
+ // if (!isset($_wp_admin_css_colors[$scheme_slug])) {
+ // $scheme_slug = $this->default_scheme_slug; // Fallback to default
+ // }
+
+ // Update the 'admin_color' user meta field.
+ update_user_meta($user_id, 'admin_color', $scheme_slug);
+ }
+
+ /**
+ * Handle the AJAX request to enable/disable the modern color scheme override.
+ *
+ * Verifies nonce, checks user capabilities, updates the option,
+ * updates the current user's scheme immediately, and sends a JSON response.
+ */
+ public function handle_ajax_color_scheme_update() {
+ // 1. Verify Nonce for security.
+ check_ajax_referer($this->ajax_nonce_action, 'nonce'); // Dies on failure
+
+ // 2. Check User Capabilities.
+ if (!current_user_can('manage_options')) { // Ensure user can change this setting
+ wp_send_json_error(array('message' => __('Insufficient permissions.', WPALLSTARS_TEXT_DOMAIN)), 403); // 403 Forbidden
+ }
+
+ // 3. Sanitize and Validate Input.
+ // Expecting 'enabled' to be 'true' or 'false' (as strings from JS).
+ $is_enabled_input = isset($_POST['enabled']) ? sanitize_text_field($_POST['enabled']) : 'false';
+ $is_enabled = ($is_enabled_input === 'true'); // Convert string 'true' to boolean true
+
+ // 4. Update the Option in the Database.
+ $options = get_option($this->options_key, []);
+ $options[$this->color_scheme_option_key] = $is_enabled ? 1 : 0; // Store as 1 or 0
+ $update_success = update_option($this->options_key, $options);
+
+ // 5. Update Current User's Scheme Immediately for instant feedback.
+ $user_id = get_current_user_id();
+ $scheme_to_set = $is_enabled ? $this->modern_scheme_slug : $this->default_scheme_slug;
+ $this->update_user_color_scheme_preference($user_id, $scheme_to_set);
+
+ // 6. Send JSON Response.
+ if ($update_success) {
+ wp_send_json_success(array(
+ 'message' => $is_enabled
+ ? __('Modern admin color scheme enabled.', WPALLSTARS_TEXT_DOMAIN)
+ : __('Default admin color scheme restored.', WPALLSTARS_TEXT_DOMAIN),
+ 'new_state' => $is_enabled, // Send back the new state
+ ));
+ } else {
+ // Option update might have failed, or the value was unchanged.
+ // Check if the value was actually unchanged.
+ $current_db_options = get_option($this->options_key, []);
+ $current_db_value = isset($current_db_options[$this->color_scheme_option_key]) ? (bool)$current_db_options[$this->color_scheme_option_key] : false;
+ if ($current_db_value === $is_enabled) {
+ wp_send_json_success(array(
+ 'message' => __('Setting unchanged.', WPALLSTARS_TEXT_DOMAIN),
+ 'new_state' => $is_enabled,
+ 'unchanged' => true
+ ));
+ } else {
+ wp_send_json_error(array('message' => __('Failed to save setting.', WPALLSTARS_TEXT_DOMAIN)), 500); // 500 Internal Server Error
+ }
+ }
+ }
+
+ /**
+ * Check if the modern color scheme override is enabled in the plugin settings.
+ *
+ * @return bool True if enabled, false otherwise.
+ */
+ public function is_modern_color_scheme_enabled() {
+ $options = get_option($this->options_key, []);
+ // Check if the specific key exists and is set to 1 (or true). Default to false if not set.
+ return isset($options[$this->color_scheme_option_key]) && $options[$this->color_scheme_option_key] == 1;
+ }
+}
\ No newline at end of file
diff --git a/includes/class-wpallstars-auto-upload.php b/includes/class-wpallstars-auto-upload.php
new file mode 100644
index 0000000..eaeec79
--- /dev/null
+++ b/includes/class-wpallstars-auto-upload.php
@@ -0,0 +1,220 @@
+ 0)); // Default to disabled (0)
+
+ // Check if the 'auto_upload_images' setting is enabled (expecting '1' if enabled)
+ if (empty($workflow_options['auto_upload_images']) || $workflow_options['auto_upload_images'] != '1') {
+ return $content; // Feature disabled, return original content.
+ }
+
+ // Regular expression to find tags and capture their src attribute.
+ // This pattern is case-insensitive (i) and handles single or double quotes.
+ $pattern = '/]+src=[\'"]([^\'"]+)[\'"][^>]*>/i';
+
+ // Use preg_replace_callback to process each found image URL individually.
+ $modified_content = preg_replace_callback($pattern, array($this, 'replace_image_url_callback'), $content);
+
+ // Return the modified content, or the original if preg_replace_callback encountered an error.
+ return (null === $modified_content) ? $content : $modified_content;
+ }
+
+ /**
+ * Callback function for preg_replace_callback. Processes a single image match.
+ *
+ * @param array $matches An array of matches from preg_replace_callback.
+ * $matches[0] is the full tag.
+ * $matches[1] is the URL from the src attribute.
+ * @return string The original tag if the URL is local or upload fails,
+ * or the modified tag with the new local URL.
+ */
+ private function replace_image_url_callback($matches) {
+ // Ensure the URL capture group exists.
+ if (empty($matches[1])) {
+ return $matches[0]; // Return original tag if no URL found.
+ }
+
+ $external_url = trim($matches[1]);
+
+ // Validate the URL format (basic check).
+ if (filter_var($external_url, FILTER_VALIDATE_URL) === false) {
+ // Optionally log invalid URL format if needed
+ // $this->log_upload_error($external_url, 'Invalid URL format detected');
+ return $matches[0]; // Invalid URL, skip.
+ }
+
+ // Skip if the URL is already pointing to the local site.
+ if ($this->is_local_image_url($external_url)) {
+ return $matches[0]; // Already local, no need to process.
+ }
+
+ try {
+ // Attempt to upload the image.
+ $local_url = $this->sideload_image($external_url);
+
+ // If upload is successful, replace the URL in the img tag.
+ if ($local_url) {
+ // Use str_replace for simple replacement within the matched tag.
+ // This is generally safe as we're replacing the exact matched URL string.
+ return str_replace($external_url, esc_url($local_url), $matches[0]);
+ }
+ } catch (Exception $e) {
+ // Trigger a WordPress action to log the error.
+ // Pass the original external URL and the exception message.
+ do_action('wpallstars_image_upload_error', esc_url($external_url), $e->getMessage());
+ }
+
+ // Return the original tag if the upload failed or an exception occurred.
+ return $matches[0];
+ }
+
+ /**
+ * Check if a given image URL belongs to the local WordPress site.
+ *
+ * Compares the host of the image URL with the host of the site URL.
+ *
+ * @param string $url The image URL to check.
+ * @return bool True if the URL is local, false otherwise.
+ */
+ private function is_local_image_url($url) {
+ // Get the host part of the site URL (e.g., '[www.example.com](www.example.com)').
+ $site_host = parse_url(get_site_url(), PHP_URL_HOST);
+
+ // Get the host part of the image URL.
+ $image_host = parse_url($url, PHP_URL_HOST);
+
+ // Return true if the hosts match, false otherwise.
+ // Use strtolower for case-insensitive comparison.
+ return !empty($site_host) && !empty($image_host) && strtolower($site_host) === strtolower($image_host);
+ }
+
+ /**
+ * Download an external image and upload it to the WordPress media library.
+ *
+ * Uses WordPress core functions download_url() and media_handle_sideload().
+ *
+ * @param string $external_url The URL of the external image to download.
+ * @return string|false The local URL of the uploaded image on success, false on failure.
+ * @throws Exception If downloading or uploading fails, or if the file type is invalid.
+ */
+ private function sideload_image($external_url) {
+ // Ensure required WordPress core files for media handling are loaded.
+ require_once ABSPATH . 'wp-admin/includes/media.php';
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ require_once ABSPATH . 'wp-admin/includes/image.php'; // For potential image processing
+
+ $file_array = array();
+ // Sanitize filename derived from the URL path.
+ $file_array['name'] = sanitize_file_name(basename(parse_url($external_url, PHP_URL_PATH)));
+
+ // Download the file to a temporary location.
+ // Set timeout to prevent long waits for unresponsive URLs.
+ $timeout_seconds = 15;
+ $temp_file_path = download_url($external_url, $timeout_seconds);
+
+ // Check for download errors.
+ if (is_wp_error($temp_file_path)) {
+ // Clean up temporary file if it exists, even on error
+ if (file_exists($temp_file_path)) {
+ @unlink($temp_file_path);
+ }
+ throw new Exception(sprintf('Failed to download image: %s', $temp_file_path->get_error_message()));
+ }
+
+ // Check file type for security. Associate with the temporary file.
+ $file_array['tmp_name'] = $temp_file_path;
+ $wp_filetype = wp_check_filetype_and_ext($file_array['tmp_name'], $file_array['name']);
+
+ // Check if the file type is allowed by WordPress.
+ if (empty($wp_filetype['ext']) || empty($wp_filetype['type']) || !in_array(strtolower($wp_filetype['ext']), get_allowed_mime_types()) && !in_array($wp_filetype['type'], get_allowed_mime_types())) {
+ unlink($file_array['tmp_name']); // Clean up the temporary file.
+ throw new Exception(sprintf('Invalid or disallowed file type detected: %s', $wp_filetype['type'] ?: 'Unknown'));
+ }
+
+
+ // Upload the file from the temporary location to the media library.
+ // The post ID '0' indicates the attachment is not associated with any specific post.
+ $attachment_id = media_handle_sideload($file_array, 0);
+
+ // Check for errors during the sideloading process.
+ if (is_wp_error($attachment_id)) {
+ unlink($file_array['tmp_name']); // Clean up the temporary file.
+ throw new Exception(sprintf('Failed to upload image: %s', $attachment_id->get_error_message()));
+ }
+
+ // Get the URL of the newly uploaded attachment.
+ $local_url = wp_get_attachment_url($attachment_id);
+
+ // Check if a valid URL was returned.
+ if (!$local_url) {
+ // Attachment likely created, but URL failed. Try to clean up attachment? Difficult.
+ // Best practice is often to leave the attachment and log the URL retrieval error.
+ unlink($file_array['tmp_name']); // Still clean up temp file
+ throw new Exception(sprintf('Failed to get attachment URL after upload (Attachment ID: %d)', $attachment_id));
+ }
+
+ // Return the local URL on success.
+ return $local_url;
+ }
+
+ /**
+ * Log image upload errors using WordPress's error logging mechanism.
+ *
+ * Only logs if WP_DEBUG is enabled.
+ *
+ * @param string $failed_url The external URL that failed to upload.
+ * @param string $error_message The specific error message.
+ */
+ public function log_upload_error($failed_url, $error_message) {
+ // Check if WordPress debugging is enabled.
+ if (defined('WP_DEBUG') && WP_DEBUG === true) {
+ error_log(sprintf(
+ '[WPALLSTARS Auto Upload] Error: Failed to process image "%s". Reason: %s',
+ esc_url_raw($failed_url), // Use raw URL for logging
+ sanitize_text_field($error_message)
+ ));
+ }
+ }
+}
\ No newline at end of file
diff --git a/includes/class-wpallstars-sync-guard.php b/includes/class-wpallstars-sync-guard.php
new file mode 100644
index 0000000..f45e9e8
--- /dev/null
+++ b/includes/class-wpallstars-sync-guard.php
@@ -0,0 +1,291 @@
+is_enabled()) {
+ // Hook into pre-save actions for posts and potentially terms
+ // Priority 10 is default, allowing other plugins to modify data first.
+ add_filter('wp_insert_post_data', array($this, 'check_post_sync_conflict'), 10, 3); // Use 3 args for postarr, update, WP_Error
+ // Hook into post-save action to update meta or release locks.
+ add_action('save_post', array($this, 'update_post_sync_meta'), 20, 2); // Run later to capture final state
+
+ // --- Term Hooks (Example - Not included in this edit for brevity) ---
+ // --- Optional AJAX Lock Release (Not included in this edit for brevity) ---
+ }
+ }
+
+ /**
+ * Check if Sync Guard is enabled in settings.
+ *
+ * @return bool True if enabled, false otherwise.
+ */
+ private function is_enabled() {
+ $options = get_option($this->options_key, []);
+ // Ensure the key exists and is explicitly set to '1' or true.
+ return !empty($options[$this->setting_key_enabled]) && $options[$this->setting_key_enabled] == 1;
+ }
+
+ /**
+ * Get the configured sync guard mode from settings.
+ *
+ * @return string The mode ('timestamp', 'lock', or default 'timestamp').
+ */
+ private function get_mode() {
+ $options = get_option($this->options_key, []);
+ $mode = isset($options[$this->setting_key_mode]) ? sanitize_key($options[$this->setting_key_mode]) : 'timestamp';
+ // Ensure mode is one of the allowed values
+ return in_array($mode, ['timestamp', 'lock'], true) ? $mode : 'timestamp'; // Default to timestamp
+ }
+
+ /**
+ * Check for potential sync conflicts before saving post data.
+ * Runs on the 'wp_insert_post_data' filter.
+ *
+ * @param array $data An array of slashed post data.
+ * @param array $postarr An array of sanitized, but otherwise unmodified post data.
+ * @param bool|WP_Error $update Whether this is an update. WP_Error if validation failed.
+ * @return array|WP_Error The original $data or a WP_Error if a conflict is detected and blocking is configured.
+ */
+ public function check_post_sync_conflict($data, $postarr, $update) {
+ // --- Basic Checks ---
+ // 1. Only act on updates (existing posts).
+ // 2. Ignore if validation already failed ($update is WP_Error).
+ // 3. Ensure we have a Post ID.
+ // 4. Check if the post type is relevant.
+ if (!$update || is_wp_error($update) || empty($postarr['ID']) || !$this->is_relevant_post_type($postarr['post_type'])) {
+ return $data; // Pass through if not applicable
+ }
+
+ $post_id = absint($postarr['ID']);
+ $mode = $this->get_mode();
+ $current_user_id = get_current_user_id(); // Can be 0 for system processes
+
+ // --- Timestamp Mode Logic ---
+ if ($mode === 'timestamp') {
+ $last_sync_time_str = get_post_meta($post_id, $this->meta_key_last_sync, true);
+ $post_modified_gmt_str = isset($data['post_modified_gmt']) ? $data['post_modified_gmt'] : get_post_field('post_modified_gmt', $post_id);
+
+ // Convert to timestamps for comparison
+ $last_sync_ts = !empty($last_sync_time_str) ? strtotime($last_sync_time_str) : 0;
+ $post_modified_ts = !empty($post_modified_gmt_str) ? strtotime($post_modified_gmt_str) : 0;
+
+ // Check if a sync occurred *after* the last modification recorded in the database.
+ // This implies an external update happened since the content being edited was loaded.
+ if ($last_sync_ts > 0 && $post_modified_ts > 0 && $last_sync_ts > $post_modified_ts) {
+ // Conflict detected: External sync is newer than the post's last known modification time.
+ // Option 1: Block the save (disruptive) - Uncomment if needed
+ /*
+ return new WP_Error('sync_conflict_timestamp',
+ __('Warning: This content appears to have been updated by an external sync process since you started editing. Saving now would overwrite those changes. Please reload the content.', WPALLSTARS_TEXT_DOMAIN)
+ );
+ */
+
+ // Option 2: Allow save but log it (less disruptive)
+ $log_message = sprintf(
+ '[WPALLSTARS Sync Guard] Post ID %d: Potential timestamp conflict detected. Save allowed. Last Sync: %s, DB Post Modified: %s',
+ $post_id,
+ esc_html($last_sync_time_str),
+ esc_html($post_modified_gmt_str)
+ );
+ error_log($log_message);
+ }
+ }
+ // --- Lock Mode Logic ---
+ elseif ($mode === 'lock') {
+ $lock_data = get_post_meta($post_id, $this->meta_key_lock, true);
+
+ if (!empty($lock_data) && is_array($lock_data)) {
+ $lock_time = isset($lock_data['time']) ? (int) $lock_data['time'] : 0;
+ $lock_user = isset($lock_data['user']) ? (int) $lock_data['user'] : -1; // -1 for unknown/system lock owner
+
+ // Check if lock is expired
+ if ((time() - $lock_time) > $this->lock_timeout) {
+ $this->release_post_lock($post_id, 'timeout_expired');
+ // Lock released due to timeout, proceed to acquire new lock below.
+ }
+ // Check if lock is held by someone else and not expired
+ elseif ($lock_user !== $current_user_id) {
+ $locked_by_user = ($lock_user > 0) ? get_userdata($lock_user) : null;
+ $locked_by_name = $locked_by_user ? $locked_by_user->display_name : __('another process', WPALLSTARS_TEXT_DOMAIN);
+ $time_ago = human_time_diff($lock_time);
+
+ $error_message = sprintf(
+ // translators: %1$s: User display name or 'another process'. %2$s: Time duration (e.g., '5 minutes ago').
+ __('Sync Conflict: This content is currently locked for editing by %1$s (since %2$s ago). Please try again later or ask them to finish.', WPALLSTARS_TEXT_DOMAIN),
+ esc_html($locked_by_name),
+ esc_html($time_ago)
+ );
+ // Block the save by returning a WP_Error
+ return new WP_Error('sync_lock_conflict', $error_message);
+ }
+ // Else: Lock is held by the current user, allow save to proceed.
+ }
+
+ // If we reached here (no conflict or lock expired), attempt to acquire or update the lock.
+ // This ensures the lock is held throughout the save process.
+ $this->acquire_post_lock($post_id, $current_user_id);
+ }
+
+ // No conflict or conflict handled (e.g., logging), allow data to pass through.
+ return $data;
+ }
+
+ /**
+ * Update sync-related meta data after a post is saved.
+ * Runs on the 'save_post' action.
+ *
+ * @param int $post_id Post ID.
+ * @param WP_Post $post Post object.
+ */
+ public function update_post_sync_meta($post_id, $post) {
+ // Prevent infinite loops and ensure post type is relevant
+ if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
+ if (wp_is_post_revision($post_id)) return;
+ if (!$this->is_relevant_post_type($post->post_type)) return;
+
+ $mode = $this->get_mode();
+
+ // Update timestamp after successful save (if in timestamp mode)
+ if ($mode === 'timestamp') {
+ // Update our custom meta field to reflect the latest save time.
+ // This uses the post_modified_gmt from the saved post object.
+ update_post_meta($post_id, $this->meta_key_last_sync, $post->post_modified_gmt);
+ }
+ // Release lock after successful save (if in lock mode)
+ elseif ($mode === 'lock') {
+ // Only release if the lock is held by the current user who initiated the save.
+ $lock_data = get_post_meta($post_id, $this->meta_key_lock, true);
+ $current_user_id = get_current_user_id();
+ if (!empty($lock_data) && is_array($lock_data) && isset($lock_data['user']) && $lock_data['user'] === $current_user_id) {
+ $this->release_post_lock($post_id, 'save_completed_by_user');
+ }
+ // Locks held by other users or expired locks should have been handled earlier or will time out.
+ }
+ }
+
+ /**
+ * Acquire or update a lock on a post for the current user/process.
+ *
+ * @param int $post_id Post ID.
+ * @param int $user_id User ID acquiring the lock (0 for system/unknown).
+ * @return bool True on success, false on failure.
+ */
+ private function acquire_post_lock($post_id, $user_id) {
+ $lock_data = array(
+ 'user' => (int) $user_id,
+ 'time' => time(), // Current server time
+ );
+ // Use update_post_meta - it handles both adding and updating the meta key.
+ $result = update_post_meta($post_id, $this->meta_key_lock, $lock_data);
+ if (!$result) {
+ error_log("[WPALLSTARS Sync Guard] Failed to acquire/update lock for Post ID {$post_id} by User ID {$user_id}.");
+ }
+ return (bool) $result;
+ }
+
+ /**
+ * Release a lock on a post.
+ *
+ * @param int $post_id Post ID.
+ * @param string $reason Optional reason for logging purposes.
+ * @return bool True if the meta key was deleted, false otherwise.
+ */
+ private function release_post_lock($post_id, $reason = '') {
+ $log_message = sprintf(
+ '[WPALLSTARS Sync Guard] Releasing lock for Post ID %d. Reason: %s',
+ absint($post_id),
+ sanitize_text_field($reason)
+ );
+ error_log($log_message);
+ // Deleting the meta key removes the lock.
+ return delete_post_meta($post_id, $this->meta_key_lock);
+ }
+
+ /**
+ * Check if the post type is relevant for sync guarding.
+ * Post types can be configured via the 'wpallstars_sync_guard_post_types' filter.
+ *
+ * @param string $post_type The post type slug.
+ * @return bool True if the post type should be guarded, false otherwise.
+ */
+ private function is_relevant_post_type($post_type) {
+ // Default relevant post types
+ $default_types = array('post', 'page');
+ // Allow themes/plugins to filter the list of guarded post types
+ $relevant_types = apply_filters('wpallstars_sync_guard_post_types', $default_types);
+ // Ensure it's an array before checking
+ return is_array($relevant_types) && in_array($post_type, $relevant_types, true);
+ }
+
+ // --- Methods for Term Guarding (Example Structure - requires implementation) ---
+ // Term guarding logic would go here, mirroring the post logic but using
+ // term meta (get/update/delete_term_meta) and term-related hooks.
+
+}
\ No newline at end of file
diff --git a/includes/class-wpallstars-ui-enhancements.php b/includes/class-wpallstars-ui-enhancements.php
new file mode 100644
index 0000000..31d6c1a
--- /dev/null
+++ b/includes/class-wpallstars-ui-enhancements.php
@@ -0,0 +1,176 @@
+init_components();
+ }
+
+ /**
+ * Enqueue CSS and JavaScript assets
+ */
+ public function enqueue_assets($hook) {
+ // Only load on WPALLSTARS pages
+ if (strpos($hook, 'wpallstars') === false) {
+ return;
+ }
+
+ // Already registered in main plugin file, but ensure they're enqueued
+ wp_enqueue_style('wpallstars-admin');
+ wp_enqueue_script('wpallstars-admin');
+
+ // Add UI enhancements script
+ wp_enqueue_script(
+ 'wpallstars-ui-enhancements',
+ WPALLSTARS_URL . 'admin/js/wpallstars-ui-enhancements.js',
+ array('jquery', 'wpallstars-admin'),
+ WPALLSTARS_VERSION,
+ true
+ );
+
+ // Add enhanced UI styles
+ wp_enqueue_style(
+ 'wpallstars-ui-enhancements',
+ WPALLSTARS_URL . 'admin/css/wpallstars-ui-enhancements.css',
+ array('wpallstars-admin'),
+ WPALLSTARS_VERSION
+ );
+
+ // Localize script with settings
+ wp_localize_script('wpallstars-ui-enhancements', 'wpallstarsUI', array(
+ 'ajaxurl' => admin_url('admin-ajax.php'),
+ 'nonce' => wp_create_nonce('wpallstars_ui_nonce'),
+ ));
+ }
+
+ /**
+ * Add body class for enhanced UI
+ */
+ public function add_body_class($classes) {
+ if (isset($_GET['page']) && strpos($_GET['page'], 'wpallstars') !== false) {
+ $classes .= ' wpallstars-ui-enabled';
+ }
+ return $classes;
+ }
+
+ /**
+ * Initialize UI components
+ */
+ private function init_components() {
+ // Add accordion functionality
+ add_action('admin_footer', array($this, 'render_accordion_template'));
+
+ // Add card component
+ add_action('admin_footer', array($this, 'render_card_template'));
+
+ // Add notification system
+ add_action('admin_footer', array($this, 'render_notification_template'));
+ }
+
+ /**
+ * Render accordion template
+ */
+ public function render_accordion_template() {
+ // Only on WPALLSTARS pages
+ if (!isset($_GET['page']) || strpos($_GET['page'], 'wpallstars') === false) {
+ return;
+ }
+
+ ?>
+
+
+
+
+
+ ';
- echo '
WP Allstars: Plugin files are currently syncing. The plugin functionality is temporarily disabled to prevent errors. Please try again in a moment.
';
- echo '
';
- });
- }
- // Exit early to prevent loading other files
- return;
-}
-
-// Load the sync guard for future use and more advanced sync detection
-wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . 'includes/class-wp-allstars-sync-guard.php');
-
-/**
- * Plugin activation hook
- */
-function wp_allstars_activate() {
- // Setup initial config
-}
-register_activation_hook(__FILE__, 'wp_allstars_activate');
-
-// Core includes
-wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . 'includes/class-wp-allstars-auto-upload.php');
-wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . 'includes/class-wp-allstars-admin-colors.php');
-wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . 'includes/class-wp-allstars-ui-enhancements.php');
-
-// Admin includes
-if (is_admin()) {
- $admin_includes = array(
- 'admin/includes/class-admin-manager.php',
- 'admin/includes/class-settings-manager.php',
- 'admin/includes/class-theme-manager.php',
- 'admin/includes/class-workflow-manager.php',
- 'admin/includes/class-tools-manager.php',
- 'admin/includes/class-hosting-manager.php',
- 'admin/includes/class-pro-plugins-manager.php',
- 'admin/includes/class-plugin-manager.php',
- 'admin/includes/class-free-plugins-manager.php',
- 'admin/includes/class-readme-manager.php'
- );
-
- foreach ($admin_includes as $file) {
- wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . $file);
- }
-
- // Settings and data
- wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . 'admin/data/pro-plugins.php');
- wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . 'admin/data/readme.php');
-
- // Admin settings
- wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . 'admin/settings.php');
-}
-
-/**
- * Auto Upload feature initialization
- *
- * Initialize the Auto Upload feature when a user is logged in
- */
-function wp_allstars_init_auto_upload() {
- // Only initialize for logged-in users
- if (is_user_logged_in()) {
- new WP_Allstars_Auto_Upload();
- }
-}
-add_action('init', 'wp_allstars_init_auto_upload');
-
-/**
- * Initialize core features
- */
-function wp_allstars_init_features() {
- // Initialize Admin Colors feature if the class exists
- if (class_exists('WP_Allstars_Admin_Colors')) {
- new WP_Allstars_Admin_Colors();
- }
-
- // Initialize UI Enhancements if the class exists
- if (class_exists('WP_Allstars_UI_Enhancements')) {
- new WP_Allstars_UI_Enhancements();
- }
-}
-add_action('plugins_loaded', 'wp_allstars_init_features');
\ No newline at end of file
diff --git a/wpallstars-plugin.php b/wpallstars-plugin.php
new file mode 100644
index 0000000..0840771
--- /dev/null
+++ b/wpallstars-plugin.php
@@ -0,0 +1,199 @@
+';
+ printf(
+ '
%s: %s
',
+ esc_html__( 'WP Allstars', WPALLSTARS_TEXT_DOMAIN ),
+ esc_html__( 'Plugin files are currently syncing. Functionality is temporarily disabled. Please try again shortly.', WPALLSTARS_TEXT_DOMAIN )
+ );
+ echo '
';
+ });
+ }
+ return; // Exit early to prevent loading other files during sync
+}
+
+// --- Core Includes ---
+// Load Sync Guard (if used for more advanced detection)
+wpallstars_require_if_exists(WPALLSTARS_PATH . 'includes/class-wpallstars-sync-guard.php');
+// Core features
+wpallstars_require_if_exists(WPALLSTARS_PATH . 'includes/class-wpallstars-auto-upload.php');
+wpallstars_require_if_exists(WPALLSTARS_PATH . 'includes/class-wpallstars-admin-colors.php');
+wpallstars_require_if_exists(WPALLSTARS_PATH . 'includes/class-wpallstars-ui-enhancements.php');
+
+// --- Admin Includes ---
+if (is_admin() || (defined('DOING_AJAX') && DOING_AJAX)) { // Load admin for AJAX requests too
+ $admin_includes = [
+ 'admin/includes/class-admin-manager.php',
+ 'admin/includes/class-settings-manager.php',
+ 'admin/includes/class-theme-manager.php',
+ 'admin/includes/class-workflow-manager.php',
+ 'admin/includes/class-pro-plugins-manager.php',
+ 'admin/includes/class-tools-manager.php',
+ 'admin/includes/class-hosting-manager.php',
+ 'admin/includes/class-plugin-manager.php', // Assuming this exists
+ 'admin/includes/class-free-plugins-manager.php',
+ 'admin/includes/class-readme-manager.php'
+ ];
+
+ foreach ($admin_includes as $relative_path) {
+ // No need to anticipate renaming anymore, use the correct path directly
+ wpallstars_require_if_exists(WPALLSTARS_PATH . $relative_path);
+ }
+
+ // Data files (ensure these are still needed and paths are correct)
+ wpallstars_require_if_exists(WPALLSTARS_PATH . 'admin/data/pro-plugins.php');
+ wpallstars_require_if_exists(WPALLSTARS_PATH . 'admin/data/readme.php');
+
+ // Load admin settings initialization file (if it sets up hooks, etc.)
+ // Deprecated: Settings should be handled by Settings_Manager and Admin_Manager
+ // wpallstars_require_if_exists(WPALLSTARS_PATH . 'admin/settings.php');
+}
+
+/**
+ * Plugin activation hook.
+ * Used for setting up default options, database tables (if any), etc.
+ */
+function wpallstars_activate() {
+ // Example: Set default options on first activation
+ if (get_option('wpallstars_version') === false) {
+ update_option('wpallstars_version', WPALLSTARS_VERSION);
+ // Add other default options here if needed
+ // update_option('wpallstars_options', ['feature_x_enabled' => 1]);
+ }
+ // Optional: Clear rewrite rules if custom post types or taxonomies are added
+ // flush_rewrite_rules();
+}
+register_activation_hook(__FILE__, 'wpallstars_activate');
+
+/**
+ * Plugin deactivation hook.
+ * Used for cleanup tasks if necessary.
+ */
+function wpallstars_deactivate() {
+ // Example: Remove scheduled tasks
+ // wp_clear_scheduled_hook('wpallstars_daily_task');
+ // Optional: Clear rewrite rules
+ // flush_rewrite_rules();
+}
+register_deactivation_hook(__FILE__, 'wpallstars_deactivate');
+
+
+/**
+ * Load the plugin text domain for localization.
+ */
+function wpallstars_load_textdomain() {
+ load_plugin_textdomain(
+ WPALLSTARS_TEXT_DOMAIN,
+ false,
+ dirname(WPALLSTARS_BASENAME) . '/languages'
+ );
+}
+add_action('plugins_loaded', 'wpallstars_load_textdomain');
+
+
+/**
+ * Initialize core plugin features after plugins are loaded.
+ * This ensures that all necessary WordPress functions and classes are available.
+ */
+function wpallstars_init_features() {
+ // Initialize Core Features
+ if (class_exists('WPALLSTARS_Admin_Colors')) {
+ new WPALLSTARS_Admin_Colors();
+ }
+ if (class_exists('WPALLSTARS_UI_Enhancements')) {
+ new WPALLSTARS_UI_Enhancements();
+ }
+
+ // Initialize Admin Area (if in admin context or AJAX)
+ if ((is_admin() || (defined('DOING_AJAX') && DOING_AJAX)) && class_exists('WPALLSTARS_Admin_Manager')) {
+ WPALLSTARS_Admin_Manager::instance(); // Use singleton pattern if implemented
+ }
+}
+add_action('plugins_loaded', 'wpallstars_init_features', 10); // Priority 10 is standard
+
+
+/**
+ * Initialize Auto Upload feature later on 'init'.
+ * This ensures the user is logged in and potentially allows other plugins to load first.
+ */
+function wpallstars_init_auto_upload() {
+ // Only initialize for logged-in users
+ if (is_user_logged_in() && class_exists('WPALLSTARS_Auto_Upload')) {
+ new WPALLSTARS_Auto_Upload();
+ }
+}
+add_action('init', 'wpallstars_init_auto_upload');
+
+
+/**
+ * Add settings link on the plugins page.
+ *
+ * @param array $links Existing plugin action links.
+ * @return array Modified plugin action links.
+ */
+function wpallstars_add_settings_link($links) {
+ $settings_link = sprintf(
+ '%s',
+ esc_url(admin_url('admin.php?page=wpallstars-settings')), // Match the menu slug from Admin_Manager
+ esc_html__( 'Settings', WPALLSTARS_TEXT_DOMAIN )
+ );
+ array_unshift($links, $settings_link); // Add link to the beginning
+ return $links;
+}
+add_filter('plugin_action_links_' . WPALLSTARS_BASENAME, 'wpallstars_add_settings_link');
+
+// --- End of Plugin ---
\ No newline at end of file