diff --git a/admin/includes/class-theme-manager.php b/admin/includes/class-theme-manager.php new file mode 100644 index 0000000..33f8677 --- /dev/null +++ b/admin/includes/class-theme-manager.php @@ -0,0 +1,332 @@ +<?php +/** + * Theme Manager Class + * + * Handles the display and management of recommended themes. + */ + +// If this file is called directly, abort. +if (!defined('WPINC')) { + die; +} + +class WP_Allstars_Theme_Manager { + + /** + * Initialize the class + */ + public static function init() { + // Register AJAX handlers + add_action('wp_ajax_wp_allstars_get_themes', array(self::class, 'ajax_get_themes')); + add_action('wp_ajax_wp_allstars_activate_theme', array(self::class, 'activate_theme')); + + // Cache clearing hooks + add_action('upgrader_process_complete', array(self::class, 'clear_theme_cache'), 10, 0); + add_action('switch_theme', array(self::class, 'clear_theme_cache')); + + // Enqueue assets when needed + add_action('admin_enqueue_scripts', array(self::class, 'enqueue_scripts')); + } + + /** + * Enqueue scripts and styles for the theme tab + */ + public static function enqueue_scripts($hook) { + if (strpos($hook, 'wp-allstars') === false) { + return; + } + + // Only load on theme tab + if (!isset($_GET['tab']) || $_GET['tab'] !== 'theme') { + return; + } + + // Required for theme installation + require_once ABSPATH . 'wp-admin/includes/theme.php'; + wp_enqueue_script('theme-install'); + wp_enqueue_script('updates'); + add_thickbox(); + + // Styles + wp_enqueue_style('wp-allstars-admin', plugins_url('css/wp-allstars-admin.css', dirname(__FILE__))); + wp_enqueue_style('wp-allstars-plugins', plugins_url('css/wp-allstars-plugins.css', dirname(__FILE__))); + + // Add inline script for theme loading and interaction + wp_add_inline_script('wp-allstars-admin', self::get_theme_scripts()); + } + + /** + * Get theme scripts for inline inclusion + */ + private static function get_theme_scripts() { + return ' + jQuery(document).ready(function($) { + if ($("#wpa-theme-list").length && $("#wpa-theme-list").is(":empty")) { + var $container = $("#wpa-theme-list"); + var $loadingOverlay = $("<div class=\"wp-allstars-loading-overlay\"><span class=\"spinner is-active\"></span></div>"); + + // Show loading overlay + $container.css("position", "relative").append($loadingOverlay); + + // AJAX request to get themes + $.ajax({ + url: ajaxurl, + type: "POST", + data: { + action: "wp_allstars_get_themes", + _wpnonce: wpAllstars.nonce + }, + success: function(response) { + $loadingOverlay.remove(); + if (response.success) { + $container.html(response.data); + // Initialize theme action buttons + if (typeof initThemeHandlers === "function") { + initThemeHandlers(); + } + } else { + $container.html("<div class=\"notice notice-error\"><p>" + response.data + "</p></div>"); + } + }, + error: function(xhr, status, error) { + $loadingOverlay.remove(); + $container.html("<div class=\"notice notice-error\"><p>Failed to load themes. Please try again. Error: " + error + "</p></div>"); + console.error("AJAX Error:", xhr.responseText); + } + }); + } + + // Initialize theme handlers + window.initThemeHandlers = function() { + // Activate theme + $(".activate-now").click(function(e) { + e.preventDefault(); + + var $button = $(this); + var slug = $button.data("slug"); + var name = $button.data("name"); + var nonce = $button.data("nonce"); + + $button.text("Activating...").addClass("updating-message").attr("disabled", true); + + $.ajax({ + url: ajaxurl, + type: "POST", + data: { + action: "wp_allstars_activate_theme", + theme: slug, + _wpnonce: nonce + }, + success: function(response) { + if (response.success) { + $button.removeClass("updating-message").addClass("updated-message").text("Activated"); + setTimeout(function() { + window.location.reload(); + }, 1000); + } else { + $button.removeClass("updating-message").text("Error"); + alert("Error: " + response.data); + } + }, + error: function(xhr, status, error) { + $button.removeClass("updating-message").text("Error"); + alert("Error: " + error); + } + }); + }); + }; + }); + '; + } + + /** + * Display the theme tab content + */ + public static function display_tab_content() { + ?> + <div id="wpa-theme-list" class="wpa-theme-container"> + <!-- Theme content will be loaded via AJAX --> + <div class="wp-allstars-loading-overlay"> + <span class="spinner is-active"></span> + <p>Loading theme data...</p> + </div> + </div> + <?php + } + + /** + * Get cached theme + */ + public static function get_cached_theme() { + $cache_key = 'wp_allstars_theme_kadence'; + return get_transient($cache_key); + } + + /** + * Set cached theme + */ + public static function set_cached_theme($data) { + $cache_key = 'wp_allstars_theme_kadence'; + set_transient($cache_key, $data, 12 * HOUR_IN_SECONDS); + } + + /** + * Clear theme cache + */ + public static function clear_theme_cache() { + delete_transient('wp_allstars_theme_kadence'); + } + + /** + * AJAX endpoint for getting themes + */ + public static function ajax_get_themes() { + error_log('WP ALLSTARS: Theme AJAX handler started'); + + // Check nonce with the correct action name + if (!isset($_POST['_wpnonce'])) { + error_log('WP ALLSTARS: No nonce provided'); + wp_send_json_error('No security token provided.'); + return; + } + + if (!check_ajax_referer('wp-allstars-nonce', '_wpnonce', false)) { + error_log('WP ALLSTARS: Invalid nonce: ' . sanitize_text_field($_POST['_wpnonce'])); + wp_send_json_error('Invalid security token sent.'); + return; + } + + if (!current_user_can('install_themes')) { + error_log('WP ALLSTARS: User does not have permission to install themes'); + wp_send_json_error('Permission denied'); + return; + } + + error_log('WP ALLSTARS: Starting theme fetch process'); + + try { + error_log('WP ALLSTARS: Fetching theme data for kadence'); + + // Check if we have cached data first + $theme_data = self::get_cached_theme(); + + // If no cached data, fetch from API + if (empty($theme_data)) { + error_log('WP ALLSTARS: No cached theme data, fetching from API'); + + // Get theme data with minimal fields + $theme_data = themes_api('theme_information', array( + 'slug' => 'kadence', + 'fields' => array( + 'sections' => false, + 'description' => true, + 'rating' => true, + 'ratings' => false, + 'downloaded' => true, + 'download_link' => true, + 'last_updated' => true, + 'homepage' => true, + 'tags' => false, + 'screenshot_url' => true, + 'version' => true, + 'requires' => true, + 'requires_php' => true, + 'active_installs' => true, + 'author' => true, + 'preview_url' => true, + ) + )); + + // Cache the result if successful + if (!is_wp_error($theme_data)) { + self::set_cached_theme($theme_data); + } + } else { + error_log('WP ALLSTARS: Using cached theme data'); + } + + if (is_wp_error($theme_data)) { + error_log('WP ALLSTARS Theme API Error: ' . $theme_data->get_error_message()); + wp_send_json_error('Theme API Error: ' . $theme_data->get_error_message()); + return; + } + + error_log('WP ALLSTARS: Successfully fetched theme data'); + + // Format author data + $author = ''; + if (is_string($theme_data->author)) { + $author = $theme_data->author; + } elseif (is_array($theme_data->author)) { + $author = isset($theme_data->author['display_name']) ? $theme_data->author['display_name'] : ''; + } + + error_log('WP ALLSTARS: Theme data retrieved, generating HTML'); + + // Generate custom HTML for the theme using our template partial + ob_start(); + include(plugin_dir_path(dirname(__FILE__)) . 'partials/theme-panel.php'); + $html = ob_get_clean(); + + if (empty($html)) { + error_log('WP ALLSTARS: Empty HTML generated'); + wp_send_json_error('Failed to generate theme display'); + return; + } + + error_log('WP ALLSTARS: Successfully generated theme display, HTML length: ' . strlen($html)); + wp_send_json_success($html); + exit; // Ensure we exit after sending the JSON response + + } catch (Exception $e) { + error_log('WP ALLSTARS Theme loading exception: ' . $e->getMessage()); + error_log('WP ALLSTARS Theme loading exception trace: ' . $e->getTraceAsString()); + wp_send_json_error('Theme loading error: ' . $e->getMessage()); + } catch (Error $e) { + error_log('WP ALLSTARS Theme loading error: ' . $e->getMessage()); + error_log('WP ALLSTARS Theme loading error trace: ' . $e->getTraceAsString()); + wp_send_json_error('Theme loading error: ' . $e->getMessage()); + } + } + + /** + * AJAX handler for theme activation + */ + public static function activate_theme() { + // Debug information + error_log('Theme activation AJAX request received: ' . print_r($_POST, true)); + + // Check nonce with the correct action name + if (!check_ajax_referer('wp-allstars-nonce', '_wpnonce', false)) { + error_log('Theme activation failed: Invalid nonce'); + wp_send_json_error('Invalid security token sent.'); + return; + } + + if (!current_user_can('switch_themes')) { + error_log('Theme activation failed: Permission denied'); + wp_send_json_error('Permission denied'); + return; + } + + $theme = isset($_POST['theme']) ? sanitize_text_field($_POST['theme']) : ''; + if (empty($theme)) { + error_log('Theme activation failed: No theme specified'); + wp_send_json_error('No theme specified'); + return; + } + + // Get the theme object + $theme_obj = wp_get_theme($theme); + if (!$theme_obj->exists()) { + error_log('Theme activation failed: Theme does not exist - ' . $theme); + wp_send_json_error('Theme does not exist'); + return; + } + + // Set the new theme + switch_theme($theme); + error_log('Theme activation success - ' . $theme); + wp_send_json_success(); + } +} diff --git a/admin/settings.php b/admin/settings.php index 13e14ed..43e3078 100644 --- a/admin/settings.php +++ b/admin/settings.php @@ -46,214 +46,20 @@ require_once dirname(__FILE__) . '/includes/class-plugin-manager.php'; require_once dirname(__FILE__) . '/includes/class-pro-plugins-manager.php'; require_once dirname(__FILE__) . '/includes/class-settings-manager.php'; require_once dirname(__FILE__) . '/includes/class-tools-manager.php'; +require_once dirname(__FILE__) . '/includes/class-theme-manager.php'; // Initialize the managers WP_Allstars_Plugin_Manager::init(); WP_Allstars_Pro_Plugins_Manager::init(); WP_Allstars_Settings_Manager::init(); WP_Allstars_Tools_Manager::init(); +WP_Allstars_Theme_Manager::init(); // Remove the old plugins API filter since we're handling everything in the AJAX endpoint remove_filter('plugins_api_result', 'wp_allstars_plugins_api_result'); -// Add transient caching for theme data -function wp_allstars_get_cached_theme() { - $cache_key = 'wp_allstars_theme_kadence'; - return get_transient($cache_key); -} - -function wp_allstars_set_cached_theme($data) { - $cache_key = 'wp_allstars_theme_kadence'; - set_transient($cache_key, $data, 12 * HOUR_IN_SECONDS); -} - -// Add AJAX endpoint for theme -function wp_allstars_ajax_get_themes() { - error_log('WP ALLSTARS: Theme AJAX handler started'); - - // Check nonce with the correct action name - if (!isset($_POST['_wpnonce'])) { - error_log('WP ALLSTARS: No nonce provided'); - wp_send_json_error('No security token provided.'); - return; - } - - if (!check_ajax_referer('wp-allstars-nonce', '_wpnonce', false)) { - error_log('WP ALLSTARS: Invalid nonce: ' . sanitize_text_field($_POST['_wpnonce'])); - wp_send_json_error('Invalid security token sent.'); - return; - } - - if (!current_user_can('install_themes')) { - error_log('WP ALLSTARS: User does not have permission to install themes'); - wp_send_json_error('Permission denied'); - return; - } - - error_log('WP ALLSTARS: Starting theme fetch process'); - - try { - error_log('WP ALLSTARS: Fetching theme data for kadence'); - - // Check if we have cached data first - $theme_data = wp_allstars_get_cached_theme(); - - // If no cached data, fetch from API - if (empty($theme_data)) { - error_log('WP ALLSTARS: No cached theme data, fetching from API'); - - // Get theme data with minimal fields - $theme_data = themes_api('theme_information', array( - 'slug' => 'kadence', - 'fields' => array( - 'sections' => false, - 'description' => true, - 'rating' => true, - 'ratings' => false, - 'downloaded' => true, - 'download_link' => true, - 'last_updated' => true, - 'homepage' => true, - 'tags' => false, - 'screenshot_url' => true, - 'version' => true, - 'requires' => true, - 'requires_php' => true, - 'active_installs' => true, - 'author' => true, - 'preview_url' => true, - ) - )); - - // Cache the result if successful - if (!is_wp_error($theme_data)) { - wp_allstars_set_cached_theme($theme_data); - } - } else { - error_log('WP ALLSTARS: Using cached theme data'); - } - - if (is_wp_error($theme_data)) { - error_log('WP ALLSTARS Theme API Error: ' . $theme_data->get_error_message()); - wp_send_json_error('Theme API Error: ' . $theme_data->get_error_message()); - return; - } - - error_log('WP ALLSTARS: Successfully fetched theme data'); - - // Format author data - $author = ''; - if (is_string($theme_data->author)) { - $author = $theme_data->author; - } elseif (is_array($theme_data->author)) { - $author = isset($theme_data->author['display_name']) ? $theme_data->author['display_name'] : ''; - } - - error_log('WP ALLSTARS: Theme data retrieved, generating HTML'); - - // Generate custom HTML for the theme using our template partial - ob_start(); - include(plugin_dir_path(__FILE__) . 'partials/theme-panel.php'); - $html = ob_get_clean(); - - if (empty($html)) { - error_log('WP ALLSTARS: Empty HTML generated'); - wp_send_json_error('Failed to generate theme display'); - return; - } - - error_log('WP ALLSTARS: Successfully generated theme display, HTML length: ' . strlen($html)); - wp_send_json_success($html); - exit; // Ensure we exit after sending the JSON response - - } catch (Exception $e) { - error_log('WP ALLSTARS Theme loading exception: ' . $e->getMessage()); - error_log('WP ALLSTARS Theme loading exception trace: ' . $e->getTraceAsString()); - wp_send_json_error('Theme loading error: ' . $e->getMessage()); - } catch (Error $e) { - error_log('WP ALLSTARS Theme loading error: ' . $e->getMessage()); - error_log('WP ALLSTARS Theme loading error trace: ' . $e->getTraceAsString()); - wp_send_json_error('Theme loading error: ' . $e->getMessage()); - } -} -add_action('wp_ajax_wp_allstars_get_themes', 'wp_allstars_ajax_get_themes'); - -// Clear theme cache when themes are updated -function wp_allstars_clear_theme_cache() { - delete_transient('wp_allstars_theme_kadence'); -} -add_action('upgrader_process_complete', 'wp_allstars_clear_theme_cache', 10, 0); -add_action('switch_theme', 'wp_allstars_clear_theme_cache'); - -// Add AJAX handler for theme activation -function wp_allstars_activate_theme() { - // Debug information - error_log('Theme activation AJAX request received: ' . print_r($_POST, true)); - - // Check nonce with the correct action name - if (!check_ajax_referer('wp-allstars-nonce', '_wpnonce', false)) { - error_log('Theme activation failed: Invalid nonce'); - wp_send_json_error('Invalid security token sent.'); - return; - } - - if (!current_user_can('switch_themes')) { - error_log('Theme activation failed: Permission denied'); - wp_send_json_error('Permission denied'); - return; - } - - $theme = isset($_POST['theme']) ? sanitize_text_field($_POST['theme']) : ''; - if (empty($theme)) { - error_log('Theme activation failed: No theme specified'); - wp_send_json_error('No theme specified'); - return; - } - - // Get the theme object - $theme_obj = wp_get_theme($theme); - if (!$theme_obj->exists()) { - error_log('Theme activation failed: Theme does not exist - ' . $theme); - wp_send_json_error('Theme does not exist'); - return; - } - - if ($theme_obj->errors()) { - error_log('Theme activation failed: Theme has errors - ' . print_r($theme_obj->errors(), true)); - wp_send_json_error('Theme has errors'); - return; - } - - // Check if theme is already active - $current_theme = wp_get_theme(); - if ($current_theme->get_stylesheet() === $theme) { - error_log('Theme is already active: ' . $theme); - wp_send_json_success(array( - 'message' => 'Theme is already active', - 'customize_url' => admin_url('customize.php') - )); - return; - } - - // Switch the theme - error_log('Switching to theme: ' . $theme); - switch_theme($theme); - - // Check if the switch was successful - $active_theme = wp_get_theme(); - if ($active_theme->get_stylesheet() === $theme) { - error_log('Theme activated successfully: ' . $theme); - wp_send_json_success(array( - 'message' => 'Theme activated successfully', - 'customize_url' => admin_url('customize.php') - )); - } else { - error_log('Failed to activate theme: ' . $theme . ', active theme is: ' . $active_theme->get_stylesheet()); - wp_send_json_error('Failed to activate theme'); - } -} -add_action('wp_ajax_wp_allstars_activate_theme', 'wp_allstars_activate_theme'); +// Theme functionality has been moved to WP_Allstars_Theme_Manager class // Register settings page HTML function wp_allstars_settings_page() { @@ -315,54 +121,7 @@ function wp_allstars_settings_page() { } }); '); - } elseif ($active_tab === 'theme') { - wp_allstars_clear_theme_cache(); - require_once ABSPATH . 'wp-admin/includes/theme.php'; - wp_enqueue_script('theme-install'); - wp_enqueue_script('updates'); - add_thickbox(); - wp_enqueue_style('wp-allstars-admin', plugins_url('css/wp-allstars-admin.css', __FILE__)); - wp_enqueue_style('wp-allstars-plugins', plugins_url('css/wp-allstars-plugins.css', __FILE__)); - - // Add inline script to load themes directly - same approach as plugins tab - wp_add_inline_script('wp-allstars-admin', ' - jQuery(document).ready(function($) { - if ($("#wpa-theme-list").length && $("#wpa-theme-list").is(":empty")) { - var $container = $("#wpa-theme-list"); - var $loadingOverlay = $("<div class=\"wp-allstars-loading-overlay\"><span class=\"spinner is-active\"></span></div>"); - - // Show loading overlay - $container.css("position", "relative").append($loadingOverlay); - - // AJAX request to get themes - $.ajax({ - url: ajaxurl, - type: "POST", - data: { - action: "wp_allstars_get_themes", - _wpnonce: wpAllstars.nonce - }, - success: function(response) { - $loadingOverlay.remove(); - if (response.success) { - $container.html(response.data); - // Initialize theme action buttons - if (typeof initThemeHandlers === "function") { - initThemeHandlers(); - } - } else { - $container.html("<div class=\"notice notice-error\"><p>" + response.data + "</p></div>"); - } - }, - error: function(xhr, status, error) { - $loadingOverlay.remove(); - $container.html("<div class=\"notice notice-error\"><p>Failed to load themes. Please try again. Error: " + error + "</p></div>"); - console.error("AJAX Error:", xhr.responseText); - } - }); - } - }); - '); + // Theme-specific scripts and styles are now handled in WP_Allstars_Theme_Manager::enqueue_scripts } ?> <div class="wrap wp-allstars-wrap"> @@ -669,96 +428,7 @@ function wp_allstars_settings_page() { </div> <?php elseif ($active_tab == 'theme'): ?> <div class="tab-content" id="theme"> - <div id="wpa-theme-list" class="wpa-theme-container"> - <!-- Theme content will be loaded via AJAX --> - <div class="wp-allstars-loading-overlay"> - <span class="spinner is-active"></span> - <p>Loading theme data...</p> - </div> - </div> - <script> - jQuery(document).ready(function($) { - // Get the theme data - var $container = $('#wpa-theme-list'); - var $loadingOverlay = $('<div class="wp-allstars-loading-overlay"><span class="spinner is-active"></span></div>'); - - // Show loading overlay - $container.css('position', 'relative').append($loadingOverlay); - - // AJAX request to get theme - $.ajax({ - url: ajaxurl, - type: 'POST', - data: { - action: 'wp_allstars_get_themes', - _wpnonce: wpAllstars.nonce - }, - success: function(response) { - // Remove loading overlay - $loadingOverlay.remove(); - - if (response.success) { - // Append theme HTML - $container.html(response.data); - - // Initialize theme action buttons - initThemeHandlers(); - } else { - // Show error message - $container.html('<div class="notice notice-error"><p>' + response.data + '</p></div>'); - } - }, - error: function(xhr, status, error) { - // Remove loading overlay - $loadingOverlay.remove(); - - // Show error message - $container.html('<div class="notice notice-error"><p>Failed to load theme. Please try again. Error: ' + error + '</p></div>'); - console.error('AJAX Error:', xhr.responseText); - } - }); - - // Initialize theme handlers - window.initThemeHandlers = function() { - // Activate theme - $('.activate-now').click(function(e) { - e.preventDefault(); - - var $button = $(this); - var slug = $button.data('slug'); - var name = $button.data('name'); - var nonce = $button.data('nonce'); - - $button.text('Activating...').addClass('updating-message').attr('disabled', true); - - $.ajax({ - url: ajaxurl, - type: 'POST', - data: { - action: 'wp_allstars_activate_theme', - theme: slug, - _wpnonce: nonce - }, - success: function(response) { - if (response.success) { - $button.removeClass('updating-message').addClass('updated-message').text('Activated'); - setTimeout(function() { - window.location.reload(); - }, 1000); - } else { - $button.removeClass('updating-message').text('Error'); - alert('Error: ' + response.data); - } - }, - error: function(xhr, status, error) { - $button.removeClass('updating-message').text('Error'); - alert('Error: ' + error); - } - }); - }); - }; - }); - </script> + <?php WP_Allstars_Theme_Manager::display_tab_content(); ?> </div> <?php elseif ($active_tab == 'tools'): ?> <div class="tab-content" id="tools">