12 Commits

Author SHA1 Message Date
84525b07b9 Fix tab navigation styling to match reference plugin exactly: correct spacing, remove unwanted background, fix active tab color, and ensure proper styling of toggle elements 2025-03-24 04:10:20 +00:00
4cf485041f Improve tab styling and refactor plugin architecture. Make Hosting tab class fully self-contained by internalizing data structures, fix CSS to match reference plugin, and remove duplicate function declarations. 2025-03-24 03:59:41 +00:00
a7537a000c Fix tab navigation styling and CSS class consistency. Update all wp-allstars and wpa- prefixes to seoprostack prefix for CSS classes, text domains, and selectors. 2025-03-24 03:51:56 +00:00
3cf5f63174 Fix refactoring issues in SEO Pro Stack plugin: Update CSS classes, text domains, and file references from wp-allstars to seoprostack 2025-03-24 03:43:20 +00:00
a6fef6200f Fix critical error in WordPress site
- Fixed incorrect path to auto-upload class file
- Updated JavaScript to use proper AJAX URL reference
- Fixed syntax and indentation issues in the admin JS file
- Ensured correct class instantiation
2025-03-24 03:38:03 +00:00
1259843d4c Match reference plugin structure and styling
- Updated main plugin file to match reference plugin structure
- Fixed CSS class naming to consistently use seoprostack prefix
- Updated JavaScript selectors to match CSS classes
- Restored original plugin functionality while maintaining new naming conventions
- Ensured exact match with reference plugin appearance and behavior
2025-03-24 03:32:53 +00:00
0e7b8a5cc6 Maintain exact functionality with reference plugin
- Updated wp-seoprostack-plugin.php to match reference plugin behavior
- Fixed JavaScript variable references to use wpSeoProStack consistently
- Updated AJAX action names to use wp_seoprostack_ prefix
- Ensured plugin matches reference plugin exactly in appearance and functionality
- Maintained pure naming convention and code structure refactoring without functional changes
2025-03-24 03:20:58 +00:00
6fc054f2bf Fix plugin activation and critical errors
- Fixed class naming inconsistency in auto-upload functionality
- Resolved duplicate menu items by removing direct inclusion of settings.php
- Fixed JavaScript variable naming from seoProStack to wpSeoProStack
- Added deprecation notice to legacy auto-upload class
- Updated AJAX nonce references for consistency
2025-03-24 03:11:03 +00:00
7f4ea3ec0c Fix fatal error: Address naming inconsistencies from WP Allstars to SEO Pro Stack refactoring
- Resolved class naming conflicts in auto-upload functionality
- Fixed menu slug from 'wp-allstars' to 'seoprostack'
- Corrected AJAX nonce references for consistency
- Updated JavaScript variable name to 'wpSeoProStack'
- Added deprecation notice to legacy auto-upload class
2025-03-24 03:06:21 +00:00
f2929bb43a Fix fatal error: Rename SEO_Pro_Stack_Auto_Upload class to SEOProStack_Auto_Upload to match autoloader naming convention 2025-03-24 03:00:59 +00:00
918d19085a Test updated post-commit hook 2025-03-24 02:53:09 +00:00
aee3cb91e2 Rename plugin to wp-seoprostack-plugin, update file structure 2025-03-24 02:48:06 +00:00
35 changed files with 5907 additions and 799 deletions

143
README.md
View File

@ -1,18 +1,19 @@
# WP Allstars # SEO Pro Stack
A WordPress plugin that enhances your WordPress experience with curated plugins, themes, and optimization tools. A WordPress plugin that enhances your WordPress site's SEO capabilities with curated tools, themes, hosting recommendations, and optimization features.
## Description ## Description
WP Allstars is a powerful WordPress plugin designed to help site owners and developers optimize their WordPress installations. It provides a curated collection of recommended plugins, themes, and optimization tools all in one place. SEO Pro Stack is a powerful WordPress plugin designed to help site owners and developers optimize their WordPress installations for better search engine performance. It provides a curated collection of recommended plugins, themes, hosting providers, and optimization tools all in one place.
## Features ## Features
- **Curated Plugin Recommendations**: Browse and install recommended free plugins organized by category. - **Pro Plugin Recommendations**: Browse and discover premium SEO and performance plugins with detailed information.
- **Pro Plugin Showcase**: Discover premium plugins with direct links to purchase. - **Theme Recommendations**: Find SEO-friendly themes that are optimized for performance and user experience.
- **Theme Integration**: Easily install and activate the Kadence theme. - **Hosting Recommendations**: Choose the best hosting providers optimized for WordPress and SEO performance.
- **Workflow Optimization**: Tools to streamline your WordPress workflow. - **Advanced Settings**: Fine-tune your WordPress installation with SEO-focused configuration options.
- **Advanced Settings**: Fine-tune your WordPress installation with advanced configuration options. - **Tools**: Optimize your database, generate robots.txt, and access other helpful SEO utilities.
- **Auto Upload**: Automatically upload and organize images for better content management.
## Installation ## Installation
@ -23,90 +24,86 @@ WP Allstars is a powerful WordPress plugin designed to help site owners and deve
## Usage ## Usage
After activation, you'll find the WP Allstars menu in your WordPress admin sidebar. The plugin includes several tabs: After activation, you'll find the SEO Pro Stack menu in your WordPress admin sidebar. The plugin includes several tabs:
### General ### Pro Plugins
Basic settings for the plugin, including: Discover premium plugins specifically chosen to enhance your site's SEO performance:
- Auto Upload Images - SEO Plugins
- Image Optimization - Performance Plugins
- Cache Management - Content Plugins
- Analytics Plugins
### Theme
Find and install SEO-optimized themes:
- Fast-loading themes
- Schema-ready themes
- Mobile-optimized themes
- Accessibility-focused themes
### Advanced ### Advanced
Advanced configuration options for WordPress optimization: Advanced configuration options for WordPress optimization:
- Disable unnecessary WordPress features
- Remove query strings from static resources
- Disable XML-RPC, embeds, and emojis
- Remove REST API links and other unnecessary metadata
- Performance Settings ### Recommended Plugins
- Security Enhancements
- Development Tools
### Workflow Free and beneficial plugins that complement the SEO Pro Stack ecosystem:
- Essential plugin recommendations
- Plugin compatibility information
- Simplified installation process
Tools to improve your WordPress workflow: ### Hosting
- Content Management Recommendations for WordPress hosting providers optimized for SEO:
- Media Handling - Managed WordPress hosting
- Site Maintenance - Performance-focused hosting
- Hosting provider comparisons
- Special offers and discounts
### Free Plugins ### Tools
Browse and install recommended free plugins organized by categories: Utilities to help optimize your WordPress site:
- Database optimization
- Robots.txt generator
- SEO audit tools
- Cache management
- Minimal ## File Structure
- Admin
- AI
- CMS
- Compliance
- CRM
- Ecommerce
- LMS
- Media
- SEO
- Setup
- Social
- Speed
- Translation
- Advanced
- Debug
### Pro Plugins The plugin follows a modular structure for better maintainability:
Discover premium plugins with direct links to purchase. ```
wp-seoprostack-plugin/
├── admin/
│ ├── css/
│ ├── images/
│ │ ├── hosting/
│ │ └── themes/
│ ├── js/
│ └── settings/
│ ├── ajax/
│ └── tabs/
├── includes/
│ ├── core/
│ └── features/
└── public/
```
### Theme ## Requirements
Easily install and activate the Kadence theme. - WordPress 5.0 or higher
- PHP 7.2 or higher
## Development ## Changelog
### Requirements ### 1.0.0
- Initial release with comprehensive SEO tools and recommendations
- WordPress 5.8 or higher
- PHP 7.4 or higher
### Contributing
1. Fork the repository
2. Create a feature branch: `git checkout -b feature/your-feature-name`
3. Commit your changes: `git commit -am 'Add some feature'`
4. Push to the branch: `git push origin feature/your-feature-name`
5. Submit a pull request
## License
This plugin is licensed under the GPL v2 or later.
## Credits ## Credits
Developed by [Your Name/Company] Developed by Marcus QuinnTest sync after hook update
## Support
For support, please [create an issue](https://github.com/yourusername/wp-allstars/issues) on the GitHub repository.
## Debugging
- Debug mode can be enabled in wp-config.php
- Errors are logged to `wp-content/wp-allstars.log`
#

View File

@ -0,0 +1,123 @@
<?php
/**
* The admin-specific functionality of the plugin.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The admin-specific functionality of the plugin.
*/
class SEOProStack_Admin {
/**
* Initialize the admin functionality.
*/
public function initialize() {
// Register settings page
add_action('admin_menu', array($this, 'add_settings_page'));
// Register admin assets
add_action('admin_enqueue_scripts', array($this, 'enqueue_styles'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_scripts'));
// Initialize AJAX handlers
$this->init_ajax_handlers();
}
/**
* Register the stylesheets for the admin area.
*
* @param string $hook The current admin page.
*/
public function enqueue_styles($hook) {
// Only load styles on our settings page
if (strpos($hook, 'seoprostack') === false && strpos($hook, 'page=seoprostack') === false) {
return;
}
wp_enqueue_style(
'seoprostack-admin',
SEOPROSTACK_PLUGIN_URL . 'admin/css/seoprostack-admin.css',
array(),
SEOPROSTACK_VERSION
);
wp_enqueue_style(
'seoprostack-plugins',
SEOPROSTACK_PLUGIN_URL . 'admin/css/seoprostack-plugins.css',
array(),
SEOPROSTACK_VERSION
);
}
/**
* Register the JavaScript for the admin area.
*
* @param string $hook The current admin page.
*/
public function enqueue_scripts($hook) {
// Only load scripts on our settings page
if (strpos($hook, 'seoprostack') === false && strpos($hook, 'page=seoprostack') === false) {
return;
}
// Enqueue WordPress updates script for theme installation
wp_enqueue_script('updates');
wp_enqueue_script(
'seoprostack-admin',
SEOPROSTACK_PLUGIN_URL . 'admin/js/seoprostack-admin.js',
array('jquery', 'updates'),
SEOPROSTACK_VERSION,
true
);
// Localize script for AJAX
$ajax_data = array(
'ajaxurl' => admin_url('admin-ajax.php'),
'adminUrl' => admin_url(),
'nonce' => wp_create_nonce('seoprostack_ajax_nonce'),
'updateNonce' => wp_create_nonce('updates')
);
wp_localize_script('seoprostack-admin', 'seoProStack', $ajax_data);
}
/**
* Add settings page to the WordPress admin menu.
*/
public function add_settings_page() {
// Initialize settings page
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings/class-seoprostack-settings-page.php';
$settings_page = new SEOProStack_Settings_Page();
$settings_page->add_menu_page();
$settings_page->register_settings();
}
/**
* Initialize AJAX handlers.
*/
public function init_ajax_handlers() {
// Pro Plugins AJAX handler
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings/ajax/class-seoprostack-ajax-pro-plugins.php';
$pro_plugins_ajax = new SEOProStack_AJAX_Pro_Plugins();
$pro_plugins_ajax->init();
// Advanced Settings AJAX handler
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings/ajax/class-seoprostack-ajax-advanced.php';
$advanced_ajax = new SEOProStack_AJAX_Advanced();
$advanced_ajax->init();
// Tools AJAX handler
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings/ajax/class-seoprostack-ajax-tools.php';
$tools_ajax = new SEOProStack_AJAX_Tools();
$tools_ajax->init();
}
}

View File

@ -1,10 +1,10 @@
.wp-allstars-wrap { .seoprostack-wrap {
max-width: none; max-width: none;
margin: 0; margin: 0;
padding-right: 20px; padding-right: 20px;
} }
.wp-allstars-header { .seoprostack-header {
background: #fff; background: #fff;
border-bottom: 1px solid #c3c4c7; border-bottom: 1px solid #c3c4c7;
box-shadow: 0 1px 0 rgba(0,0,0,.04); box-shadow: 0 1px 0 rgba(0,0,0,.04);
@ -17,7 +17,7 @@
position: relative; position: relative;
} }
.wp-allstars-header h1 { .seoprostack-header h1 {
font-size: 23px; font-size: 23px;
font-weight: 400; font-weight: 400;
margin: 0; margin: 0;
@ -26,14 +26,14 @@
color: #1d2327; color: #1d2327;
} }
.wp-allstars-header-actions { .seoprostack-header-actions {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
} }
.wp-allstars-version { .seoprostack-version {
color: #d35400; /* Updated to dark orange */ color: #646970; /* Neutral gray color */
font-size: 13px; font-size: 13px;
font-weight: 400; font-weight: 400;
} }
@ -42,12 +42,15 @@
.nav-tab-wrapper, .nav-tab-wrapper,
.wrap h2.nav-tab-wrapper { .wrap h2.nav-tab-wrapper {
border-bottom: 1px solid #c3c4c7; border-bottom: 1px solid #c3c4c7;
margin: 0 -20px; margin: 15px -20px 0;
padding: 0 20px; padding: 0 20px;
background: #fff; background: #fff;
position: sticky; position: sticky;
top: 32px; top: 32px;
z-index: 100; z-index: 100;
display: flex;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
} }
.nav-tab { .nav-tab {
@ -64,6 +67,9 @@
border-bottom: 2px solid transparent; border-bottom: 2px solid transparent;
display: inline-block; display: inline-block;
transition: all 0.2s ease; transition: all 0.2s ease;
position: relative;
outline: none;
box-shadow: none;
} }
.nav-tab:hover, .nav-tab:hover,
@ -83,8 +89,32 @@
font-weight: 600; font-weight: 600;
} }
/* Tab content container */
.tab-content {
padding: 20px 0;
animation: fadeIn 0.3s ease-in-out;
background: transparent;
}
/* Ensure tab content containers don't have a background color */
.seoprostack-settings-content {
background: transparent;
}
/* Make sure toggle containers have background */
.seoprostack-toggle, .seoprostack-setting-base, .seoprostack-setting-row {
background: #fff;
border: 1px solid #c3c4c7;
box-shadow: 0 1px 1px rgba(0,0,0,0.04);
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* Base Toggle Switch Component */ /* Base Toggle Switch Component */
.wp-toggle-switch { .seoprostack-toggle-switch {
position: relative; position: relative;
display: inline-block; display: inline-block;
width: 36px; width: 36px;
@ -95,7 +125,7 @@
z-index: 2; z-index: 2;
} }
.wp-toggle-switch input { .seoprostack-toggle-switch input {
opacity: 0; opacity: 0;
width: 0; width: 0;
height: 0; height: 0;
@ -104,7 +134,7 @@
position: absolute; position: absolute;
} }
.wp-toggle-slider { .seoprostack-toggle-slider {
position: absolute; position: absolute;
cursor: pointer; cursor: pointer;
top: 0; top: 0;
@ -116,7 +146,7 @@
border-radius: 20px; border-radius: 20px;
} }
.wp-toggle-slider:before { .seoprostack-toggle-slider:before {
position: absolute; position: absolute;
content: ""; content: "";
height: 16px; height: 16px;
@ -129,27 +159,27 @@
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
} }
input:checked + .wp-toggle-slider { input:checked + .seoprostack-toggle-slider {
background-color: #2271b1; background-color: #2271b1;
} }
input:checked + .wp-toggle-slider:before { input:checked + .seoprostack-toggle-slider:before {
transform: translateX(16px); transform: translateX(16px);
} }
/* Base Setting Styles (Shared between simple and expandable) */ /* Base Setting Styles (Shared between simple and expandable) */
.wp-setting-base, .seoprostack-setting-base,
.wp-setting-row, .seoprostack-setting-row,
.wp-allstars-toggle { .seoprostack-toggle {
background: #fff; background: #fff;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 8px; border-radius: 8px;
margin-bottom: 15px; margin-bottom: 15px;
} }
.wp-setting-base:hover, .seoprostack-setting-base:hover,
.wp-setting-row:hover, .seoprostack-setting-row:hover,
.wp-allstars-toggle:hover { .seoprostack-toggle:hover {
border-color: #2271b1; border-color: #2271b1;
box-shadow: 0 2px 6px rgba(0,0,0,0.15); box-shadow: 0 2px 6px rgba(0,0,0,0.15);
} }
@ -240,15 +270,15 @@ input:checked + .wp-toggle-slider:before {
border-bottom-right-radius: 8px; border-bottom-right-radius: 8px;
} }
.wp-allstars-setting-row { .seoprostack-setting-row {
margin-bottom: 24px; margin-bottom: 24px;
} }
.wp-allstars-setting-row:last-child { .seoprostack-setting-row:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
.wp-allstars-setting-row label { .seoprostack-setting-row label {
display: block; display: block;
margin-bottom: 8px; margin-bottom: 8px;
font-size: 14px; font-size: 14px;
@ -258,9 +288,9 @@ input:checked + .wp-toggle-slider:before {
padding-right: 80px; padding-right: 80px;
} }
.wp-allstars-setting-row input[type="text"], .seoprostack-setting-row input[type="text"],
.wp-allstars-setting-row input[type="number"], .seoprostack-setting-row input[type="number"],
.wp-allstars-setting-row textarea { .seoprostack-setting-row textarea {
width: 100%; width: 100%;
max-width: 400px; max-width: 400px;
padding: 8px; padding: 8px;
@ -271,9 +301,9 @@ input:checked + .wp-toggle-slider:before {
display: block; display: block;
} }
.wp-allstars-setting-row input[type="text"]:focus, .seoprostack-setting-row input[type="text"]:focus,
.wp-allstars-setting-row input[type="number"]:focus, .seoprostack-setting-row input[type="number"]:focus,
.wp-allstars-setting-row textarea:focus { .seoprostack-setting-row textarea:focus {
border-color: #2271b1; border-color: #2271b1;
box-shadow: 0 0 0 1px #2271b1; box-shadow: 0 0 0 1px #2271b1;
outline: 2px solid transparent; outline: 2px solid transparent;
@ -631,7 +661,7 @@ input:checked + .wp-toggle-slider:before {
} }
/* Settings Notification */ /* Settings Notification */
.wp-setting-notification { .seoprostack-setting-notification {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
margin-left: 10px; margin-left: 10px;
@ -647,22 +677,22 @@ input:checked + .wp-toggle-slider:before {
position: relative; position: relative;
} }
.wp-setting-notification.error { .seoprostack-setting-notification.error {
background: #d63638; background: #d63638;
} }
/* Add space for notification to prevent layout shifts */ /* Add space for notification to prevent layout shifts */
.wp-setting-left label, .wp-setting-left label,
.wp-allstars-toggle-left label, .wp-allstars-toggle-left label,
.wp-allstars-setting-row label { .seoprostack-setting-row label {
position: relative; position: relative;
padding-right: 20px; padding-right: 20px;
display: inline-block; display: inline-block;
} }
.wp-setting-left label .wp-setting-notification, .wp-setting-left label .seoprostack-setting-notification,
.wp-allstars-toggle-left label .wp-setting-notification, .wp-allstars-toggle-left label .seoprostack-setting-notification,
.wp-allstars-setting-row label .wp-setting-notification { .seoprostack-setting-row label .seoprostack-setting-notification {
position: absolute; position: absolute;
right: -60px; right: -60px;
top: -2px; top: -2px;
@ -695,7 +725,7 @@ input:checked + .wp-toggle-slider:before {
} }
/* Panel styles for Pro Plugins, Hosting, and Tools tabs */ /* Panel styles for Pro Plugins, Hosting, and Tools tabs */
.wpa-pro-plugins { .seoprostack-pro-plugins {
padding: 20px; padding: 20px;
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(450px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(450px, 1fr));
@ -704,7 +734,7 @@ input:checked + .wp-toggle-slider:before {
margin: 0 auto; margin: 0 auto;
} }
.wpa-pro-plugin { .seoprostack-pro-plugin {
background: #fff; background: #fff;
border: 1px solid #ddd; border: 1px solid #ddd;
padding: 24px; padding: 24px;
@ -715,12 +745,12 @@ input:checked + .wp-toggle-slider:before {
box-shadow: 0 1px 3px rgba(0,0,0,0.1); box-shadow: 0 1px 3px rgba(0,0,0,0.1);
} }
.wpa-pro-plugin:hover { .seoprostack-pro-plugin:hover {
border-color: #2271b1; border-color: #2271b1;
box-shadow: 0 2px 6px rgba(0,0,0,0.15); box-shadow: 0 2px 6px rgba(0,0,0,0.15);
} }
.wpa-pro-plugin h3 { .seoprostack-pro-plugin h3 {
margin: 0 0 12px; margin: 0 0 12px;
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
@ -728,21 +758,21 @@ input:checked + .wp-toggle-slider:before {
line-height: 1.4; line-height: 1.4;
} }
.wpa-pro-plugin p { .seoprostack-pro-plugin p {
margin: 0 0 16px; margin: 0 0 16px;
color: #50575e; color: #50575e;
font-size: 14px; font-size: 14px;
line-height: 1.6; line-height: 1.6;
} }
.wpa-pro-plugin .button-group { .seoprostack-pro-plugin .button-group {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 8px; gap: 8px;
margin-top: auto; margin-top: auto;
} }
.wpa-pro-plugin .button { .seoprostack-pro-plugin .button {
text-decoration: none; text-decoration: none;
min-width: 120px; min-width: 120px;
text-align: center; text-align: center;
@ -762,45 +792,619 @@ input:checked + .wp-toggle-slider:before {
cursor: pointer; cursor: pointer;
} }
.wpa-pro-plugin .button:hover { .seoprostack-pro-plugin .button:hover {
background: #f0f0f1; background: #f0f0f1;
border-color: #0071a1; border-color: #0071a1;
color: #0071a1; color: #0071a1;
} }
.wpa-pro-plugin .button.button-primary { .seoprostack-pro-plugin .button.button-primary {
background: #2271b1; background: #2271b1;
border-color: #2271b1 !important; border-color: #2271b1 !important;
color: #fff; color: #fff;
} }
.wpa-pro-plugin .button.button-primary:hover { .seoprostack-pro-plugin .button.button-primary:hover {
background: #135e96; background: #135e96;
border-color: #135e96 !important; border-color: #135e96 !important;
color: #fff; color: #fff;
} }
@media screen and (max-width: 960px) { @media screen and (max-width: 960px) {
.wpa-pro-plugins { .seoprostack-pro-plugins {
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
gap: 20px; gap: 20px;
padding: 16px; padding: 16px;
} }
.wpa-pro-plugin { .seoprostack-pro-plugin {
padding: 20px; padding: 20px;
} }
} }
@media screen and (max-width: 782px) { @media screen and (max-width: 782px) {
.wpa-pro-plugins { .seoprostack-pro-plugins {
grid-template-columns: 1fr; grid-template-columns: 1fr;
gap: 16px; gap: 16px;
padding: 12px; padding: 12px;
} }
.wpa-pro-plugin { .seoprostack-pro-plugin {
padding: 16px; padding: 16px;
} }
.wpa-pro-plugin .button { .seoprostack-pro-plugin .button {
width: 100%; width: 100%;
} }
} }
/**
* SEO Pro Stack Admin CSS
*
* Styles for the admin settings pages
*
* @package SEO_Pro_Stack
*/
/* Main Settings Container */
.seoprostack-wrap {
max-width: none;
margin: 0;
padding-right: 20px;
}
/* Header Section */
.seoprostack-header {
background: #fff;
border-bottom: 1px solid #c3c4c7;
box-shadow: 0 1px 0 rgba(0,0,0,.04);
margin: 0 -20px 0 -20px;
padding: 20px;
display: flex;
align-items: center;
justify-content: space-between;
width: auto;
position: relative;
}
.seoprostack-header h1 {
font-size: 23px;
font-weight: 400;
margin: 0;
padding: 0;
line-height: 1.3;
color: #1d2327;
}
.seoprostack-header-actions {
display: flex;
align-items: center;
gap: 10px;
}
.seoprostack-version {
color: #d35400; /* Dark orange */
font-size: 13px;
font-weight: 400;
}
.seoprostack-description {
margin-top: 5px;
color: #757575;
font-size: 14px;
}
/* Navigation Tabs */
.nav-tab-wrapper,
.wrap h2.nav-tab-wrapper {
border-bottom: 1px solid #c3c4c7;
margin: 15px -20px 0;
padding: 0 20px;
background: #fff;
position: sticky;
top: 32px;
z-index: 100;
display: flex;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.nav-tab {
background: #f7f7f7;
border-color: #c3c4c7;
color: #555;
margin-bottom: -1px;
margin-right: 5px;
}
.nav-tab:hover,
.nav-tab:focus {
background: #fff;
color: #d35400;
}
.nav-tab-active,
.nav-tab-active:hover,
.nav-tab-active:focus {
background: #fff;
border-bottom-color: #fff;
color: #d35400;
}
/* Settings Container */
.seoprostack-settings-container {
margin-top: 20px;
display: flex;
flex-direction: column;
}
.seoprostack-settings-content {
background: transparent;
border: none;
border-radius: 0;
padding: 0;
margin-bottom: 20px;
}
/* Setting Sections */
.seoprostack-setting-section {
margin-bottom: 30px;
}
.seoprostack-setting-section h2 {
font-size: 18px;
font-weight: 600;
margin-top: 0;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.seoprostack-setting-section h3 {
font-size: 16px;
font-weight: 600;
margin-top: 20px;
margin-bottom: 10px;
}
.seoprostack-setting-section p.description {
color: #757575;
font-size: 13px;
margin-bottom: 15px;
max-width: 760px;
}
/* Setting Rows */
.seoprostack-setting-row {
margin-bottom: 15px;
padding: 10px;
border-radius: 4px;
transition: background-color 0.3s;
}
.seoprostack-setting-row:hover {
background-color: #f9f9f9;
}
.seoprostack-setting-row label {
display: block;
margin-bottom: 8px;
font-size: 14px;
font-weight: 600;
}
.seoprostack-setting-row input[type="text"],
.seoprostack-setting-row input[type="number"],
.seoprostack-setting-row select,
.seoprostack-setting-row textarea {
width: 100%;
max-width: 500px;
}
.seoprostack-setting-row .description {
display: block;
margin-top: 5px;
color: #757575;
font-size: 13px;
}
/* Toggle Sections */
.seoprostack-toggle {
border: 1px solid #ddd;
border-radius: 4px;
margin-bottom: 15px;
overflow: hidden;
}
.seoprostack-toggle-header {
background: #f9f9f9;
padding: 15px;
cursor: pointer;
border-bottom: 1px solid #ddd;
transition: background-color 0.3s;
}
.seoprostack-toggle-header:hover {
background: #f5f5f5;
}
.seoprostack-toggle-header.active {
background: #e9e9e9;
}
.seoprostack-toggle-main {
display: flex;
justify-content: space-between;
align-items: center;
}
.seoprostack-toggle-left h3 {
margin: 0;
font-size: 15px;
font-weight: 600;
}
.seoprostack-toggle-left p {
margin: 5px 0 0;
color: #757575;
font-size: 13px;
}
.seoprostack-toggle-settings {
padding: 15px;
background: #fff;
}
/* Toggle Switch */
.seoprostack-toggle-switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
.seoprostack-toggle-switch input {
opacity: 0;
width: 0;
height: 0;
}
.toggle-label {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 24px;
}
.toggle-label:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .toggle-label {
background-color: #d35400;
}
input:focus + .toggle-label {
box-shadow: 0 0 1px #d35400;
}
input:checked + .toggle-label:before {
transform: translateX(26px);
}
/* Checkbox Styling */
.seoprostack-checkbox-label {
display: flex;
align-items: center;
font-weight: 600;
margin-bottom: 5px;
}
.seoprostack-checkbox-label input[type="checkbox"] {
margin-right: 8px;
}
/* Action Buttons */
.seoprostack-setting-actions {
margin-top: 20px;
display: flex;
align-items: center;
}
.seoprostack-setting-actions .button-primary {
background: #d35400;
border-color: #aa4400;
}
.seoprostack-setting-actions .button-primary:hover,
.seoprostack-setting-actions .button-primary:focus {
background: #aa4400;
border-color: #803300;
}
.seoprostack-setting-actions .spinner {
float: none;
margin-left: 10px;
}
/* Notices */
.seoprostack-notice {
padding: 10px 15px;
margin: 15px 0;
border-radius: 4px;
border-left: 4px solid;
}
.seoprostack-notice-success {
background-color: #f0fff1;
border-left-color: #46b450;
}
.seoprostack-notice-error {
background-color: #ffeaea;
border-left-color: #dc3232;
}
.seoprostack-notice-warning {
background-color: #fef8ee;
border-left-color: #ffb900;
}
.seoprostack-notice-info {
background-color: #f0f6fc;
border-left-color: #00a0d2;
}
/* Theme Cards */
.seoprostack-theme-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
margin-top: 20px;
}
.seoprostack-theme-card {
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
transition: transform 0.3s, box-shadow 0.3s;
}
.seoprostack-theme-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.seoprostack-theme-card-header {
height: 200px;
overflow: hidden;
}
.seoprostack-theme-card-header img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s;
}
.seoprostack-theme-card:hover .seoprostack-theme-card-header img {
transform: scale(1.05);
}
.seoprostack-theme-card-content {
padding: 15px;
}
.seoprostack-theme-card-content h4 {
margin: 0 0 10px;
font-size: 16px;
font-weight: 600;
}
.seoprostack-theme-card-content p {
margin: 0 0 15px;
color: #666;
font-size: 14px;
line-height: 1.5;
}
/* Hosting Cards */
.seoprostack-hosting-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
margin-top: 20px;
}
.seoprostack-hosting-card {
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
transition: transform 0.3s, box-shadow 0.3s;
}
.seoprostack-hosting-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.seoprostack-hosting-card-header {
padding: 15px;
text-align: center;
border-bottom: 1px solid #eee;
}
.seoprostack-hosting-card-header img {
max-width: 160px;
max-height: 60px;
}
.seoprostack-hosting-card-content {
padding: 15px;
}
.seoprostack-hosting-card-content h4 {
margin: 0 0 10px;
font-size: 16px;
font-weight: 600;
}
.seoprostack-hosting-card-content p {
margin: 0 0 15px;
color: #666;
font-size: 14px;
line-height: 1.5;
}
/* Server Info */
.seoprostack-info-table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
}
.seoprostack-info-table th,
.seoprostack-info-table td {
padding: 10px;
border-bottom: 1px solid #eee;
text-align: left;
}
.seoprostack-info-table th {
font-weight: 600;
width: 20%;
}
.seoprostack-info-note {
color: #666;
font-size: 13px;
}
.seoprostack-status-icon {
display: inline-block;
width: 16px;
height: 16px;
border-radius: 50%;
margin-left: 5px;
vertical-align: middle;
}
.seoprostack-status-good {
background-color: #46b450;
}
.seoprostack-status-warning {
background-color: #ffb900;
}
.seoprostack-status-bad {
background-color: #dc3232;
}
/* Tools Grid */
.seoprostack-tools-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
margin-top: 20px;
}
.seoprostack-tool-card {
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
transition: transform 0.3s, box-shadow 0.3s;
}
.seoprostack-tool-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.seoprostack-tool-card-header {
padding: 20px;
text-align: center;
background: #f7f7f7;
}
.seoprostack-tool-card-header .dashicons {
font-size: 32px;
width: 32px;
height: 32px;
color: #d35400;
}
.seoprostack-tool-card-content {
padding: 15px;
}
.seoprostack-tool-card-content h3 {
margin: 0 0 10px;
font-size: 16px;
font-weight: 600;
}
.seoprostack-tool-card-content p {
margin: 0 0 15px;
color: #666;
font-size: 14px;
line-height: 1.5;
}
/* DB Actions */
.seoprostack-db-actions {
margin-top: 15px;
display: flex;
align-items: center;
}
.seoprostack-db-actions .spinner {
float: none;
margin-left: 10px;
}
/* Loading States */
.loading::after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255,255,255,0.7);
z-index: 1;
}
/* Responsive */
@media screen and (max-width: 782px) {
.seoprostack-theme-grid,
.seoprostack-hosting-grid,
.seoprostack-tools-grid {
grid-template-columns: 1fr;
}
.seoprostack-header {
flex-direction: column;
align-items: flex-start;
}
.seoprostack-header-actions {
margin-top: 10px;
}
}

View File

@ -1,5 +1,5 @@
/* Plugin Browser Styles */ /* Plugin Browser Styles */
.wp-allstars-wrap .wp-allstars-plugin-browser { .seoprostack-wrap .seoprostack-plugin-browser {
margin: 0 -8px !important; margin: 0 -8px !important;
padding: 0 8px !important; padding: 0 8px !important;
width: 100% !important; width: 100% !important;
@ -7,7 +7,7 @@
} }
/* Plugin List Container */ /* Plugin List Container */
.wp-allstars-wrap #wpa-plugin-list { .seoprostack-wrap #seoprostack-plugin-list {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
margin: 0; margin: 0;
@ -15,7 +15,7 @@
} }
/* Filter Bar */ /* Filter Bar */
.wp-allstars-wrap #wpa-plugin-filters.wp-filter { .seoprostack-wrap #seoprostack-plugin-filters.wp-filter {
margin-left: 0; margin-left: 0;
margin-right: 0; margin-right: 0;
width: 100%; width: 100%;
@ -23,13 +23,13 @@
} }
/* Standard WordPress Plugin Grid Layout - exactly matching core */ /* Standard WordPress Plugin Grid Layout - exactly matching core */
.wp-allstars-wrap .wp-list-table.plugin-install { .seoprostack-wrap .wp-list-table.plugin-install {
margin-top: 20px; margin-top: 20px;
clear: both; clear: both;
padding: 0; padding: 0;
} }
.wp-allstars-wrap #the-list { .seoprostack-wrap #the-list {
margin: 0; margin: 0;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

View File

@ -0,0 +1,403 @@
// Define loadTheme in the global scope so it can be called from inline scripts
var loadTheme;
jQuery(document).ready(function($) {
// Function to show notification
function showNotification(message, $element, isError = false) {
// Remove any existing notifications
$('.seoprostack-setting-notification').remove();
// Create notification element
var $notification = $('<span class="seoprostack-setting-notification' + (isError ? ' error' : '') + '">' + message + '</span>');
// If element is provided, show notification next to it
if ($element && $element.length) {
$element.after($notification);
} else {
// Fallback to header if no element provided
$('.seoprostack-header h1').after($notification);
}
// Fade out after delay
setTimeout(function() {
$notification.fadeOut(300, function() {
$(this).remove();
});
}, 2000);
}
// Handle option updates
function updateOption(option, value) {
return $.ajax({
url: wpSeoProStack.ajaxurl,
type: 'POST',
data: {
action: 'wp_seoprostack_update_option',
option: option,
value: value,
nonce: wpSeoProStack.nonce
}
}).then(function(response) {
if (!response.success) {
throw new Error(response.data || 'Error saving setting');
}
return response;
});
}
// Toggle sections
$('.seoprostack-toggle-header').on('click', function() {
$(this).toggleClass('active');
$(this).next('.seoprostack-toggle-settings').slideToggle(300);
});
// Tabs functionality (if not using WP default tabs)
$('.seoprostack-tab-nav a').on('click', function(e) {
e.preventDefault();
var targetTab = $(this).attr('href').substring(1);
// Update active tab
$('.seoprostack-tab-nav a').removeClass('active');
$(this).addClass('active');
// Show target tab content
$('.seoprostack-tab-content').hide();
$('#' + targetTab).show();
// Update URL without refreshing
if (history.pushState) {
var newUrl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?page=seoprostack&tab=' + targetTab;
window.history.pushState({path: newUrl}, '', newUrl);
}
});
// Pro Plugins Tab
if ($('#pro-plugins').length) {
// Category filter
$('.seoprostack-category-filter a').on('click', function(e) {
e.preventDefault();
var category = $(this).data('category');
// Update active filter
$('.seoprostack-category-filter a').removeClass('active');
$(this).addClass('active');
// Show loading
$('#seoprostack-plugins-grid').addClass('loading');
// Load plugins
$.ajax({
url: wpSeoProStack.ajaxurl,
type: 'POST',
data: {
action: 'wp_seoprostack_get_plugins',
category: category,
nonce: wpSeoProStack.nonce
},
success: function(response) {
$('#seoprostack-plugins-grid').removeClass('loading');
if (response.success) {
renderPlugins(response.data.plugins);
} else {
$('#seoprostack-plugins-grid').html('<div class="seoprostack-notice seoprostack-notice-error">' + response.data.message + '</div>');
}
},
error: function() {
$('#seoprostack-plugins-grid').removeClass('loading');
$('#seoprostack-plugins-grid').html('<div class="seoprostack-notice seoprostack-notice-error">Error connecting to server</div>');
}
});
});
// Activate plugin
$(document).on('click', '.seoprostack-activate-plugin', function(e) {
e.preventDefault();
var $button = $(this);
var plugin = $button.data('plugin');
var $card = $button.closest('.seoprostack-plugin-card');
// Show loading
$button.prop('disabled', true).text('Activating...');
// Send activation request
$.ajax({
url: wpSeoProStack.ajaxurl,
type: 'POST',
data: {
action: 'wp_seoprostack_activate_plugin',
plugin: plugin,
nonce: wpSeoProStack.nonce
},
success: function(response) {
if (response.success) {
// Update UI
$button.text('Activated').addClass('button-disabled');
$card.find('.plugin-status').removeClass('not-installed installed').addClass('active').text('Active');
} else {
$button.prop('disabled', false).text('Activate');
alert(response.data.message);
}
},
error: function() {
$button.prop('disabled', false).text('Activate');
alert('Error connecting to server');
}
});
});
// Render plugins
function renderPlugins(plugins) {
var html = '';
if (plugins.length === 0) {
html = '<div class="seoprostack-notice seoprostack-notice-info">No plugins found in this category</div>';
} else {
plugins.forEach(function(plugin) {
var statusClass = plugin.active ? 'active' : (plugin.status === 'installed' ? 'installed' : 'not-installed');
var statusText = plugin.active ? 'Active' : (plugin.status === 'installed' ? 'Installed' : 'Not Installed');
var buttonText = plugin.active ? 'Activated' : 'Activate';
var buttonDisabled = plugin.active ? ' button-disabled' : '';
html += '<div class="seoprostack-plugin-card">';
html += '<div class="seoprostack-plugin-card-header">';
html += '<span class="plugin-status ' + statusClass + '">' + statusText + '</span>';
html += '</div>';
html += '<div class="seoprostack-plugin-card-content">';
html += '<h3>' + plugin.name + ' <span class="version">v' + plugin.version + '</span></h3>';
html += '<p>' + plugin.description + '</p>';
html += '<div class="seoprostack-plugin-card-footer">';
html += '<a href="' + plugin.url + '" class="button button-secondary" target="_blank">View Details</a>';
if (!plugin.active) {
html += '<button class="button button-primary seoprostack-activate-plugin' + buttonDisabled + '" data-plugin="' + plugin.path + '">' + buttonText + '</button>';
} else {
html += '<button class="button button-primary' + buttonDisabled + '">' + buttonText + '</button>';
}
html += '</div>';
html += '</div>';
html += '</div>';
});
}
$('#seoprostack-plugins-grid').html(html);
}
// Load initial plugins
$('.seoprostack-category-filter a.active').trigger('click');
}
// Advanced Tab Form
if ($('#seoprostack-advanced-settings-form').length) {
$('#seoprostack-advanced-settings-form').on('submit', function(e) {
e.preventDefault();
var $form = $(this);
var $button = $('#seoprostack-save-advanced-settings');
var $spinner = $button.next('.spinner');
var $response = $('#advanced-settings-response');
// Show loading
$button.prop('disabled', true);
$spinner.css('visibility', 'visible');
// Get form data
var formData = $form.serializeArray();
var data = {
action: 'wp_seoprostack_save_advanced_settings',
nonce: wpSeoProStack.nonce
};
// Convert form data to proper format
$.each(formData, function(i, field) {
data[field.name] = field.value;
});
// Add checkbox fields that might not be in formData
$form.find('input[type="checkbox"]').each(function() {
var name = $(this).attr('name');
if (data[name] === undefined) {
data[name] = 'no';
}
});
// Send AJAX request
$.post(seoProStack.ajaxurl, data, function(response) {
// Hide loading
$button.prop('disabled', false);
$spinner.css('visibility', 'hidden');
// Show response
if (response.success) {
$response.html('<div class="seoprostack-notice seoprostack-notice-success">' + response.data.message + '</div>');
} else {
$response.html('<div class="seoprostack-notice seoprostack-notice-error">' + response.data.message + '</div>');
}
// Hide response after delay
setTimeout(function() {
$response.find('.seoprostack-notice').fadeOut(500, function() {
$(this).remove();
});
}, 3000);
}).fail(function() {
// Hide loading
$button.prop('disabled', false);
$spinner.css('visibility', 'hidden');
// Show error
$response.html('<div class="seoprostack-notice seoprostack-notice-error">Error connecting to server</div>');
});
});
}
// Tools Tab
if ($('#tools').length) {
// Database Optimization
$('#seoprostack-optimize-db').on('click', function(e) {
e.preventDefault();
var $button = $(this);
var $spinner = $button.next('.spinner');
var $response = $('#db-optimize-response');
// Show loading
$button.prop('disabled', true);
$spinner.css('visibility', 'visible');
// Send AJAX request
$.ajax({
url: wpSeoProStack.ajaxurl,
type: 'POST',
data: {
action: 'wp_seoprostack_optimize_database',
nonce: wpSeoProStack.nonce
},
success: function(response) {
// Hide loading
$button.prop('disabled', false);
$spinner.css('visibility', 'hidden');
// Show response
if (response.success) {
$response.html('<div class="seoprostack-notice seoprostack-notice-success">' + response.data.message + '</div>');
// Update stats if provided
if (response.data.stats) {
updateDbStats(response.data.stats);
}
} else {
$response.html('<div class="seoprostack-notice seoprostack-notice-error">' + response.data.message + '</div>');
}
// Hide response after delay
setTimeout(function() {
$response.find('.seoprostack-notice').fadeOut(500, function() {
$(this).remove();
});
}, 5000);
},
error: function() {
// Hide loading
$button.prop('disabled', false);
$spinner.css('visibility', 'hidden');
// Show error
$response.html('<div class="seoprostack-notice seoprostack-notice-error">Error connecting to server</div>');
}
});
});
// Function to update database stats
function updateDbStats(stats) {
if (stats.total_cleaned) {
$('#db-total-cleaned').text(stats.total_cleaned);
}
if (stats.db_size_before) {
$('#db-size-before').text(stats.db_size_before);
}
if (stats.db_size_after) {
$('#db-size-after').text(stats.db_size_after);
}
if (stats.savings_percentage) {
$('#db-savings').text(stats.savings_percentage + '%');
}
}
// Generate Robots.txt
$('#seoprostack-generate-robots').on('click', function(e) {
e.preventDefault();
var $button = $(this);
var $spinner = $button.next('.spinner');
var $response = $('#robots-response');
var $content = $('#robots-content');
// Show loading
$button.prop('disabled', true);
$spinner.css('visibility', 'visible');
// Send AJAX request
$.ajax({
url: wpSeoProStack.ajaxurl,
type: 'POST',
data: {
action: 'wp_seoprostack_generate_robots',
nonce: wpSeoProStack.nonce
},
success: function(response) {
// Hide loading
$button.prop('disabled', false);
$spinner.css('visibility', 'hidden');
// Show response
if (response.success) {
$response.html('<div class="seoprostack-notice seoprostack-notice-success">' + response.data.message + '</div>');
// Display robots.txt content
if (response.data.content) {
$content.val(response.data.content);
$content.closest('.seoprostack-setting-row').show();
}
} else {
$response.html('<div class="seoprostack-notice seoprostack-notice-error">' + response.data.message + '</div>');
}
},
error: function() {
// Hide loading
$button.prop('disabled', false);
$spinner.css('visibility', 'hidden');
// Show error
$response.html('<div class="seoprostack-notice seoprostack-notice-error">Error connecting to server</div>');
}
});
});
// Copy to Clipboard Functionality
$('.seoprostack-copy-to-clipboard').on('click', function(e) {
e.preventDefault();
var targetId = $(this).data('target');
var $target = $('#' + targetId);
var $button = $(this);
var originalText = $button.text();
// Copy to clipboard
$target.select();
document.execCommand('copy');
// Update button text
$button.text('Copied!');
// Reset button text
setTimeout(function() {
$button.text(originalText);
}, 2000);
});
}
});
});

View File

@ -1,327 +0,0 @@
// Define loadTheme in the global scope so it can be called from inline scripts
var loadTheme;
jQuery(document).ready(function($) {
// Function to show notification
function showNotification(message, $element, isError = false) {
// Remove any existing notifications
$('.wp-setting-notification').remove();
// Create notification element
var $notification = $('<span class="wp-setting-notification' + (isError ? ' error' : '') + '">' + message + '</span>');
// If element is provided, show notification next to it
if ($element && $element.length) {
$element.after($notification);
} else {
// Fallback to header if no element provided
$('.wp-allstars-header h1').after($notification);
}
// Fade out after delay
setTimeout(function() {
$notification.fadeOut(300, function() {
$(this).remove();
});
}, 2000);
}
// Handle option updates
function updateOption(option, value) {
return $.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'wp_allstars_update_option',
option: option,
value: value,
nonce: wpAllstars.nonce
}
}).then(function(response) {
if (!response.success) {
throw new Error(response.data || 'Error saving setting');
}
return response;
});
}
// Handle toggle switch clicks
$('.wp-toggle-switch').on('click', function(e) {
e.stopPropagation();
var $checkbox = $(this).find('input[type="checkbox"]');
var isChecked = $checkbox.is(':checked');
$checkbox.prop('checked', !isChecked).trigger('change');
});
// Prevent label clicks from toggling the checkbox directly
$('.wp-setting-label, .wp-allstars-toggle-left label').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
});
// Handle checkbox changes
$('.wp-toggle-switch input[type="checkbox"]').on('change', function(e) {
e.stopPropagation();
var $input = $(this);
var option = $input.attr('name');
var value = $input.is(':checked') ? 1 : 0;
var $label = $input.closest('.wp-setting-left, .wp-allstars-toggle-left').find('label');
updateOption(option, value)
.then(function() {
showNotification('Saved', $label);
})
.catch(function() {
showNotification('Error saving settings', $label, true);
});
});
// Handle text input changes
$('.wp-allstars-setting-row input[type="text"], .wp-allstars-setting-row input[type="number"], .wp-allstars-setting-row textarea').on('change', function() {
var $input = $(this);
var option = $input.attr('name');
var value = $input.val();
var $label = $input.closest('.wp-allstars-setting-row').find('label').first();
updateOption(option, value)
.then(function() {
showNotification('Saved', $label);
})
.catch(function(error) {
console.error('Error:', error);
showNotification('Error saving setting', $label, true);
});
});
// Toggle expandable panels
$('.wp-allstars-toggle-header').on('click', function(e) {
if (!$(e.target).closest('.wp-toggle-switch').length &&
!$(e.target).closest('label').length) {
var $settings = $(this).closest('.wp-allstars-toggle').find('.wp-allstars-toggle-settings');
var isExpanded = $(this).attr('aria-expanded') === 'true';
$(this).attr('aria-expanded', !isExpanded);
$settings.slideToggle(200);
}
});
// Set initial panel states
$('.wp-allstars-toggle-header').each(function() {
var $settings = $(this).closest('.wp-allstars-toggle').find('.wp-allstars-toggle-settings');
var isExpanded = $(this).attr('aria-expanded') === 'true';
if (!isExpanded) {
$settings.hide();
}
});
// Remove JavaScript-based tab switching - let the native WordPress tab links work
// Plugin category filters
if ($('#wpa-plugin-filters').length) {
$('#wpa-plugin-filters a').on('click', function(e) {
e.preventDefault();
var category = $(this).data('category');
// Update active filter
$('#wpa-plugin-filters a').removeClass('current');
$(this).addClass('current');
// Load plugins for the selected category
loadPlugins(category);
});
// Load initial plugins if we're on the recommended tab
if ($('#recommended').is(':visible') && $('#wpa-plugin-list').is(':empty')) {
loadPlugins('minimal');
}
}
// Load theme tab content if we're on the theme tab
if ($('#theme').is(':visible') && $('#wpa-theme-list').length && $('#wpa-theme-list').is(':empty')) {
loadTheme();
}
// Function to load plugins
function loadPlugins(category) {
var $container = $('#wpa-plugin-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);
// Clear existing plugins
$container.empty().append($loadingOverlay);
// AJAX request to get plugins
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'wp_allstars_get_plugins',
category: category,
_wpnonce: wpAllstars.nonce
},
success: function(response) {
// Remove loading overlay
$loadingOverlay.remove();
if (response.success) {
// Append plugins HTML
$container.html(response.data);
// Initialize plugin action buttons
initPluginActions();
// Individual plugin card spinners have been removed
} 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 plugins. Please try again. Error: ' + error + '</p></div>');
console.error('AJAX Error:', xhr.responseText);
}
});
}
// Theme handlers are initialized directly from the inline script
// We don't need a separate loadTheme function anymore
// Initialize plugin action buttons
function initPluginActions() {
// Remove any existing event handlers to prevent duplicates
$('.plugin-card .install-now').off('click');
$('.plugin-card .update-now').off('click');
$('.plugin-card .activate-now').off('click');
// Install plugin
$('.plugin-card .install-now').on('click', function(e) {
e.preventDefault();
var $button = $(this);
var slug = $button.data('slug');
$button.addClass('updating-message').text('Installing...');
wp.updates.installPlugin({
slug: slug,
success: function(response) {
$button.removeClass('updating-message').addClass('updated-message').text('Installed!');
setTimeout(function() {
// Replace the button with an activate button
var $parent = $button.parent();
$button.remove();
$parent.html('<a class="button activate-now" href="' + response.activateUrl + '" data-slug="' + slug + '" aria-label="Activate ' + slug + '">Activate</a>');
// Re-initialize the event handlers
initPluginActions();
}, 1000);
},
error: function(response) {
$button.removeClass('updating-message').text('Install Now');
alert(response.errorMessage);
}
});
});
// Update plugin
$('.plugin-card .update-now').on('click', function(e) {
e.preventDefault();
var $button = $(this);
var slug = $button.data('slug');
$button.addClass('updating-message').text('Updating...');
wp.updates.updatePlugin({
slug: slug,
success: function() {
$button.removeClass('updating-message').addClass('updated-message').text('Updated!');
setTimeout(function() {
$button.removeClass('update-now updated-message')
.addClass('button-disabled')
.text('Active');
}, 1000);
},
error: function(response) {
$button.removeClass('updating-message').text('Update Now');
alert(response.errorMessage);
}
});
});
// Activate plugin
$('.plugin-card .activate-now').on('click', function(e) {
e.preventDefault();
var $button = $(this);
var url = $button.attr('href');
var slug = $button.data('slug');
$button.addClass('updating-message').text('Activating...');
$.ajax({
url: url,
dataType: 'html',
success: function() {
$button.removeClass('updating-message').addClass('updated-message').text('Activated!');
setTimeout(function() {
// Replace the button with an active button
var $parent = $button.parent();
$button.remove();
$parent.html('<button type="button" class="button button-disabled" disabled="disabled">Active</button>');
}, 1000);
},
error: function() {
$button.removeClass('updating-message').text('Activate');
alert('Failed to activate plugin. Please try again or activate from the Plugins page.');
}
});
});
}
// Initialize theme handlers
function initThemeHandlers() {
console.log('Initializing theme handlers');
// Remove any existing event handlers to prevent duplicates
$('.theme-actions .install-now').off('click');
$('.theme-actions .activate-now').off('click');
// Install theme - use standard WordPress behavior
$('.theme-actions .install-now').on('click', function(e) {
// We're not preventing default here - let the standard WordPress installer handle it
// Just add the updating message
var $button = $(this);
var slug = $button.data('slug');
$button.addClass('updating-message').text('Installing...');
console.log('Installing theme using standard WordPress URL:', $button.attr('href'));
// The rest will be handled by WordPress core
});
// Activate theme - use standard WordPress behavior
$('.theme-actions .activate-now').on('click', function(e) {
// We're not preventing default here - let the standard WordPress activation handle it
// Just add the updating message
var $button = $(this);
var slug = $button.data('slug');
$button.addClass('updating-message').text('Activating...');
console.log('Activating theme using standard WordPress URL:', $button.attr('href'));
// The rest will be handled by WordPress core
});
}
});

View File

@ -1,8 +1,9 @@
<?php <?php
/** /**
* Theme panel template for WP Allstars * Theme panel template for SEO Pro Stack
* *
* @package WP_Allstars * @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Partials
*/ */
// Prevent direct access // Prevent direct access
@ -24,7 +25,7 @@ if (!defined('ABSPATH')) {
$installed_theme = wp_get_theme('kadence'); $installed_theme = wp_get_theme('kadence');
$current_theme = wp_get_theme(); $current_theme = wp_get_theme();
$is_active = ($current_theme->get_stylesheet() === 'kadence'); $is_active = ($current_theme->get_stylesheet() === 'kadence');
$nonce = wp_create_nonce('wp-allstars-nonce'); $nonce = wp_create_nonce('wp-seoprostack-nonce');
if ($is_active): ?> if ($is_active): ?>
<button type="button" class="button button-disabled" disabled="disabled"> <button type="button" class="button button-disabled" disabled="disabled">

View File

@ -3,7 +3,7 @@
* Pro Plugins Configuration * Pro Plugins Configuration
*/ */
function wp_allstars_get_pro_plugins_config() { function wp_seoprostack_get_pro_plugins_config() {
return array( return array(
'magic-login-pro' => array( 'magic-login-pro' => array(
'name' => 'Magic Login Pro', 'name' => 'Magic Login Pro',
@ -776,3 +776,8 @@ function wp_allstars_get_pro_plugins_config() {
) )
); );
} }
// Backward compatibility alias
function wp_allstars_get_pro_plugins_config() {
return wp_seoprostack_get_pro_plugins_config();
}

View File

@ -4,35 +4,49 @@
*/ */
// Add menu item // Add menu item
function wp_allstars_admin_menu() { function wp_seoprostack_admin_menu() {
add_options_page( add_options_page(
'WP ALLSTARS Settings', 'SEO Pro Stack Settings',
'WP ALLSTARS', 'SEO Pro Stack',
'manage_options', 'manage_options',
'wp-allstars', 'seoprostack',
'wp_allstars_settings_page' 'wp_seoprostack_settings_page'
); );
} }
add_action('admin_menu', 'wp_allstars_admin_menu'); // Backward compatibility alias
function wp_allstars_admin_menu() {
return wp_seoprostack_admin_menu();
}
add_action('admin_menu', 'wp_seoprostack_admin_menu');
// Register settings // Register settings
function wp_allstars_register_settings() { function wp_seoprostack_register_settings() {
// Removed minification settings // Removed minification settings
} }
add_action('admin_init', 'wp_allstars_register_settings'); // Backward compatibility alias
function wp_allstars_register_settings() {
return wp_seoprostack_register_settings();
}
add_action('admin_init', 'wp_seoprostack_register_settings');
// AJAX handler for settings // AJAX handler for settings
function wp_allstars_update_option() { function wp_seoprostack_update_option() {
check_ajax_referer('wp-allstars-nonce', 'nonce'); check_ajax_referer('seoprostack-nonce', 'nonce');
$option = sanitize_text_field($_POST['option']); $option = sanitize_text_field($_POST['option']);
$value = intval($_POST['value']); $value = intval($_POST['value']);
update_option($option, $value); update_option($option, $value);
wp_send_json_success('Option updated'); wp_send_json_success('Option updated');
} }
add_action('wp_ajax_wp_allstars_update_option', 'wp_allstars_update_option'); // Backward compatibility alias
function wp_allstars_update_option() {
return wp_seoprostack_update_option();
}
add_action('wp_ajax_wp_seoprostack_update_option', 'wp_seoprostack_update_option');
// Add new AJAX action with updated name
add_action('wp_ajax_wp_seoprostack_update_option', 'wp_seoprostack_update_option');
// Define tools // Define tools
function wp_allstars_get_tools() { function wp_seoprostack_get_tools() {
return array( return array(
'advise' => array( 'advise' => array(
'name' => 'Advise.so', 'name' => 'Advise.so',
@ -555,7 +569,7 @@ function wp_allstars_get_tools() {
} }
// Define hosting providers // Define hosting providers
function wp_allstars_get_hosting_providers() { function wp_seoprostack_get_hosting_providers() {
return array( return array(
'closte' => array( 'closte' => array(
'name' => 'Closte', 'name' => 'Closte',
@ -703,7 +717,7 @@ function wp_allstars_get_hosting_providers() {
} }
// Define recommended plugins // Define recommended plugins
function wp_allstars_get_recommended_plugins() { function wp_seoprostack_get_recommended_plugins() {
return array( return array(
'minimal' => array( 'minimal' => array(
'antispam-bee', 'antispam-bee',
@ -860,8 +874,8 @@ function wp_allstars_get_recommended_plugins() {
} }
// Add transient caching for plugin data // Add transient caching for plugin data
function wp_allstars_get_cached_plugins($category) { function wp_seoprostack_get_cached_plugins($category) {
$cache_key = 'wp_allstars_plugins_' . $category; $cache_key = 'wp_seoprostack_plugins_' . $category;
$cached_data = get_transient($cache_key); $cached_data = get_transient($cache_key);
if ($cached_data !== false) { if ($cached_data !== false) {
@ -871,15 +885,15 @@ function wp_allstars_get_cached_plugins($category) {
return false; return false;
} }
function wp_allstars_set_cached_plugins($category, $data) { function wp_seoprostack_set_cached_plugins($category, $data) {
$cache_key = 'wp_allstars_plugins_' . $category; $cache_key = 'wp_seoprostack_plugins_' . $category;
set_transient($cache_key, $data, 12 * HOUR_IN_SECONDS); set_transient($cache_key, $data, 12 * HOUR_IN_SECONDS);
} }
// Add AJAX endpoint for plugin list // Add AJAX endpoint for plugin list
function wp_allstars_ajax_get_plugins() { function wp_seoprostack_ajax_get_plugins() {
// Check nonce with the correct action name // Check nonce with the correct action name
if (!check_ajax_referer('wp-allstars-nonce', '_wpnonce', false)) { if (!check_ajax_referer('wp-seoprostack-nonce', 'nonce', false)) {
wp_send_json_error('Invalid security token sent.'); wp_send_json_error('Invalid security token sent.');
return; return;
} }
@ -893,19 +907,19 @@ function wp_allstars_ajax_get_plugins() {
require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
// Get our recommended plugins for this category // Get our recommended plugins for this category
$recommended_plugins = wp_allstars_get_recommended_plugins(); $recommended_plugins = wp_seoprostack_get_recommended_plugins();
if (!isset($recommended_plugins[$category])) { if (!isset($recommended_plugins[$category])) {
wp_send_json_error('Invalid category: ' . $category); wp_send_json_error('Invalid category: ' . $category);
return; return;
} }
// Try to get cached data first // Try to get cached data first
$cached_data = wp_allstars_get_cached_plugins($category); $cached_data = wp_seoprostack_get_cached_plugins($category);
if ($cached_data !== false) { if ($cached_data !== false) {
error_log('Using cached data for category: ' . $category); error_log('Using cached data for category: ' . $category);
try { try {
// Generate plugin cards HTML // Generate plugin cards HTML
$html = wp_allstars_generate_plugin_cards($cached_data->plugins); $html = wp_seoprostack_generate_plugin_cards($cached_data->plugins);
wp_send_json_success($html); wp_send_json_success($html);
return; return;
} catch (Exception $e) { } catch (Exception $e) {
@ -979,21 +993,24 @@ function wp_allstars_ajax_get_plugins() {
); );
// Cache the results // Cache the results
wp_allstars_set_cached_plugins($category, $res); wp_seoprostack_set_cached_plugins($category, $res);
// Generate plugin cards HTML // Generate plugin cards HTML
$html = wp_allstars_generate_plugin_cards($plugins); $html = wp_seoprostack_generate_plugin_cards($plugins);
wp_send_json_success($html); wp_send_json_success($html);
} catch (Exception $e) { } catch (Exception $e) {
error_log('Failed to fetch plugin data: ' . $e->getMessage()); error_log('Failed to fetch plugin data: ' . $e->getMessage());
wp_send_json_error('Failed to fetch plugin data: ' . $e->getMessage()); wp_send_json_error('Failed to fetch plugin data: ' . $e->getMessage());
} catch (Error $e) {
error_log('Failed to fetch plugin data: ' . $e->getMessage());
wp_send_json_error('Failed to fetch plugin data: ' . $e->getMessage());
} }
} }
add_action('wp_ajax_wp_allstars_get_plugins', 'wp_allstars_ajax_get_plugins'); add_action('wp_ajax_wp_seoprostack_get_plugins', 'wp_seoprostack_ajax_get_plugins');
// Function to generate plugin cards HTML // Function to generate plugin cards HTML
function wp_allstars_generate_plugin_cards($plugins) { function wp_seoprostack_generate_plugin_cards($plugins) {
if (empty($plugins)) { if (empty($plugins)) {
return '<div class="notice notice-error"><p>No plugins found.</p></div>'; return '<div class="notice notice-error"><p>No plugins found.</p></div>';
} }
@ -1032,7 +1049,7 @@ function wp_allstars_generate_plugin_cards($plugins) {
} }
// Add "Go Pro" button if applicable // Add "Go Pro" button if applicable
$pro_plugins = wp_allstars_get_pro_plugins_config(); $pro_plugins = wp_seoprostack_get_pro_plugins_config();
foreach ($pro_plugins as $pro_plugin) { foreach ($pro_plugins as $pro_plugin) {
if (isset($pro_plugin['free_slug']) && $pro_plugin['free_slug'] === $plugin->slug) { if (isset($pro_plugin['free_slug']) && $pro_plugin['free_slug'] === $plugin->slug) {
// Find the primary button URL in the button_group array // Find the primary button URL in the button_group array
@ -1102,16 +1119,16 @@ function wp_allstars_generate_plugin_cards($plugins) {
} }
// Helper function to add pro button to plugin cards // Helper function to add pro button to plugin cards
function wp_allstars_add_pro_button($action_links, $plugin) { function wp_seoprostack_add_pro_button($action_links, $plugin) {
// Get pro plugins configuration // Get pro plugins configuration
$pro_plugins = wp_allstars_get_pro_plugins_config(); $pro_plugins = wp_seoprostack_get_pro_plugins_config();
// Check if this plugin has a pro version // Check if this plugin has a pro version
foreach ($pro_plugins as $pro_plugin) { foreach ($pro_plugins as $pro_plugin) {
if (isset($pro_plugin['free_slug']) && $pro_plugin['free_slug'] === $plugin['slug']) { if (isset($pro_plugin['free_slug']) && $pro_plugin['free_slug'] === $plugin['slug']) {
$action_links[] = sprintf( $action_links[] = sprintf(
'<a class="button button-primary" href="%s" target="_blank">%s</a>', '<a class="button button-primary" href="%s" target="_blank">%s</a>',
esc_url(wp_allstars_get_pro_plugin_url($pro_plugin)), esc_url(wp_seoprostack_get_pro_plugin_url($pro_plugin)),
esc_html__('Go Pro', 'wp-allstars') esc_html__('Go Pro', 'wp-allstars')
); );
break; break;
@ -1127,7 +1144,7 @@ function wp_allstars_add_pro_button($action_links, $plugin) {
* @param array $pro_plugin The pro plugin configuration array * @param array $pro_plugin The pro plugin configuration array
* @return string The URL for the pro plugin * @return string The URL for the pro plugin
*/ */
function wp_allstars_get_pro_plugin_url($pro_plugin) { function wp_seoprostack_get_pro_plugin_url($pro_plugin) {
// Find the primary button URL in the button_group array // Find the primary button URL in the button_group array
$pro_url = ''; $pro_url = '';
@ -1150,66 +1167,65 @@ function wp_allstars_get_pro_plugin_url($pro_plugin) {
} }
// Remove the old plugins API filter since we're handling everything in the AJAX endpoint // 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'); remove_filter('plugins_api_result', 'wp_seoprostack_plugins_api_result');
// Clear plugin cache when plugins are updated, activated, or deactivated // Clear plugin cache when plugins are updated, activated, or deactivated
function wp_allstars_clear_plugin_cache() { function wp_seoprostack_clear_plugin_cache() {
$recommended_plugins = wp_allstars_get_recommended_plugins(); $recommended_plugins = wp_seoprostack_get_recommended_plugins();
foreach (array_keys($recommended_plugins) as $category) { foreach (array_keys($recommended_plugins) as $category) {
delete_transient('wp_allstars_plugins_' . $category); delete_transient('wp_seoprostack_plugins_' . $category);
} }
} }
add_action('upgrader_process_complete', 'wp_allstars_clear_plugin_cache', 10, 0); add_action('upgrader_process_complete', 'wp_seoprostack_clear_plugin_cache', 10, 0);
add_action('activated_plugin', 'wp_allstars_clear_plugin_cache'); add_action('activated_plugin', 'wp_seoprostack_clear_plugin_cache');
add_action('deactivated_plugin', 'wp_allstars_clear_plugin_cache'); add_action('deactivated_plugin', 'wp_seoprostack_clear_plugin_cache');
add_action('deleted_plugin', 'wp_allstars_clear_plugin_cache'); add_action('deleted_plugin', 'wp_seoprostack_clear_plugin_cache');
add_action('update_option_active_plugins', 'wp_allstars_clear_plugin_cache'); add_action('update_option_active_plugins', 'wp_seoprostack_clear_plugin_cache');
// Add transient caching for theme data // Add transient caching for theme data
function wp_allstars_get_cached_theme() { function wp_seoprostack_get_cached_theme() {
$cache_key = 'wp_allstars_theme_kadence'; $cache_key = 'wp_seoprostack_theme_kadence';
return get_transient($cache_key); return get_transient($cache_key);
} }
function wp_allstars_set_cached_theme($data) { function wp_seoprostack_set_cached_theme($data) {
$cache_key = 'wp_allstars_theme_kadence'; $cache_key = 'wp_seoprostack_theme_kadence';
set_transient($cache_key, $data, 12 * HOUR_IN_SECONDS); set_transient($cache_key, $data, 12 * HOUR_IN_SECONDS);
} }
// Add AJAX endpoint for theme // Add AJAX endpoint for theme
function wp_allstars_ajax_get_themes() { function wp_seoprostack_ajax_get_themes() {
error_log('WP ALLSTARS: Theme AJAX handler started'); error_log('SEO Pro Stack: Theme AJAX handler started');
// Check nonce with the correct action name // Check nonce with the correct action name
if (!isset($_POST['_wpnonce'])) { if (!isset($_POST['_wpnonce'])) {
error_log('WP ALLSTARS: No nonce provided'); error_log('SEO Pro Stack: No nonce provided');
wp_send_json_error('No security token provided.'); wp_send_json_error('No security token provided.');
return; return;
} }
if (!check_ajax_referer('wp-allstars-nonce', '_wpnonce', false)) { if (!check_ajax_referer('wp-seoprostack-nonce', '_wpnonce', false)) {
error_log('WP ALLSTARS: Invalid nonce: ' . sanitize_text_field($_POST['_wpnonce'])); error_log('SEO Pro Stack: Invalid nonce: ' . sanitize_text_field($_POST['_wpnonce']));
wp_send_json_error('Invalid security token sent.'); wp_send_json_error('Invalid security token sent.');
return; return;
} }
if (!current_user_can('install_themes')) { if (!current_user_can('install_themes')) {
error_log('WP ALLSTARS: User does not have permission to install themes'); error_log('SEO Pro Stack: User does not have permission to install themes');
wp_send_json_error('Permission denied'); wp_die(-1);
return;
} }
error_log('WP ALLSTARS: Starting theme fetch process'); error_log('SEO Pro Stack: Starting theme fetch process');
try { try {
error_log('WP ALLSTARS: Fetching theme data for kadence'); error_log('SEO Pro Stack: Fetching theme data for kadence');
// Check if we have cached data first // Check if we have cached data first
$theme_data = wp_allstars_get_cached_theme(); $theme_data = wp_seoprostack_get_cached_theme();
// If no cached data, fetch from API // If no cached data, fetch from API
if (empty($theme_data)) { if (empty($theme_data)) {
error_log('WP ALLSTARS: No cached theme data, fetching from API'); error_log('SEO Pro Stack: No cached theme data, fetching from API');
// Get theme data with minimal fields // Get theme data with minimal fields
$theme_data = themes_api('theme_information', array( $theme_data = themes_api('theme_information', array(
@ -1236,19 +1252,19 @@ function wp_allstars_ajax_get_themes() {
// Cache the result if successful // Cache the result if successful
if (!is_wp_error($theme_data)) { if (!is_wp_error($theme_data)) {
wp_allstars_set_cached_theme($theme_data); wp_seoprostack_set_cached_theme($theme_data);
} }
} else { } else {
error_log('WP ALLSTARS: Using cached theme data'); error_log('SEO Pro Stack: Using cached theme data');
} }
if (is_wp_error($theme_data)) { if (is_wp_error($theme_data)) {
error_log('WP ALLSTARS Theme API Error: ' . $theme_data->get_error_message()); error_log('SEO Pro Stack Theme API Error: ' . $theme_data->get_error_message());
wp_send_json_error('Theme API Error: ' . $theme_data->get_error_message()); wp_send_json_error('Theme API Error: ' . $theme_data->get_error_message());
return; return;
} }
error_log('WP ALLSTARS: Successfully fetched theme data'); error_log('SEO Pro Stack: Successfully fetched theme data');
// Format author data // Format author data
$author = ''; $author = '';
@ -1258,7 +1274,7 @@ function wp_allstars_ajax_get_themes() {
$author = isset($theme_data->author['display_name']) ? $theme_data->author['display_name'] : ''; $author = isset($theme_data->author['display_name']) ? $theme_data->author['display_name'] : '';
} }
error_log('WP ALLSTARS: Theme data retrieved, generating HTML'); error_log('SEO Pro Stack: Theme data retrieved, generating HTML');
// Generate custom HTML for the theme using our template partial // Generate custom HTML for the theme using our template partial
ob_start(); ob_start();
@ -1266,55 +1282,55 @@ function wp_allstars_ajax_get_themes() {
$html = ob_get_clean(); $html = ob_get_clean();
if (empty($html)) { if (empty($html)) {
error_log('WP ALLSTARS: Empty HTML generated'); error_log('SEO Pro Stack: Empty HTML generated');
wp_send_json_error('Failed to generate theme display'); wp_send_json_error('Failed to generate theme display');
return; return;
} }
error_log('WP ALLSTARS: Successfully generated theme display, HTML length: ' . strlen($html)); error_log('SEO Pro Stack: Successfully generated theme display, HTML length: ' . strlen($html));
wp_send_json_success($html); wp_send_json_success($html);
exit; // Ensure we exit after sending the JSON response exit; // Ensure we exit after sending the JSON response
} catch (Exception $e) { } catch (Exception $e) {
error_log('WP ALLSTARS Theme loading exception: ' . $e->getMessage()); error_log('SEO Pro Stack Theme loading exception: ' . $e->getMessage());
error_log('WP ALLSTARS Theme loading exception trace: ' . $e->getTraceAsString()); error_log('SEO Pro Stack Theme loading exception trace: ' . $e->getTraceAsString());
wp_send_json_error('Theme loading error: ' . $e->getMessage()); wp_send_json_error('Theme loading error: ' . $e->getMessage());
} catch (Error $e) { } catch (Error $e) {
error_log('WP ALLSTARS Theme loading error: ' . $e->getMessage()); error_log('SEO Pro Stack Theme loading error: ' . $e->getMessage());
error_log('WP ALLSTARS Theme loading error trace: ' . $e->getTraceAsString()); error_log('SEO Pro Stack Theme loading error trace: ' . $e->getTraceAsString());
wp_send_json_error('Theme loading error: ' . $e->getMessage()); wp_send_json_error('Theme loading error: ' . $e->getMessage());
} }
} }
add_action('wp_ajax_wp_allstars_get_themes', 'wp_allstars_ajax_get_themes'); add_action('wp_ajax_wp_seoprostack_get_themes', 'wp_seoprostack_ajax_get_themes');
// Clear theme cache when themes are updated // Clear theme cache when themes are updated
function wp_allstars_clear_theme_cache() { function wp_seoprostack_clear_theme_cache() {
delete_transient('wp_allstars_theme_kadence'); delete_transient('wp_seoprostack_theme_kadence');
} }
add_action('upgrader_process_complete', 'wp_allstars_clear_theme_cache', 10, 0); add_action('upgrader_process_complete', 'wp_seoprostack_clear_theme_cache', 10, 0);
add_action('switch_theme', 'wp_allstars_clear_theme_cache'); add_action('switch_theme', 'wp_seoprostack_clear_theme_cache');
// Add AJAX handler for theme activation // Add AJAX handler for theme activation
function wp_allstars_activate_theme() { function wp_seoprostack_activate_theme() {
// Debug information // Debug information
error_log('Theme activation AJAX request received: ' . print_r($_POST, true)); error_log('SEO Pro Stack: Theme activation AJAX request received: ' . print_r($_POST, true));
// Check nonce with the correct action name // Check nonce with the correct action name
if (!check_ajax_referer('wp-allstars-nonce', '_wpnonce', false)) { if (!check_ajax_referer('wp-seoprostack-nonce', '_wpnonce', false)) {
error_log('Theme activation failed: Invalid nonce'); error_log('SEO Pro Stack: Theme activation failed: Invalid nonce');
wp_send_json_error('Invalid security token sent.'); wp_send_json_error('Invalid security token sent.');
return; return;
} }
if (!current_user_can('switch_themes')) { if (!current_user_can('switch_themes')) {
error_log('Theme activation failed: Permission denied'); error_log('SEO Pro Stack: Theme activation failed: Permission denied');
wp_send_json_error('Permission denied'); wp_send_json_error('Permission denied');
return; return;
} }
$theme = isset($_POST['theme']) ? sanitize_text_field($_POST['theme']) : ''; $theme = isset($_POST['theme']) ? sanitize_text_field($_POST['theme']) : '';
if (empty($theme)) { if (empty($theme)) {
error_log('Theme activation failed: No theme specified'); error_log('SEO Pro Stack: Theme activation failed: No theme specified');
wp_send_json_error('No theme specified'); wp_send_json_error('No theme specified');
return; return;
} }
@ -1322,13 +1338,13 @@ function wp_allstars_activate_theme() {
// Get the theme object // Get the theme object
$theme_obj = wp_get_theme($theme); $theme_obj = wp_get_theme($theme);
if (!$theme_obj->exists()) { if (!$theme_obj->exists()) {
error_log('Theme activation failed: Theme does not exist - ' . $theme); error_log('SEO Pro Stack: Theme activation failed: Theme does not exist - ' . $theme);
wp_send_json_error('Theme does not exist'); wp_send_json_error('Theme does not exist');
return; return;
} }
if ($theme_obj->errors()) { if ($theme_obj->errors()) {
error_log('Theme activation failed: Theme has errors - ' . print_r($theme_obj->errors(), true)); error_log('SEO Pro Stack: Theme activation failed: Theme has errors - ' . print_r($theme_obj->errors(), true));
wp_send_json_error('Theme has errors'); wp_send_json_error('Theme has errors');
return; return;
} }
@ -1336,7 +1352,7 @@ function wp_allstars_activate_theme() {
// Check if theme is already active // Check if theme is already active
$current_theme = wp_get_theme(); $current_theme = wp_get_theme();
if ($current_theme->get_stylesheet() === $theme) { if ($current_theme->get_stylesheet() === $theme) {
error_log('Theme is already active: ' . $theme); error_log('SEO Pro Stack: Theme is already active: ' . $theme);
wp_send_json_success(array( wp_send_json_success(array(
'message' => 'Theme is already active', 'message' => 'Theme is already active',
'customize_url' => admin_url('customize.php') 'customize_url' => admin_url('customize.php')
@ -1345,26 +1361,26 @@ function wp_allstars_activate_theme() {
} }
// Switch the theme // Switch the theme
error_log('Switching to theme: ' . $theme); error_log('SEO Pro Stack: Switching to theme: ' . $theme);
switch_theme($theme); switch_theme($theme);
// Check if the switch was successful // Check if the switch was successful
$active_theme = wp_get_theme(); $active_theme = wp_get_theme();
if ($active_theme->get_stylesheet() === $theme) { if ($active_theme->get_stylesheet() === $theme) {
error_log('Theme activated successfully: ' . $theme); error_log('SEO Pro Stack: Theme activated successfully: ' . $theme);
wp_send_json_success(array( wp_send_json_success(array(
'message' => 'Theme activated successfully', 'message' => 'Theme activated successfully',
'customize_url' => admin_url('customize.php') 'customize_url' => admin_url('customize.php')
)); ));
} else { } else {
error_log('Failed to activate theme: ' . $theme . ', active theme is: ' . $active_theme->get_stylesheet()); error_log('SEO Pro Stack: Failed to activate theme: ' . $theme . ', active theme is: ' . $active_theme->get_stylesheet());
wp_send_json_error('Failed to activate theme'); wp_send_json_error('Failed to activate theme');
} }
} }
add_action('wp_ajax_wp_allstars_activate_theme', 'wp_allstars_activate_theme'); add_action('wp_ajax_wp_seoprostack_activate_theme', 'wp_seoprostack_activate_theme');
// Register settings page HTML // Register settings page HTML
function wp_allstars_settings_page() { function wp_seoprostack_settings_page() {
global $tabs; global $tabs;
$active_tab = isset($_GET['tab']) ? $_GET['tab'] : 'general'; $active_tab = isset($_GET['tab']) ? $_GET['tab'] : 'general';
@ -1372,21 +1388,21 @@ function wp_allstars_settings_page() {
// Clear cache and load required files // Clear cache and load required files
if ($active_tab === 'recommended') { if ($active_tab === 'recommended') {
wp_allstars_clear_plugin_cache(); wp_seoprostack_clear_plugin_cache();
require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
wp_enqueue_script('plugin-install'); wp_enqueue_script('plugin-install');
wp_enqueue_script('updates'); wp_enqueue_script('updates');
add_thickbox(); add_thickbox();
wp_enqueue_style('wp-allstars-admin', plugins_url('css/wp-allstars-admin.css', __FILE__)); wp_enqueue_style('seoprostack-admin', SEOPROSTACK_PLUGIN_URL . 'admin/css/seoprostack-admin.css', array(), SEOPROSTACK_VERSION);
wp_enqueue_style('wp-allstars-plugins', plugins_url('css/wp-allstars-plugins.css', __FILE__)); wp_enqueue_style('seoprostack-plugins', SEOPROSTACK_PLUGIN_URL . 'admin/css/seoprostack-admin.css', array(), SEOPROSTACK_VERSION);
// Add inline script to load plugins on page load // Add inline script to load plugins on page load
wp_add_inline_script('wp-allstars-admin', ' wp_add_inline_script('seoprostack-admin', '
jQuery(document).ready(function($) { jQuery(document).ready(function($) {
if ($("#wpa-plugin-list").length && $("#wpa-plugin-list").is(":empty")) { if ($("#seoprostack-plugin-list").length && $("#seoprostack-plugin-list").is(":empty")) {
var category = "' . esc_js($active_category) . '"; var category = "' . esc_js($active_category) . '";
var $container = $("#wpa-plugin-list"); var $container = $("#seoprostack-plugin-list");
var $loadingOverlay = $("<div class=\"wp-allstars-loading-overlay\"><span class=\"spinner is-active\"></span></div>"); var $loadingOverlay = $("<div class=\"seoprostack-loading-overlay\"><span class=\"spinner is-active\"></span></div>");
// Show loading overlay // Show loading overlay
$container.css("position", "relative").append($loadingOverlay); $container.css("position", "relative").append($loadingOverlay);
@ -1396,9 +1412,9 @@ function wp_allstars_settings_page() {
url: ajaxurl, url: ajaxurl,
type: "POST", type: "POST",
data: { data: {
action: "wp_allstars_get_plugins", action: "wp_seoprostack_get_plugins",
category: category, category: category,
_wpnonce: wpAllstars.nonce _wpnonce: wpSeoProStack.nonce
}, },
success: function(response) { success: function(response) {
$loadingOverlay.remove(); $loadingOverlay.remove();
@ -1424,20 +1440,20 @@ function wp_allstars_settings_page() {
}); });
'); ');
} elseif ($active_tab === 'theme') { } elseif ($active_tab === 'theme') {
wp_allstars_clear_theme_cache(); wp_seoprostack_clear_theme_cache();
require_once ABSPATH . 'wp-admin/includes/theme.php'; require_once ABSPATH . 'wp-admin/includes/theme.php';
wp_enqueue_script('theme-install'); wp_enqueue_script('theme-install');
wp_enqueue_script('updates'); wp_enqueue_script('updates');
add_thickbox(); add_thickbox();
wp_enqueue_style('wp-allstars-admin', plugins_url('css/wp-allstars-admin.css', __FILE__)); wp_enqueue_style('seoprostack-admin', SEOPROSTACK_PLUGIN_URL . 'admin/css/seoprostack-admin.css', array(), SEOPROSTACK_VERSION);
wp_enqueue_style('wp-allstars-plugins', plugins_url('css/wp-allstars-plugins.css', __FILE__)); wp_enqueue_style('seoprostack-plugins', SEOPROSTACK_PLUGIN_URL . 'admin/css/seoprostack-admin.css', array(), SEOPROSTACK_VERSION);
// Add inline script to load themes directly - same approach as plugins tab // Add inline script to load themes directly - same approach as plugins tab
wp_add_inline_script('wp-allstars-admin', ' wp_add_inline_script('seoprostack-admin', '
jQuery(document).ready(function($) { jQuery(document).ready(function($) {
if ($("#wpa-theme-list").length && $("#wpa-theme-list").is(":empty")) { if ($("#seoprostack-theme-list").length && $("#seoprostack-theme-list").is(":empty")) {
var $container = $("#wpa-theme-list"); var $container = $("#seoprostack-theme-list");
var $loadingOverlay = $("<div class=\"wp-allstars-loading-overlay\"><span class=\"spinner is-active\"></span></div>"); var $loadingOverlay = $("<div class=\"seoprostack-loading-overlay\"><span class=\"spinner is-active\"></span></div>");
// Show loading overlay // Show loading overlay
$container.css("position", "relative").append($loadingOverlay); $container.css("position", "relative").append($loadingOverlay);
@ -1447,8 +1463,8 @@ function wp_allstars_settings_page() {
url: ajaxurl, url: ajaxurl,
type: "POST", type: "POST",
data: { data: {
action: "wp_allstars_get_themes", action: "wp_seoprostack_get_themes",
_wpnonce: wpAllstars.nonce _wpnonce: wpSeoProStack.nonce
}, },
success: function(response) { success: function(response) {
$loadingOverlay.remove(); $loadingOverlay.remove();
@ -1473,123 +1489,123 @@ function wp_allstars_settings_page() {
'); ');
} }
?> ?>
<div class="wrap wp-allstars-wrap"> <div class="wrap seoprostack-wrap">
<div class="wp-allstars-header"> <div class="seoprostack-header">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1> <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<div class="wp-allstars-header-actions"> <div class="seoprostack-header-actions">
<span class="wp-allstars-version">Version <?php echo esc_html(WP_ALLSTARS_VERSION); ?></span> <span class="seoprostack-version">Version <?php echo esc_html(SEOPROSTACK_VERSION); ?></span>
<a href="https://www.wpallstars.com/" target="_blank" class="button button-secondary"> <a href="https://www.wpseoprostack.com/" target="_blank" class="button button-secondary">
<?php esc_html_e('Documentation', 'wp-allstars'); ?> <?php esc_html_e('Documentation', 'seoprostack'); ?>
</a> </a>
</div> </div>
</div> </div>
<div class="wpa-settings-container"> <div class="seoprostack-settings-container">
<div class="wp-allstars-nav"> <div class="seoprostack-nav">
<h2 class="nav-tab-wrapper"> <h2 class="nav-tab-wrapper">
<a href="?page=wp-allstars&tab=general" class="nav-tab <?php echo $active_tab == 'general' ? 'nav-tab-active' : ''; ?>"> <a href="?page=seoprostack&tab=general" class="nav-tab <?php echo $active_tab == 'general' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e('General', 'wp-allstars'); ?> <?php esc_html_e('General', 'seoprostack'); ?>
</a> </a>
<a href="?page=wp-allstars&tab=advanced" class="nav-tab <?php echo $active_tab == 'advanced' ? 'nav-tab-active' : ''; ?>"> <a href="?page=seoprostack&tab=advanced" class="nav-tab <?php echo $active_tab == 'advanced' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e('Advanced', 'wp-allstars'); ?> <?php esc_html_e('Advanced', 'seoprostack'); ?>
</a> </a>
<a href="?page=wp-allstars&tab=workflow" class="nav-tab <?php echo $active_tab == 'workflow' ? 'nav-tab-active' : ''; ?>"> <a href="?page=seoprostack&tab=workflow" class="nav-tab <?php echo $active_tab == 'workflow' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e('Workflow', 'wp-allstars'); ?> <?php esc_html_e('Workflow', 'seoprostack'); ?>
</a> </a>
<a href="?page=wp-allstars&tab=recommended" class="nav-tab <?php echo $active_tab == 'recommended' ? 'nav-tab-active' : ''; ?>"> <a href="?page=seoprostack&tab=recommended" class="nav-tab <?php echo $active_tab == 'recommended' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e('Free Plugins', 'wp-allstars'); ?> <?php esc_html_e('Free Plugins', 'seoprostack'); ?>
</a> </a>
<a href="?page=wp-allstars&tab=pro" class="nav-tab <?php echo $active_tab == 'pro' ? 'nav-tab-active' : ''; ?>"> <a href="?page=seoprostack&tab=pro" class="nav-tab <?php echo $active_tab == 'pro' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e('Pro Plugins', 'wp-allstars'); ?> <?php esc_html_e('Pro Plugins', 'seoprostack'); ?>
</a> </a>
<a href="?page=wp-allstars&tab=theme" class="nav-tab <?php echo $active_tab == 'theme' ? 'nav-tab-active' : ''; ?>"> <a href="?page=seoprostack&tab=theme" class="nav-tab <?php echo $active_tab == 'theme' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e('Theme', 'wp-allstars'); ?> <?php esc_html_e('Theme', 'seoprostack'); ?>
</a> </a>
<a href="?page=wp-allstars&tab=hosting" class="nav-tab <?php echo $active_tab == 'hosting' ? 'nav-tab-active' : ''; ?>"> <a href="?page=seoprostack&tab=hosting" class="nav-tab <?php echo $active_tab == 'hosting' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e('Hosting', 'wp-allstars'); ?> <?php esc_html_e('Hosting', 'seoprostack'); ?>
</a> </a>
<a href="?page=wp-allstars&tab=tools" class="nav-tab <?php echo $active_tab == 'tools' ? 'nav-tab-active' : ''; ?>"> <a href="?page=seoprostack&tab=tools" class="nav-tab <?php echo $active_tab == 'tools' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e('Tools', 'wp-allstars'); ?> <?php esc_html_e('Tools', 'seoprostack'); ?>
</a> </a>
</h2> </h2>
</div> </div>
<div class="wpa-settings-content"> <div class="seoprostack-settings-content">
<?php if ($active_tab == 'workflow'): ?> <?php if ($active_tab == 'workflow'): ?>
<div class="wp-allstars-settings-content tab-content" id="workflow"> <div class="tab-content" id="workflow">
<div class="wp-allstars-toggle"> <div class="seoprostack-toggle">
<div class="wp-allstars-toggle-header" aria-expanded="false"> <div class="seoprostack-toggle-header" aria-expanded="false">
<div class="wp-allstars-toggle-main"> <div class="seoprostack-toggle-main">
<div class="wp-allstars-toggle-left"> <div class="seoprostack-toggle-left">
<div class="wp-toggle-switch"> <div class="seoprostack-toggle-switch">
<input type="checkbox" <input type="checkbox"
id="wp_allstars_auto_upload_images" id="wp_seoprostack_auto_upload_images"
name="wp_allstars_auto_upload_images" name="wp_seoprostack_auto_upload_images"
value="1" value="1"
<?php checked(get_option('wp_allstars_auto_upload_images', false)); ?> <?php checked(get_option('wp_seoprostack_auto_upload_images', get_option('wp_allstars_auto_upload_images', false))); ?>
/> />
<span class="wp-toggle-slider"></span> <span class="seoprostack-toggle-slider"></span>
</div> </div>
<label for="wp_allstars_auto_upload_images"> <label for="wp_seoprostack_auto_upload_images">
<?php esc_html_e('Enable Auto Upload Images', 'wp-allstars'); ?> <?php esc_html_e('Enable Auto Upload Images', 'seoprostack'); ?>
</label> </label>
</div> </div>
</div> </div>
<p class="wp-setting-description"> <p class="seoprostack-setting-description">
<?php esc_html_e('Import images that have external URLs into your Media Library when saving. Consider disabling during large data imports with many external image URLs.', 'wp-allstars'); ?> <?php esc_html_e('Import images that have external URLs into your Media Library when saving. Consider disabling during large data imports with many external image URLs.', 'seoprostack'); ?>
</p> </p>
</div> </div>
<div class="wp-allstars-toggle-settings"> <div class="seoprostack-toggle-settings">
<div class="wp-allstars-setting-row"> <div class="seoprostack-setting-row">
<label for="wp_allstars_max_width"><?php esc_html_e('Max Width', 'wp-allstars'); ?></label> <label for="wp_seoprostack_max_width"><?php esc_html_e('Max Width', 'seoprostack'); ?></label>
<input type="number" <input type="number"
id="wp_allstars_max_width" id="wp_seoprostack_max_width"
name="wp_allstars_max_width" name="wp_seoprostack_max_width"
value="<?php echo esc_attr(get_option('wp_allstars_max_width', 2560)); ?>" value="<?php echo esc_attr(get_option('wp_seoprostack_max_width', get_option('wp_allstars_max_width', 2560))); ?>"
/> />
<p class="description"><?php esc_html_e('Maximum width for uploaded images in pixels.', 'wp-allstars'); ?></p> <p class="description"><?php esc_html_e('Maximum width for uploaded images in pixels.', 'seoprostack'); ?></p>
</div> </div>
<div class="wp-allstars-setting-row"> <div class="seoprostack-setting-row">
<label for="wp_allstars_max_height"><?php esc_html_e('Max Height', 'wp-allstars'); ?></label> <label for="wp_seoprostack_max_height"><?php esc_html_e('Max Height', 'seoprostack'); ?></label>
<input type="number" <input type="number"
id="wp_allstars_max_height" id="wp_seoprostack_max_height"
name="wp_allstars_max_height" name="wp_seoprostack_max_height"
value="<?php echo esc_attr(get_option('wp_allstars_max_height', 2560)); ?>" value="<?php echo esc_attr(get_option('wp_seoprostack_max_height', get_option('wp_allstars_max_height', 2560))); ?>"
/> />
<p class="description"><?php esc_html_e('Maximum height for uploaded images in pixels.', 'wp-allstars'); ?></p> <p class="description"><?php esc_html_e('Maximum height for uploaded images in pixels.', 'seoprostack'); ?></p>
</div> </div>
<div class="wp-allstars-setting-row"> <div class="seoprostack-setting-row">
<label for="wp_exclude_urls"><?php esc_html_e('Exclude URLs', 'wp-allstars'); ?></label> <label for="wp_seoprostack_exclude_urls"><?php esc_html_e('Exclude URLs', 'seoprostack'); ?></label>
<textarea id="wp_exclude_urls" <textarea id="wp_seoprostack_exclude_urls"
name="wp_exclude_urls" name="wp_seoprostack_exclude_urls"
rows="3" rows="3"
placeholder="example.com&#10;another-domain.com" placeholder="example.com&#10;another-domain.com"
><?php echo esc_textarea(get_option('wp_allstars_exclude_urls', '')); ?></textarea> ><?php echo esc_textarea(get_option('wp_seoprostack_exclude_urls', get_option('wp_allstars_exclude_urls', ''))); ?></textarea>
<p class="description"><?php esc_html_e('Enter domains to exclude (one per line). Images from these domains will not be imported.', 'wp-allstars'); ?></p> <p class="description"><?php esc_html_e('Enter domains to exclude (one per line). Images from these domains will not be imported.', 'seoprostack'); ?></p>
</div> </div>
<div class="wp-allstars-setting-row"> <div class="seoprostack-setting-row">
<label for="wp_image_name"><?php esc_html_e('Image Name Pattern', 'wp-allstars'); ?></label> <label for="wp_seoprostack_image_name"><?php esc_html_e('Image Name Pattern', 'seoprostack'); ?></label>
<input type="text" <input type="text"
id="wp_image_name" id="wp_seoprostack_image_name"
name="wp_image_name" name="wp_seoprostack_image_name"
value="<?php echo esc_attr(get_option('wp_allstars_image_name_pattern', '%filename%')); ?>" value="<?php echo esc_attr(get_option('wp_seoprostack_image_name_pattern', get_option('wp_allstars_image_name_pattern', '%filename%'))); ?>"
/> />
<p class="description"> <p class="description">
<?php esc_html_e('Available patterns:', 'wp-allstars'); ?> %filename%, %post_id%, %postname%, %timestamp%, %date%, %year%, %month%, %day% <?php esc_html_e('Available patterns:', 'seoprostack'); ?> %filename%, %post_id%, %postname%, %timestamp%, %date%, %year%, %month%, %day%
</p> </p>
</div> </div>
<div class="wp-allstars-setting-row"> <div class="seoprostack-setting-row">
<label for="wp_image_alt"><?php esc_html_e('Image Alt Pattern', 'wp-allstars'); ?></label> <label for="wp_seoprostack_image_alt"><?php esc_html_e('Image Alt Pattern', 'seoprostack'); ?></label>
<input type="text" <input type="text"
id="wp_image_alt" id="wp_seoprostack_image_alt"
name="wp_image_alt" name="wp_seoprostack_image_alt"
value="<?php echo esc_attr(get_option('wp_allstars_image_alt_pattern', '%filename%')); ?>" value="<?php echo esc_attr(get_option('wp_seoprostack_image_alt_pattern', get_option('wp_allstars_image_alt_pattern', '%filename%'))); ?>"
/> />
<p class="description"> <p class="description">
<?php esc_html_e('Available patterns:', 'wp-allstars'); ?> %filename%, %post_title%, %post_id%, %postname%, %timestamp% <?php esc_html_e('Available patterns:', 'seoprostack'); ?> %filename%, %post_title%, %post_id%, %postname%, %timestamp%
</p> </p>
</div> </div>
</div> </div>
@ -1599,7 +1615,7 @@ function wp_allstars_settings_page() {
<?php elseif ($active_tab == 'theme'): ?> <?php elseif ($active_tab == 'theme'): ?>
<div class="tab-content" id="theme"> <div class="tab-content" id="theme">
<style> <style>
#wpa-theme-list { #seoprostack-theme-list {
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
} }
@ -1659,9 +1675,34 @@ function wp_allstars_settings_page() {
line-height: 34px; line-height: 34px;
text-align: center; text-align: center;
padding: 0 10px; padding: 0 10px;
font-size: 13px;
font-weight: normal;
margin: 0; margin: 0;
border: 1px solid #0071a1 !important;
border-radius: 3px !important;
background: #f6f7f7;
color: #0071a1;
display: inline-block;
vertical-align: top;
box-shadow: none;
cursor: pointer;
} }
@media (max-width: 782px) { .theme-actions .button:hover {
background: #f0f0f1;
border-color: #0071a1;
color: #0071a1;
}
.theme-actions .button-primary {
background: #0071a1;
border-color: #0071a1;
color: #fff;
}
.theme-actions .button-primary:hover {
background: #005d8c;
border-color: #005d8c;
color: #fff;
}
@media screen and (max-width: 782px) {
.theme-actions { .theme-actions {
flex-direction: column; flex-direction: column;
gap: 10px; gap: 10px;
@ -1673,13 +1714,13 @@ function wp_allstars_settings_page() {
} }
} }
</style> </style>
<div id="wpa-theme-list"></div> <div id="seoprostack-theme-list"></div>
</div> </div>
<?php elseif ($active_tab == 'hosting'): ?> <?php elseif ($active_tab == 'hosting'): ?>
<div class="tab-content" id="hosting"> <div class="tab-content" id="hosting">
<div class="wpa-pro-plugins"> <div class="wpa-pro-plugins">
<?php <?php
$hosting_providers = wp_allstars_get_hosting_providers(); $hosting_providers = wp_seoprostack_get_hosting_providers();
// Sort providers alphabetically by name // Sort providers alphabetically by name
uasort($hosting_providers, function($a, $b) { uasort($hosting_providers, function($a, $b) {
return strcasecmp($a['name'], $b['name']); return strcasecmp($a['name'], $b['name']);
@ -1759,15 +1800,15 @@ function wp_allstars_settings_page() {
</ul> </ul>
</div> </div>
<div class="wp-allstars-plugin-browser"> <div class="seoprostack-plugin-browser">
<div id="wpa-plugin-list"></div> <div id="seoprostack-plugin-list"></div>
</div> </div>
</div> </div>
<?php elseif ($active_tab == 'pro'): ?> <?php elseif ($active_tab == 'pro'): ?>
<div class="tab-content" id="pro"> <div class="tab-content" id="pro">
<div class="wpa-pro-plugins"> <div class="wpa-pro-plugins">
<?php <?php
$pro_plugins = wp_allstars_get_pro_plugins_config(); $pro_plugins = wp_seoprostack_get_pro_plugins_config();
// Sort plugins alphabetically by name // Sort plugins alphabetically by name
uasort($pro_plugins, function($a, $b) { uasort($pro_plugins, function($a, $b) {
return strcasecmp($a['name'], $b['name']); return strcasecmp($a['name'], $b['name']);
@ -1785,17 +1826,6 @@ function wp_allstars_settings_page() {
</a> </a>
<?php endforeach; ?> <?php endforeach; ?>
</div> </div>
<?php else: ?>
<div class="button-group">
<?php if (!empty($plugin['demo_url'])): ?>
<a href="<?php echo esc_url($plugin['demo_url']); ?>" class="button" target="_blank">
<?php esc_html_e('View Demo', 'wp-allstars'); ?>
</a>
<?php endif; ?>
<a href="<?php echo esc_url($plugin['url']); ?>" class="button button-primary" target="_blank">
<?php esc_html_e('Learn More', 'wp-allstars'); ?>
</a>
</div>
<?php endif; ?> <?php endif; ?>
</div> </div>
<?php <?php
@ -1869,14 +1899,14 @@ function wp_allstars_settings_page() {
border-color: #0071a1; border-color: #0071a1;
color: #0071a1; color: #0071a1;
} }
.wpa-pro-plugin .button-primary { .wpa-pro-plugin .button.button-primary {
background: #0071a1; background: #2271b1;
border-color: #0071a1; border-color: #2271b1 !important;
color: #fff; color: #fff;
} }
.wpa-pro-plugin .button-primary:hover { .wpa-pro-plugin .button.button-primary:hover {
background: #005d8c; background: #135e96;
border-color: #005d8c; border-color: #135e96 !important;
color: #fff; color: #fff;
} }
@media screen and (max-width: 960px) { @media screen and (max-width: 960px) {
@ -1906,29 +1936,29 @@ function wp_allstars_settings_page() {
</div> </div>
<?php elseif ($active_tab == 'general'): ?> <?php elseif ($active_tab == 'general'): ?>
<div class="tab-content" id="general"> <div class="tab-content" id="general">
<div class="wp-allstars-settings-section"> <div class="seoprostack-settings-section">
<div class="wp-allstars-settings-grid"> <div class="seoprostack-settings-grid">
<!-- Example of a simple toggle setting (no panel) --> <!-- Example of a simple toggle setting (no panel) -->
<div class="wp-setting-row"> <div class="seoprostack-setting-row">
<div class="wp-setting-header"> <div class="seoprostack-setting-header">
<div class="wp-setting-main"> <div class="seoprostack-setting-main">
<div class="wp-setting-left"> <div class="seoprostack-setting-left">
<div class="wp-toggle-switch"> <div class="seoprostack-toggle-switch">
<input type="checkbox" <input type="checkbox"
id="wp_allstars_simple_setting" id="wp_seoprostack_simple_setting"
name="wp_allstars_simple_setting" name="wp_seoprostack_simple_setting"
value="1" value="1"
<?php checked(get_option('wp_allstars_simple_setting', false)); ?> <?php checked(get_option('wp_seoprostack_simple_setting', get_option('wp_allstars_simple_setting', false))); ?>
/> />
<span class="wp-toggle-slider"></span> <span class="seoprostack-toggle-slider"></span>
</div> </div>
<label for="wp_allstars_simple_setting" class="wp-setting-label"> <label for="wp_seoprostack_simple_setting" class="seoprostack-setting-label">
<?php esc_html_e('Example: Simple Toggle', 'wp-allstars'); ?> <?php esc_html_e('Example: Simple Toggle', 'seoprostack'); ?>
</label> </label>
</div> </div>
</div> </div>
<p class="wp-setting-description"> <p class="seoprostack-setting-description">
<?php esc_html_e('This is an example of a simple toggle setting without an expandable panel. Currently for demonstration purposes only.', 'wp-allstars'); ?> <?php esc_html_e('This is an example of a simple toggle setting without an expandable panel. Currently for demonstration purposes only.', 'seoprostack'); ?>
</p> </p>
</div> </div>
</div> </div>
@ -1936,34 +1966,34 @@ function wp_allstars_settings_page() {
</div> </div>
<?php elseif ($active_tab == 'advanced'): ?> <?php elseif ($active_tab == 'advanced'): ?>
<div class="tab-content" id="advanced"> <div class="tab-content" id="advanced">
<div class="wp-allstars-settings-section"> <div class="seoprostack-settings-section">
<div class="wp-allstars-settings-grid"> <div class="seoprostack-settings-grid">
<!-- Example of an expandable panel setting --> <!-- Example of an expandable panel setting -->
<div class="wp-allstars-toggle"> <div class="seoprostack-toggle">
<div class="wp-allstars-toggle-header" aria-expanded="false"> <div class="seoprostack-toggle-header" aria-expanded="false">
<div class="wp-allstars-toggle-main"> <div class="seoprostack-toggle-main">
<div class="wp-allstars-toggle-left"> <div class="seoprostack-toggle-left">
<div class="wp-toggle-switch"> <div class="seoprostack-toggle-switch">
<input type="checkbox" <input type="checkbox"
id="wp_allstars_auto_upload_images" id="wp_seoprostack_auto_upload_images"
name="wp_allstars_auto_upload_images" name="wp_seoprostack_auto_upload_images"
value="1" value="1"
<?php checked(get_option('wp_allstars_auto_upload_images', false)); ?> <?php checked(get_option('wp_seoprostack_auto_upload_images', get_option('wp_allstars_auto_upload_images', false))); ?>
/> />
<span class="wp-toggle-slider"></span> <span class="seoprostack-toggle-slider"></span>
</div> </div>
<label for="wp_allstars_auto_upload_images"> <label for="wp_seoprostack_auto_upload_images">
<?php esc_html_e('Example: Expandable Panel', 'wp-allstars'); ?> <?php esc_html_e('Example: Expandable Panel', 'seoprostack'); ?>
</label> </label>
</div> </div>
</div> </div>
<p class="wp-setting-description"> <p class="seoprostack-setting-description">
<?php esc_html_e('This is an example of an expandable panel setting. Currently for demonstration purposes only - no actual functionality.', 'wp-allstars'); ?> <?php esc_html_e('This is an example of an expandable panel setting. Currently for demonstration purposes only - no actual functionality.', 'seoprostack'); ?>
</p> </p>
</div> </div>
<div class="wp-allstars-toggle-settings"> <div class="seoprostack-toggle-settings">
<div class="wp-allstars-setting-row"> <div class="seoprostack-setting-row">
<label for="example_text"><?php esc_html_e('Example Text Field', 'wp-allstars'); ?></label> <label for="example_text"><?php esc_html_e('Example Text Field', 'seoprostack'); ?></label>
<input type="text" <input type="text"
id="example_text" id="example_text"
name="example_text" name="example_text"
@ -2051,11 +2081,12 @@ function wp_allstars_settings_page() {
.wpa-pro-plugin .button.button-primary:hover { .wpa-pro-plugin .button.button-primary:hover {
background: #135e96; background: #135e96;
border-color: #135e96 !important; border-color: #135e96 !important;
color: #fff;
} }
</style> </style>
<div class="wpa-pro-plugins"> <div class="wpa-pro-plugins">
<?php <?php
$tools = wp_allstars_get_tools(); $tools = wp_seoprostack_get_tools();
// Sort tools alphabetically by name // Sort tools alphabetically by name
uasort($tools, function($a, $b) { uasort($tools, function($a, $b) {
return strcasecmp($a['name'], $b['name']); return strcasecmp($a['name'], $b['name']);
@ -2088,18 +2119,21 @@ function wp_allstars_settings_page() {
} }
// Enqueue admin scripts and styles // Enqueue admin scripts and styles
function wp_allstars_admin_enqueue_scripts($hook) { function wp_seoprostack_admin_enqueue_scripts($hook) {
if ('settings_page_wp-allstars' !== $hook) { if ($hook !== 'toplevel_page_seoprostack') {
return; return;
} }
wp_enqueue_style('wp-allstars-admin', plugins_url('css/wp-allstars-admin.css', __FILE__)); // Add admin CSS
wp_enqueue_script('wp-allstars-admin', plugins_url('js/wp-allstars-admin.js', __FILE__), array('jquery'), WP_ALLSTARS_VERSION, true); wp_enqueue_style('wp-seoprostack-admin', plugins_url('css/seoprostack-admin.css', __FILE__), array(), WP_ALLSTARS_VERSION);
// Add admin JavaScript
wp_enqueue_script('seoprostack-admin', plugins_url('js/seoprostack-admin.js', __FILE__), array('jquery'), WP_ALLSTARS_VERSION, true);
// Localize the script with new data // Localize the script with new data
wp_localize_script('wp-allstars-admin', 'wpAllstars', array( wp_localize_script('seoprostack-admin', 'wpSeoProStack', array(
'nonce' => wp_create_nonce('wp-allstars-nonce'), 'nonce' => wp_create_nonce('wp-seoprostack-nonce'),
'ajaxurl' => admin_url('admin-ajax.php') 'ajaxurl' => admin_url('admin-ajax.php')
)); ));
} }
add_action('admin_enqueue_scripts', 'wp_allstars_admin_enqueue_scripts'); add_action('admin_enqueue_scripts', 'wp_seoprostack_admin_enqueue_scripts');

View File

@ -0,0 +1,132 @@
<?php
/**
* The Advanced Settings AJAX handler.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/AJAX
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The Advanced Settings AJAX handler.
*/
class SEOProStack_AJAX_Advanced {
/**
* Initialize the AJAX handlers.
*/
public function init() {
add_action('wp_ajax_seoprostack_save_advanced_settings', array($this, 'save_advanced_settings'));
add_action('wp_ajax_seoprostack_optimize_database', array($this, 'optimize_database'));
}
/**
* Save advanced settings.
*/
public function save_advanced_settings() {
// Verify nonce
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'seoprostack_ajax_nonce')) {
wp_send_json_error(array('message' => 'Security check failed'));
}
// Check capabilities
if (!current_user_can('manage_options')) {
wp_send_json_error(array('message' => 'You do not have permission to change settings'));
}
// Get settings
$settings = array(
'disable_emojis' => isset($_POST['disable_emojis']) ? sanitize_text_field($_POST['disable_emojis']) : 'no',
'disable_embeds' => isset($_POST['disable_embeds']) ? sanitize_text_field($_POST['disable_embeds']) : 'no',
'remove_query_strings' => isset($_POST['remove_query_strings']) ? sanitize_text_field($_POST['remove_query_strings']) : 'no',
'disable_xmlrpc' => isset($_POST['disable_xmlrpc']) ? sanitize_text_field($_POST['disable_xmlrpc']) : 'no',
'remove_shortlink' => isset($_POST['remove_shortlink']) ? sanitize_text_field($_POST['remove_shortlink']) : 'no',
'remove_rsd_link' => isset($_POST['remove_rsd_link']) ? sanitize_text_field($_POST['remove_rsd_link']) : 'no',
'remove_wlwmanifest_link' => isset($_POST['remove_wlwmanifest_link']) ? sanitize_text_field($_POST['remove_wlwmanifest_link']) : 'no',
'disable_self_pingbacks' => isset($_POST['disable_self_pingbacks']) ? sanitize_text_field($_POST['disable_self_pingbacks']) : 'no',
'disable_feed_links' => isset($_POST['disable_feed_links']) ? sanitize_text_field($_POST['disable_feed_links']) : 'no',
'remove_rest_api_links' => isset($_POST['remove_rest_api_links']) ? sanitize_text_field($_POST['remove_rest_api_links']) : 'no',
'minify_html' => isset($_POST['minify_html']) ? sanitize_text_field($_POST['minify_html']) : 'no',
'minify_css' => isset($_POST['minify_css']) ? sanitize_text_field($_POST['minify_css']) : 'no',
'minify_js' => isset($_POST['minify_js']) ? sanitize_text_field($_POST['minify_js']) : 'no'
);
// Save settings
update_option('seoprostack_advanced_settings', $settings);
// Flush rewrite rules if necessary
if (isset($settings['disable_feed_links']) && $settings['disable_feed_links'] === 'yes') {
flush_rewrite_rules();
}
// Send response
wp_send_json_success(array('message' => 'Settings saved successfully'));
}
/**
* Optimize database.
*/
public function optimize_database() {
global $wpdb;
// Verify nonce
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'seoprostack_ajax_nonce')) {
wp_send_json_error(array('message' => 'Security check failed'));
}
// Check capabilities
if (!current_user_can('manage_options')) {
wp_send_json_error(array('message' => 'You do not have permission to optimize database'));
}
// Tables to optimize
$tables = $wpdb->get_col("SHOW TABLES LIKE '{$wpdb->prefix}%'");
$optimized = 0;
$failed = 0;
foreach ($tables as $table) {
$result = $wpdb->query("OPTIMIZE TABLE $table");
if ($result === false) {
$failed++;
} else {
$optimized++;
}
}
// Delete post revisions
$deleted_revisions = $wpdb->query("DELETE FROM $wpdb->posts WHERE post_type = 'revision'");
// Delete auto drafts
$deleted_drafts = $wpdb->query("DELETE FROM $wpdb->posts WHERE post_status = 'auto-draft'");
// Delete trashed posts
$deleted_trash = $wpdb->query("DELETE FROM $wpdb->posts WHERE post_status = 'trash'");
// Delete spam comments
$deleted_spam = $wpdb->query("DELETE FROM $wpdb->comments WHERE comment_approved = 'spam'");
// Delete trashed comments
$deleted_trash_comments = $wpdb->query("DELETE FROM $wpdb->comments WHERE comment_approved = 'trash'");
// Delete expired transients
$deleted_transients = $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_%' AND option_name NOT LIKE '_transient_timeout_%'");
// Send response
wp_send_json_success(array(
'message' => sprintf(
'Database optimization complete. %d tables optimized, %d revisions deleted, %d auto-drafts deleted, %d trash posts deleted, %d spam comments deleted, %d trash comments deleted, %d expired transients deleted.',
$optimized,
$deleted_revisions ? $deleted_revisions : 0,
$deleted_drafts ? $deleted_drafts : 0,
$deleted_trash ? $deleted_trash : 0,
$deleted_spam ? $deleted_spam : 0,
$deleted_trash_comments ? $deleted_trash_comments : 0,
$deleted_transients ? $deleted_transients : 0
)
));
}
}

View File

@ -0,0 +1,65 @@
<?php
/**
* AJAX handler for plugin-related functionality.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/AJAX
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* AJAX handler for plugins.
*/
class SEOProStack_AJAX_Plugins {
/**
* Get list of installed plugins.
*/
public function get_plugins() {
// Check nonce
if (!check_ajax_referer('seoprostack-nonce', 'nonce', false)) {
wp_send_json_error('Invalid security token sent.');
return;
}
// Check permissions
if (!current_user_can('manage_options')) {
wp_send_json_error('You do not have permission to view plugins.');
return;
}
$installed_plugins = get_plugins();
$active_plugins = get_option('active_plugins');
$plugin_list = array();
// Create the plugins array
foreach ($installed_plugins as $path => $plugin) {
// Skip the SEO Pro Stack plugin
if (strpos($path, 'wp-seoprostack-plugin') !== false) {
continue;
}
$is_active = in_array($path, $active_plugins);
$plugin_slug = explode('/', $path)[0];
$plugin_list[] = array(
'name' => $plugin['Name'],
'slug' => $plugin_slug,
'version' => $plugin['Version'],
'active' => $is_active,
'path' => $path
);
}
// Sort plugins alphabetically
usort($plugin_list, function ($a, $b) {
return strcasecmp($a['name'], $b['name']);
});
wp_send_json_success($plugin_list);
}
}

View File

@ -0,0 +1,194 @@
<?php
/**
* The Pro Plugins AJAX handler.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/AJAX
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The Pro Plugins AJAX handler.
*/
class SEOProStack_AJAX_Pro_Plugins {
/**
* Initialize the AJAX handlers.
*/
public function init() {
add_action('wp_ajax_seoprostack_get_pro_plugins', array($this, 'get_pro_plugins'));
add_action('wp_ajax_seoprostack_activate_plugin', array($this, 'activate_plugin'));
}
/**
* Get the list of pro plugins.
*/
public function get_pro_plugins() {
// Verify nonce
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'seoprostack_ajax_nonce')) {
wp_send_json_error(array('message' => 'Security check failed'));
}
// Get category filter
$category = isset($_POST['category']) ? sanitize_text_field($_POST['category']) : 'all';
// Plugin data
$plugins = $this->get_plugin_data($category);
// Send response
wp_send_json_success(array('plugins' => $plugins));
}
/**
* Activate a plugin.
*/
public function activate_plugin() {
// Verify nonce
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'seoprostack_ajax_nonce')) {
wp_send_json_error(array('message' => 'Security check failed'));
}
// Check capabilities
if (!current_user_can('activate_plugins')) {
wp_send_json_error(array('message' => 'You do not have permission to activate plugins'));
}
// Get plugin path
if (!isset($_POST['plugin'])) {
wp_send_json_error(array('message' => 'No plugin specified'));
}
$plugin = sanitize_text_field($_POST['plugin']);
// Activate the plugin
$result = activate_plugin($plugin);
if (is_wp_error($result)) {
wp_send_json_error(array('message' => $result->get_error_message()));
} else {
wp_send_json_success(array('message' => 'Plugin activated successfully'));
}
}
/**
* Get the plugin data based on category.
*
* @param string $category The plugin category.
* @return array The plugin data.
*/
private function get_plugin_data($category) {
$plugins = array(
array(
'name' => 'Rank Math SEO',
'version' => '1.0.123',
'description' => 'The most advanced SEO plugin for WordPress that helps you optimize your website for search engines.',
'url' => 'https://rankmath.com/',
'status' => 'not-installed',
'active' => false,
'path' => 'rank-math-seo/rank-math.php',
'category' => 'seo'
),
array(
'name' => 'WP Rocket',
'version' => '3.14.4',
'description' => 'The best WordPress caching plugin to speed up your website in a few clicks.',
'url' => 'https://wp-rocket.me/',
'status' => 'not-installed',
'active' => false,
'path' => 'wp-rocket/wp-rocket.php',
'category' => 'performance'
),
array(
'name' => 'MonsterInsights',
'version' => '8.14.0',
'description' => 'The best Google Analytics plugin for WordPress that connects your website with Google Analytics.',
'url' => 'https://www.monsterinsights.com/',
'status' => 'not-installed',
'active' => false,
'path' => 'google-analytics-for-wordpress/googleanalytics.php',
'category' => 'analytics'
),
array(
'name' => 'Yoast SEO',
'version' => '21.2',
'description' => 'The first true all-in-one SEO solution for WordPress, including on-page content analysis, XML sitemaps and much more.',
'url' => 'https://yoast.com/wordpress/plugins/seo/',
'status' => 'not-installed',
'active' => false,
'path' => 'wordpress-seo/wp-seo.php',
'category' => 'seo'
),
array(
'name' => 'WP Cloudflare Super Page Cache',
'version' => '4.7.0',
'description' => 'Speed up your website by implementing full page caching using Cloudflare.',
'url' => 'https://wordpress.org/plugins/wp-cloudflare-page-cache/',
'status' => 'not-installed',
'active' => false,
'path' => 'wp-cloudflare-page-cache/wp-cloudflare-super-page-cache.php',
'category' => 'performance'
),
array(
'name' => 'ExactMetrics',
'version' => '7.14.1',
'description' => 'Google Analytics Dashboard for WordPress. See how visitors find and use your website.',
'url' => 'https://www.exactmetrics.com/',
'status' => 'not-installed',
'active' => false,
'path' => 'google-analytics-dashboard-for-wp/gadwp.php',
'category' => 'analytics'
),
array(
'name' => 'SEOPress',
'version' => '7.2.2',
'description' => 'Boost your SEO with SEOPress, a simple, fast and powerful WordPress SEO plugin.',
'url' => 'https://www.seopress.org/',
'status' => 'not-installed',
'active' => false,
'path' => 'wp-seopress/seopress.php',
'category' => 'seo'
),
array(
'name' => 'WP-Optimize',
'version' => '3.2.19',
'description' => 'A comprehensive plugin with database clean-up, image compression and page caching features.',
'url' => 'https://getwpo.com/',
'status' => 'not-installed',
'active' => false,
'path' => 'wp-optimize/wp-optimize.php',
'category' => 'performance'
),
array(
'name' => 'Fathom Analytics',
'version' => '3.2.1',
'description' => 'Simple, privacy-focused website analytics that doesn\'t compromise visitor privacy.',
'url' => 'https://usefathom.com/',
'status' => 'not-installed',
'active' => false,
'path' => 'fathom-analytics-wordpress-plugin/fathom-analytics.php',
'category' => 'analytics'
)
);
// Update plugin status (check if installed and active)
foreach ($plugins as $key => $plugin) {
if (file_exists(WP_PLUGIN_DIR . '/' . $plugin['path'])) {
$plugins[$key]['status'] = 'installed';
$plugins[$key]['active'] = is_plugin_active($plugin['path']);
}
}
// Filter by category if needed
if ($category !== 'all') {
$plugins = array_filter($plugins, function($plugin) use ($category) {
return $plugin['category'] === $category;
});
}
return array_values($plugins);
}
}

View File

@ -0,0 +1,119 @@
<?php
/**
* AJAX handler for settings functionality.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/AJAX
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* AJAX handler for settings.
*/
class SEOProStack_AJAX_Settings {
/**
* Initialize the class
*/
public function __construct() {
add_action('wp_ajax_seoprostack_update_option', array($this, 'update_option'));
add_action('wp_ajax_seoprostack_get_options', array($this, 'get_options'));
}
/**
* Update a plugin option via AJAX.
*/
public function update_option() {
// Check nonce
if (!check_ajax_referer('seoprostack-nonce', 'nonce', false)) {
wp_send_json_error(array(
'message' => 'Invalid security token sent.'
));
return;
}
// Check permissions
if (!current_user_can('manage_options')) {
wp_send_json_error(array(
'message' => 'You do not have permission to update settings.'
));
return;
}
// Get option data
$option_group = isset($_POST['option_group']) ? sanitize_text_field($_POST['option_group']) : '';
$option_name = isset($_POST['option_name']) ? sanitize_text_field($_POST['option_name']) : '';
$option_value = isset($_POST['option_value']) ? sanitize_text_field($_POST['option_value']) : '';
if (empty($option_group) || empty($option_name)) {
wp_send_json_error(array(
'message' => 'Missing required parameters.'
));
return;
}
// Get current option values
$options = get_option($option_group, array());
// Update value
$options[$option_name] = $option_value;
// Save updated options
$result = update_option($option_group, $options);
if ($result) {
wp_send_json_success(array(
'message' => 'Option updated successfully',
'option_group' => $option_group,
'option_name' => $option_name,
'option_value' => $option_value
));
} else {
wp_send_json_error(array(
'message' => 'Failed to update option or no changes were made.'
));
}
}
/**
* Get plugin options via AJAX.
*/
public function get_options() {
// Check nonce
if (!check_ajax_referer('seoprostack-nonce', 'nonce', false)) {
wp_send_json_error(array(
'message' => 'Invalid security token sent.'
));
return;
}
// Check permissions
if (!current_user_can('manage_options')) {
wp_send_json_error(array(
'message' => 'You do not have permission to retrieve settings.'
));
return;
}
// Get option group
$option_group = isset($_POST['option_group']) ? sanitize_text_field($_POST['option_group']) : '';
if (empty($option_group)) {
wp_send_json_error(array(
'message' => 'Missing required parameters.'
));
return;
}
// Get options
$options = get_option($option_group, array());
wp_send_json_success(array(
'options' => $options
));
}
}

View File

@ -0,0 +1,93 @@
<?php
/**
* AJAX handler for theme-related functionality.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/AJAX
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* AJAX handler for themes.
*/
class SEOProStack_AJAX_Themes {
/**
* Get list of available themes.
*/
public function get_themes() {
// Check nonce
if (!check_ajax_referer('seoprostack-nonce', 'nonce', false)) {
wp_send_json_error('Invalid security token sent.');
return;
}
// Check permissions
if (!current_user_can('manage_options')) {
wp_send_json_error('You do not have permission to view themes.');
return;
}
$themes = wp_get_themes();
$current_theme = wp_get_theme();
$theme_list = array();
foreach ($themes as $theme_slug => $theme_obj) {
$theme_list[] = array(
'name' => $theme_obj->get('Name'),
'version' => $theme_obj->get('Version'),
'description' => $theme_obj->get('Description'),
'author' => $theme_obj->get('Author'),
'slug' => $theme_slug,
'active' => ($current_theme->get_stylesheet() === $theme_slug),
'screenshot' => $theme_obj->get_screenshot(),
);
}
// Sort themes - active first, then alphabetically
usort($theme_list, function ($a, $b) {
if ($a['active'] && !$b['active']) return -1;
if (!$a['active'] && $b['active']) return 1;
return strcasecmp($a['name'], $b['name']);
});
wp_send_json_success($theme_list);
}
/**
* Activate a theme.
*/
public function activate_theme() {
// Check nonce
if (!check_ajax_referer('seoprostack-nonce', 'nonce', false)) {
wp_send_json_error('Invalid security token sent.');
return;
}
// Check permissions
if (!current_user_can('switch_themes')) {
wp_send_json_error('You do not have permission to switch themes.');
return;
}
$theme_slug = sanitize_text_field($_POST['theme']);
// Check if theme exists
$themes = wp_get_themes();
if (!isset($themes[$theme_slug])) {
wp_send_json_error('Theme does not exist.');
return;
}
// Activate theme
switch_theme($theme_slug);
wp_send_json_success(array(
'message' => sprintf('Theme "%s" has been activated.', $themes[$theme_slug]->get('Name')),
));
}
}

View File

@ -0,0 +1,77 @@
<?php
/**
* The Tools AJAX handler.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/AJAX
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The Tools AJAX handler.
*/
class SEOProStack_AJAX_Tools {
/**
* Initialize the AJAX handlers.
*/
public function init() {
add_action('wp_ajax_seoprostack_generate_robots', array($this, 'generate_robots'));
}
/**
* Generate robots.txt file content.
*/
public function generate_robots() {
// Verify nonce
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'seoprostack_ajax_nonce')) {
wp_send_json_error(array('message' => 'Security check failed'));
}
// Check capabilities
if (!current_user_can('manage_options')) {
wp_send_json_error(array('message' => 'You do not have permission to generate robots.txt'));
}
// Generate robots.txt content
$site_url = get_home_url();
$parsed_url = parse_url($site_url);
$host = $parsed_url['host'];
$content = "# SEO Pro Stack generated robots.txt\n";
$content .= "# Generated on: " . date('Y-m-d H:i:s') . "\n\n";
$content .= "User-agent: *\n";
// Disallow WordPress admin
$content .= "Disallow: /wp-admin/\n";
// Allow assets and ajax
$content .= "Allow: /wp-admin/admin-ajax.php\n";
$content .= "Allow: /wp-includes/*.js\n";
$content .= "Allow: /wp-includes/*.css\n";
$content .= "Allow: /wp-content/uploads/\n";
// Disallow common WordPress files and directories
$content .= "Disallow: /wp-includes/\n";
$content .= "Disallow: /readme.html\n";
$content .= "Disallow: /license.txt\n";
$content .= "Disallow: /xmlrpc.php\n";
$content .= "Disallow: /wp-json/\n";
// Add sitemap if Yoast SEO or other SEO plugin is active
if (function_exists('wpseo_init') || defined('AIOSEO_VERSION') || defined('RANK_MATH_VERSION')) {
$content .= "\n# XML Sitemap\n";
$content .= "Sitemap: " . trailingslashit($site_url) . "sitemap_index.xml\n";
}
// Send response
wp_send_json_success(array(
'message' => 'Robots.txt content generated successfully.',
'content' => $content
));
}
}

View File

@ -0,0 +1,193 @@
<?php
/**
* The admin settings page class.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The admin settings page class.
*/
class SEOProStack_Settings_Page {
/**
* Register the settings page.
*/
public function add_menu_page() {
add_options_page(
'SEO Pro Stack Settings', // Page title
'SEO Pro Stack', // Menu title
'manage_options', // Capability
'seoprostack', // Menu slug
array($this, 'render_settings_page') // Function to display the page
);
}
/**
* Register settings.
*/
public function register_settings() {
register_setting('seoprostack_settings', 'seoprostack_workflow_options');
register_setting('seoprostack_settings', 'seoprostack_advanced_options');
}
/**
* Render the settings page.
*/
public function render_settings_page() {
$active_tab = isset($_GET['tab']) ? sanitize_key($_GET['tab']) : 'general';
$tabs = $this->get_tabs();
?>
<div class="wrap seoprostack-wrap">
<div class="seoprostack-header">
<h1><?php echo esc_html('SEO Pro Stack'); ?></h1>
<p class="seoprostack-description"><?php echo esc_html('Speed up your WordPress site with our optimization tools.'); ?></p>
</div>
<div class="seoprostack-settings-container">
<div class="seoprostack-nav">
<h2 class="nav-tab-wrapper">
<?php foreach ($tabs as $tab_id => $tab) : ?>
<a href="?page=seoprostack&tab=<?php echo esc_attr($tab_id); ?>"
class="nav-tab <?php echo $active_tab === $tab_id ? 'nav-tab-active' : ''; ?>">
<?php echo esc_html($tab['label']); ?>
</a>
<?php endforeach; ?>
</h2>
</div>
<div class="seoprostack-settings-content">
<?php
if (isset($tabs[$active_tab]) && isset($tabs[$active_tab]['callback'])) {
call_user_func($tabs[$active_tab]['callback']);
}
?>
</div>
</div>
</div>
<?php
}
/**
* Get all available tabs.
*
* @return array Array of tab configurations.
*/
private function get_tabs() {
$tabs = array(
'general' => array(
'label' => __('General', 'seoprostack'),
'callback' => array($this, 'render_general_tab'),
),
'advanced' => array(
'label' => __('Advanced', 'seoprostack'),
'callback' => array($this, 'render_advanced_tab'),
),
'workflow' => array(
'label' => __('Workflow', 'seoprostack'),
'callback' => array($this, 'render_workflow_tab'),
),
'recommended' => array(
'label' => __('Free Plugins', 'seoprostack'),
'callback' => array($this, 'render_recommended_plugins_tab'),
),
'pro' => array(
'label' => __('Pro Plugins', 'seoprostack'),
'callback' => array($this, 'render_pro_plugins_tab'),
),
'theme' => array(
'label' => __('Theme', 'seoprostack'),
'callback' => array($this, 'render_theme_tab'),
),
'hosting' => array(
'label' => __('Hosting', 'seoprostack'),
'callback' => array($this, 'render_hosting_tab'),
),
'tools' => array(
'label' => __('Tools', 'seoprostack'),
'callback' => array($this, 'render_tools_tab'),
),
);
return $tabs;
}
/**
* Render the General tab.
*/
public function render_general_tab() {
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings/tabs/class-seoprostack-tab-general.php';
$tab = new SEOProStack_Tab_General();
$tab->render();
}
/**
* Render the Advanced tab.
*/
public function render_advanced_tab() {
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings/tabs/class-seoprostack-tab-advanced.php';
$tab = new SEOProStack_Tab_Advanced();
$tab->render();
}
/**
* Render the Workflow tab.
*/
public function render_workflow_tab() {
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings/tabs/class-seoprostack-tab-workflow.php';
$tab = new SEOProStack_Tab_Workflow();
$tab->render();
}
/**
* Render the Recommended Plugins tab.
*/
public function render_recommended_plugins_tab() {
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings/tabs/class-seoprostack-tab-recommended-plugins.php';
$tab = new SEOProStack_Tab_Recommended_Plugins();
$tab->render();
}
/**
* Render the Pro Plugins tab.
*/
public function render_pro_plugins_tab() {
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings/tabs/class-seoprostack-tab-pro-plugins.php';
$tab = new SEOProStack_Tab_Pro_Plugins();
$tab->render();
}
/**
* Render the Theme tab.
*/
public function render_theme_tab() {
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings/tabs/class-seoprostack-tab-theme.php';
$tab = new SEOProStack_Tab_Theme();
$tab->render();
}
/**
* Render the Hosting tab.
*/
public function render_hosting_tab() {
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings/tabs/class-seoprostack-tab-hosting.php';
$tab = new SEOProStack_Tab_Hosting();
$tab->render();
}
/**
* Render the Tools tab.
*/
public function render_tools_tab() {
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings/tabs/class-seoprostack-tab-tools.php';
$tab = new SEOProStack_Tab_Tools();
$tab->render();
}
}

View File

@ -0,0 +1,229 @@
<?php
/**
* Hosting providers data for SEO Pro Stack
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/Data
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* Define hosting providers
*
* @return array Array of hosting providers with their details
*/
function wp_seoprostack_get_hosting_providers() {
return array(
'closte' => array(
'name' => 'Closte',
'description' => 'Managed WordPress hosting with advanced performance optimization and auto-scaling.',
'features' => array(
'Auto-scaling architecture',
'Global CDN included',
'Advanced caching',
'Free SSL certificates'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://closte.com/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://closte.com/pricing'
)
)
),
'cloudron' => array(
'name' => 'Cloudron',
'description' => 'Self-hosted platform that makes it easy to run web applications like WordPress on your server.',
'features' => array(
'One-click installation',
'Automatic updates',
'Built-in backups',
'SSL certificate management'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.cloudron.io/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.cloudron.io/pricing.html'
)
)
),
'hostinger' => array(
'name' => 'Hostinger',
'description' => 'Affordable WordPress hosting with good performance and user-friendly management tools.',
'features' => array(
'Free domain name',
'Managed WordPress features',
'LiteSpeed cache',
'Weekly backups'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.hostinger.com/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.hostinger.com/wordpress-hosting'
)
)
),
'hetzner' => array(
'name' => 'Hetzner Cloud',
'description' => 'High-performance cloud servers with excellent price-to-performance ratio for self-managed WordPress hosting.',
'features' => array(
'Scalable cloud instances',
'Per-minute billing',
'Snapshots and backups',
'Global data centers'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.hetzner.com/cloud/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.hetzner.com/cloud#pricing'
)
)
),
'simplehost' => array(
'name' => 'SimpleHost',
'description' => 'Streamlined WordPress hosting with a focus on simplicity and performance.',
'features' => array(
'Simplified hosting dashboard',
'Pre-optimized WordPress',
'Automated backups',
'Email hosting included'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://simplehost.so/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://simplehost.so/#pricing'
)
)
),
'cloudflare' => array(
'name' => 'Cloudflare',
'description' => 'Global cloud platform that provides CDN, security, and performance optimization services.',
'features' => array(
'Global CDN network',
'DDoS protection',
'Web application firewall',
'Performance optimization'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.cloudflare.com/en-gb/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.cloudflare.com/en-gb/plans/'
)
)
),
'spaceship' => array(
'name' => 'Spaceship',
'description' => 'Modern hosting platform with advanced features for WordPress sites.',
'features' => array(
'Advanced WordPress tools',
'Optimized for speed',
'Developer-friendly features',
'Smart caching system'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.spaceship.com/',
'primary' => true
)
)
),
'101domain' => array(
'name' => '101Domain',
'description' => 'Domain registration and management service with support for hundreds of TLDs.',
'features' => array(
'Extensive TLD selection',
'Domain privacy protection',
'Expert domain support',
'Bulk domain management'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.101domain.com/',
'primary' => true
)
)
),
'namecheap' => array(
'name' => 'Namecheap',
'description' => 'Domain registrar and web hosting provider with competitive pricing and good support.',
'features' => array(
'Free WhoisGuard protection',
'Competitive domain pricing',
'Reliable hosting services',
'Excellent support'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.namecheap.com/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.namecheap.com/hosting/shared/'
)
)
),
'updownio' => array(
'name' => 'Updown.io',
'description' => 'Simple and affordable website monitoring service with uptime checks and performance metrics.',
'features' => array(
'Real-time monitoring',
'Performance metrics',
'Notification alerts',
'Detailed reports'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://updown.io/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://updown.io/pricing'
)
)
)
);
}
// Alias for backward compatibility with the old codebase
function wp_allstars_get_hosting_providers() {
return wp_seoprostack_get_hosting_providers();
}

View File

@ -0,0 +1,183 @@
<?php
/**
* Recommended plugins data for SEO Pro Stack
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/Data
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* Define recommended plugins
*
* @return array Array of recommended plugins categorized by use case
*/
function wp_seoprostack_get_recommended_plugins() {
return array(
'minimal' => array(
'antispam-bee',
'compressx',
'fluent-smtp',
'kadence-blocks',
'simple-cloudflare-turnstile'
),
'admin' => array(
'admin-bar-dashboard-control',
'codepress-admin-columns',
'admin-menu-editor',
'hide-admin-notices',
'mainwp-child',
'mainwp-child-reports',
'magic-login',
'manage-notification-emails',
'plugin-groups',
'plugin-toggle'
),
'affiliates' => array(
'pretty-links',
'simple-urls',
'slicewp'
),
'ai' => array(
'ai-engine',
),
'cms' => array(
'auto-post-scheduler',
'block-options',
'bookmark-card',
'browser-shots',
'bulk-actions-select-all',
'bulk-edit-categories-tags',
'bulk-edit-user-profiles-in-spreadsheet',
'carbon-copy',
'code-block-pro',
'iframe-block',
'ics-calendar',
'mammoth-docx-converter',
'nav-menu-roles',
'ninja-tables',
'post-draft-preview',
'post-type-switcher',
'simple-custom-post-order',
'simple-icons',
'sticky-posts-switch',
'term-management-tools',
'the-paste',
'ultimate-addons-for-gutenberg',
'wikipedia-preview',
'wp-sheet-editor-bulk-spreadsheet-editor-for-posts-and-pages'
),
'compliance' => array(
'avatar-privacy',
'complianz-gdpr',
'complianz-terms-conditions',
'really-simple-ssl'
),
'crm' => array(
'fluent-boards',
'fluent-booking',
'fluent-community',
'fluent-crm',
'fluentform',
'fluentforms-pdf',
'fluentform-block',
'fluent-support'
),
'ecommerce' => array(
'woocommerce',
'woo-bulk-edit-products',
'woo-coupons-bulk-editor',
'woocommerce-gateway-gocardless',
'kadence-woocommerce-email-designer',
'pymntpl-paypal-woocommerce',
'woo-stripe-payment'
),
'lms' => array(
'fluent-community',
'masterstudy-lms-learning-management-system',
'tutor'
),
'media' => array(
'easy-watermark',
'enable-media-replace',
'image-copytrack',
'imsanity',
'media-file-renamer',
'safe-svg'
),
'seo' => array(
'burst-statistics',
'pretty-link',
'revive-so',
'seo-by-rank-math',
'syndication-links',
'ultimate-410',
'webmention'
),
'setup' => array(
'kadence-starter-templates',
'wordpress-importer'
),
'social' => array(
'bit-social',
'easy-video-reviews',
'social-engine',
'wp-social-ninja',
'wp-social-reviews'
),
'speed' => array(
'disable-wordpress-updates',
'flying-analytics',
'flying-pages',
'flying-scripts',
'freesoul-deactivate-plugins',
'index-wp-mysql-for-speed',
'litespeed-cache',
'performant-translations',
'wp-optimize',
'wp-widget-disable'
),
'translation' => array(
'hreflang-manager-lite',
'performant-translations',
'translatepress-multilingual'
),
'advanced' => array(
'acf-better-search',
'advanced-custom-fields',
'automatorwp',
'bit-pi',
'bit-integrations',
'code-snippets',
'easy-code-manager',
'favorites',
'remove-cpt-base',
'remove-old-slugspermalinks',
'secure-custom-fields',
'yellow-pencil-visual-theme-customizer'
),
'debug' => array(
'advanced-database-cleaner',
'debug-log-manager',
'gotmls',
'query-monitor',
'string-locator',
'user-switching',
'wp-crontrol'
)
);
}
// Alias for backward compatibility with the old codebase
function wp_allstars_get_recommended_plugins() {
return wp_seoprostack_get_recommended_plugins();
}
// Alias for backward compatibility with the new codebase
function seoprostack_get_recommended_plugins() {
return wp_seoprostack_get_recommended_plugins();
}

View File

@ -0,0 +1,373 @@
<?php
/**
* Tools data for SEO Pro Stack
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/Data
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* Define tools
*
* @return array Array of tools with their details
*/
function wp_seoprostack_get_tools() {
return array(
'advise' => array(
'name' => 'Advise.so',
'description' => 'Website analytics and optimization tool for improving user experience and conversion rates.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://advise.so/',
'primary' => true
)
)
),
'seoutils' => array(
'name' => 'SEO Utils',
'description' => 'Collection of SEO tools to analyze and improve website search engine optimization.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://seoutils.app/',
'primary' => true
)
)
),
'dataforseo' => array(
'name' => 'DataForSEO',
'description' => 'API-based SEO data provider for rank tracking, keyword research and competitive analysis.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://dataforseo.com/',
'primary' => true
)
)
),
'ahrefs' => array(
'name' => 'Ahrefs',
'description' => 'Comprehensive SEO toolset for backlink analysis, keyword research, and competitor research.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://ahrefs.com/',
'primary' => true
)
)
),
'localrank' => array(
'name' => 'LocalRank.so',
'description' => 'Local SEO tool for tracking and improving local search rankings for businesses.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://localrank.so/',
'primary' => true
)
)
),
'turnithuman' => array(
'name' => 'Turn It Human',
'description' => 'AI content humanizer that makes AI-generated content sound more natural and authentic.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://turnithuman.com/',
'primary' => true
)
)
),
'searchconsole' => array(
'name' => 'Google Search Console',
'description' => 'Free tool from Google to monitor and troubleshoot your site\'s presence in Google Search results.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://search.google.com/search-console/about',
'primary' => true
)
)
),
'bingwebmaster' => array(
'name' => 'Bing Webmaster Tools',
'description' => 'Free tool from Microsoft to help optimize your website for Bing search engine.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.bing.com/webmasters/about',
'primary' => true
)
)
),
'fiverr' => array(
'name' => 'Fiverr',
'description' => 'Freelance services marketplace for businesses to find digital services including web development.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.fiverr.com/',
'primary' => true
)
)
),
'legiit' => array(
'name' => 'Legiit',
'description' => 'Marketplace for digital marketing services including SEO, content writing, and web design.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://legiit.com/',
'primary' => true
)
)
),
'openwebui' => array(
'name' => 'Open WebUI',
'description' => 'Open-source web interface for interacting with AI models and chatbots.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://openwebui.com/',
'primary' => true
)
)
),
'nextcloud' => array(
'name' => 'Nextcloud',
'description' => 'Self-hosted productivity platform and file sync solution for secure collaboration.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://nextcloud.com/',
'primary' => true
)
)
),
'enpass' => array(
'name' => 'Enpass',
'description' => 'Password manager that stores sensitive information locally on your device.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.enpass.io/',
'primary' => true
)
)
),
'pdfstudio' => array(
'name' => 'PDF Studio',
'description' => 'Professional PDF editor with advanced features for creating and modifying PDF documents.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.qoppa.com/pdfstudio/',
'primary' => true
)
)
),
'affinity' => array(
'name' => 'Affinity',
'description' => 'Professional creative software suite including Photo, Designer, and Publisher applications.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://affinity.serif.com/',
'primary' => true
)
)
),
'urlmonitor' => array(
'name' => 'URL Monitor',
'description' => 'Website monitoring service that tracks uptime, performance, and alerts you to issues.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://urlmonitor.com/',
'primary' => true
)
)
),
'speedyindex' => array(
'name' => 'Speedy Index',
'description' => 'Tool for monitoring website indexing speed and performance in search engines.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://en.speedyindex.com/',
'primary' => true
)
)
),
'pagespeed' => array(
'name' => 'PageSpeed Insights',
'description' => 'Google tool that analyzes web page performance on mobile and desktop devices.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://pagespeed.web.dev/',
'primary' => true
)
)
),
'windsurf' => array(
'name' => 'Codeium Windsurf',
'description' => 'AI-powered IDE with advanced code completion and generation capabilities.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://codeium.com/windsurf',
'primary' => true
)
)
),
'lowfruits' => array(
'name' => 'Low Fruits',
'description' => 'SEO tool for finding low-competition keywords to target for faster ranking.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://lowfruits.io/',
'primary' => true
)
)
),
'keysearch' => array(
'name' => 'Keysearch',
'description' => 'Affordable keyword research tool for finding valuable keywords for SEO.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.keysearch.co/',
'primary' => true
)
)
),
'smartlead' => array(
'name' => 'SmartLead',
'description' => 'Email outreach platform for cold email campaigns and lead generation.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.smartlead.ai/',
'primary' => true
)
)
),
'zerogptplus' => array(
'name' => 'ZeroGPT Plus',
'description' => 'Advanced AI content detector with improved accuracy and additional features.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.zerogpt.plus/en',
'primary' => true
)
)
),
'neuronwriter' => array(
'name' => 'NeuronWriter',
'description' => 'AI-powered SEO content optimization tool for creating high-ranking content.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.neuronwriter.com/',
'primary' => true
)
)
),
'serposcope' => array(
'name' => 'Serposcope',
'description' => 'Open-source rank tracker to monitor website positions in search engines.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.serposcope.com/en/',
'primary' => true
)
)
),
'seoptimer' => array(
'name' => 'SEOptimer',
'description' => 'Website audit tool that provides SEO, usability, and performance recommendations.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.seoptimer.com/',
'primary' => true
)
)
),
'jitsi' => array(
'name' => 'Jitsi Meet',
'description' => 'Free, open-source video conferencing platform with no account required.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://meet.jit.si/',
'primary' => true
)
)
),
'libreoffice' => array(
'name' => 'LibreOffice',
'description' => 'Free and open-source office suite compatible with Microsoft Office formats.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.libreoffice.org/',
'primary' => true
)
)
),
'localwp' => array(
'name' => 'Local',
'description' => 'Local WordPress development tool for creating WordPress sites locally.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://localwp.com/',
'primary' => true
)
)
),
'notability' => array(
'name' => 'Notability',
'description' => 'Note-taking app for iPad and Mac with handwriting and PDF annotation features.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://notability.com/',
'primary' => true
)
)
),
'ulysses' => array(
'name' => 'Ulysses',
'description' => 'Writing app for Mac, iPad, and iPhone with a clean interface and powerful features.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://ulysses.app/',
'primary' => true
)
)
),
);
}
// Alias for backward compatibility with the old codebase
function wp_allstars_get_tools() {
return wp_seoprostack_get_tools();
}
// Alias for backward compatibility with the new codebase
function seoprostack_get_tools() {
return wp_seoprostack_get_tools();
}

View File

@ -0,0 +1,159 @@
<?php
/**
* The Advanced tab for plugin settings.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/Tabs
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The Advanced tab for plugin settings.
*/
class SEOProStack_Tab_Advanced {
/**
* Render the tab content.
*/
public function render() {
// Get current settings
$settings = get_option('seoprostack_advanced_settings', array(
'disable_emojis' => 'yes',
'disable_embeds' => 'yes',
'remove_query_strings' => 'no',
'disable_xmlrpc' => 'yes',
'remove_shortlink' => 'yes',
'remove_rsd_link' => 'yes',
'remove_wlwmanifest_link' => 'yes',
'disable_self_pingbacks' => 'yes',
'disable_feed_links' => 'no',
'remove_rest_api_links' => 'no',
'minify_html' => 'no',
'minify_css' => 'no',
'minify_js' => 'no'
));
?>
<div class="seoprostack-settings-content tab-content" id="advanced">
<div class="seoprostack-setting-section">
<h2><?php esc_html_e('Advanced Settings', 'seoprostack'); ?></h2>
<p class="description"><?php esc_html_e('These settings help optimize your WordPress site for better performance. Use with caution and test thoroughly after making changes.', 'seoprostack'); ?></p>
<div id="advanced-settings-response"></div>
<form id="seoprostack-advanced-settings-form">
<div class="seoprostack-toggle">
<div class="seoprostack-toggle-header">
<div class="seoprostack-toggle-main">
<div class="seoprostack-toggle-left">
<h3><?php esc_html_e('WordPress Cleanup', 'seoprostack'); ?></h3>
<p><?php esc_html_e('Remove unnecessary code from WordPress header', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-toggle-right">
<label class="wp-toggle-switch">
<input type="checkbox" class="seoprostack-toggle-switch" <?php checked(true, true); ?>>
<span class="toggle-label"></span>
</label>
</div>
</div>
</div>
<div class="seoprostack-toggle-settings" style="display: block;">
<div class="seoprostack-setting-row">
<label class="seoprostack-checkbox-label">
<input type="checkbox" name="disable_emojis" value="yes" <?php checked('yes', $settings['disable_emojis']); ?>>
<?php esc_html_e('Disable WordPress Emojis', 'seoprostack'); ?>
</label>
<p class="description"><?php esc_html_e('Removes the WordPress emoji script and related code from loading on your site.', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-setting-row">
<label class="seoprostack-checkbox-label">
<input type="checkbox" name="disable_embeds" value="yes" <?php checked('yes', $settings['disable_embeds']); ?>>
<?php esc_html_e('Disable WordPress Embeds', 'seoprostack'); ?>
</label>
<p class="description"><?php esc_html_e('Disables the WordPress embed functionality, removing the related JavaScript file.', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-setting-row">
<label class="seoprostack-checkbox-label">
<input type="checkbox" name="remove_query_strings" value="yes" <?php checked('yes', $settings['remove_query_strings']); ?>>
<?php esc_html_e('Remove Query Strings from Static Resources', 'seoprostack'); ?>
</label>
<p class="description"><?php esc_html_e('Removes query strings from static resources like CSS and JavaScript files, improving caching.', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-setting-row">
<label class="seoprostack-checkbox-label">
<input type="checkbox" name="disable_xmlrpc" value="yes" <?php checked('yes', $settings['disable_xmlrpc']); ?>>
<?php esc_html_e('Disable XML-RPC', 'seoprostack'); ?>
</label>
<p class="description"><?php esc_html_e('Disables the XML-RPC API, which could be a security vulnerability if not used.', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-setting-row">
<label class="seoprostack-checkbox-label">
<input type="checkbox" name="remove_shortlink" value="yes" <?php checked('yes', $settings['remove_shortlink']); ?>>
<?php esc_html_e('Remove Shortlink', 'seoprostack'); ?>
</label>
<p class="description"><?php esc_html_e('Removes the shortlink tag from the header.', 'seoprostack'); ?></p>
</div>
</div>
</div>
<div class="seoprostack-toggle">
<div class="seoprostack-toggle-header">
<div class="seoprostack-toggle-main">
<div class="seoprostack-toggle-left">
<h3><?php esc_html_e('Performance Optimization', 'seoprostack'); ?></h3>
<p><?php esc_html_e('Enable additional performance optimizations', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-toggle-right">
<label class="wp-toggle-switch">
<input type="checkbox" class="seoprostack-toggle-switch" <?php checked(true, true); ?>>
<span class="toggle-label"></span>
</label>
</div>
</div>
</div>
<div class="seoprostack-toggle-settings" style="display: block;">
<div class="seoprostack-setting-row">
<label class="seoprostack-checkbox-label">
<input type="checkbox" name="minify_html" value="yes" <?php checked('yes', $settings['minify_html']); ?>>
<?php esc_html_e('Minify HTML', 'seoprostack'); ?>
</label>
<p class="description"><?php esc_html_e('Removes unnecessary whitespace from HTML to reduce file size.', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-setting-row">
<label class="seoprostack-checkbox-label">
<input type="checkbox" name="minify_css" value="yes" <?php checked('yes', $settings['minify_css']); ?>>
<?php esc_html_e('Minify CSS', 'seoprostack'); ?>
</label>
<p class="description"><?php esc_html_e('Combines and minifies CSS files to reduce HTTP requests and file size.', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-setting-row">
<label class="seoprostack-checkbox-label">
<input type="checkbox" name="minify_js" value="yes" <?php checked('yes', $settings['minify_js']); ?>>
<?php esc_html_e('Minify JavaScript', 'seoprostack'); ?>
</label>
<p class="description"><?php esc_html_e('Combines and minifies JavaScript files to reduce HTTP requests and file size.', 'seoprostack'); ?></p>
</div>
</div>
</div>
<div class="seoprostack-setting-actions">
<button type="submit" class="button button-primary" id="seoprostack-save-advanced-settings">
<?php esc_html_e('Save Advanced Settings', 'seoprostack'); ?>
</button>
<span class="spinner"></span>
</div>
</form>
</div>
</div>
<?php
}
}

View File

@ -0,0 +1,62 @@
<?php
/**
* The General tab for plugin settings.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/Tabs
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The General tab for plugin settings.
*/
class SEOProStack_Tab_General {
/**
* Render the tab content.
*/
public function render() {
?>
<div class="seoprostack-settings-content tab-content" id="general">
<div class="seoprostack-settings-section">
<h2><?php esc_html_e('Welcome to SEO Pro Stack', 'seoprostack'); ?></h2>
<p><?php esc_html_e('SEO Pro Stack helps you optimize your WordPress site for better search engine rankings and faster performance.', 'seoprostack'); ?></p>
<div class="seoprostack-welcome-cards">
<div class="seoprostack-card">
<div class="seoprostack-card-icon dashicons dashicons-performance"></div>
<h3><?php esc_html_e('Optimize Performance', 'seoprostack'); ?></h3>
<p><?php esc_html_e('Speed up your site with our performance optimization tools.', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-card">
<div class="seoprostack-card-icon dashicons dashicons-admin-plugins"></div>
<h3><?php esc_html_e('Recommended Plugins', 'seoprostack'); ?></h3>
<p><?php esc_html_e('Discover plugins that enhance your site\'s SEO and performance.', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-card">
<div class="seoprostack-card-icon dashicons dashicons-admin-appearance"></div>
<h3><?php esc_html_e('Theme Optimization', 'seoprostack'); ?></h3>
<p><?php esc_html_e('Find and activate SEO-friendly themes for your site.', 'seoprostack'); ?></p>
</div>
</div>
<div class="seoprostack-quick-start">
<h3><?php esc_html_e('Quick Start Guide', 'seoprostack'); ?></h3>
<ol>
<li><?php esc_html_e('Configure auto-upload settings in the Workflow tab', 'seoprostack'); ?></li>
<li><?php esc_html_e('Explore recommended plugins in the Free Plugins tab', 'seoprostack'); ?></li>
<li><?php esc_html_e('Check out premium plugins in the Pro Plugins tab', 'seoprostack'); ?></li>
<li><?php esc_html_e('Find an SEO-optimized theme in the Theme tab', 'seoprostack'); ?></li>
</ol>
</div>
</div>
</div>
<?php
}
}

View File

@ -0,0 +1,692 @@
<?php
/**
* The Hosting tab for plugin settings.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/Tabs
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The Hosting tab for plugin settings.
* Self-contained class with integrated data and functionality
*/
class SEOProStack_Tab_Hosting {
/**
* Tab identifier
*
* @var string
*/
private $tab_id = 'hosting';
/**
* Initialize the class.
* Register any hooks or actions here.
*/
/**
* Hosting providers data
*
* @var array
*/
private $hosting_providers;
/**
* Server information
*
* @var array
*/
private $server_info;
public function __construct() {
// Initialize the hosting providers data
$this->hosting_providers = $this->get_hosting_providers();
$this->server_info = $this->get_server_info();
}
/**
* Get the tab ID
*
* @return string The tab ID
*/
public function get_tab_id() {
return $this->tab_id;
}
/**
* Get the tab title
*
* @return string The tab title
*/
public function get_title() {
return __('Hosting', 'seoprostack');
}
/**
* Get server information
*
* @return array Server information
*/
private function get_server_info() {
global $wpdb;
$server_info = array();
// PHP Version
$server_info['php_version'] = array(
'label' => __('PHP Version', 'seoprostack'),
'value' => phpversion(),
'recommendation' => __('PHP 8.0 or higher recommended', 'seoprostack')
);
// MySQL Version
$server_info['mysql_version'] = array(
'label' => __('MySQL Version', 'seoprostack'),
'value' => $wpdb->db_version(),
'recommendation' => __('MySQL 8.0 or higher recommended', 'seoprostack')
);
// Server Software
$server_info['server_software'] = array(
'label' => __('Server Software', 'seoprostack'),
'value' => $_SERVER['SERVER_SOFTWARE'] ?? __('Unknown', 'seoprostack'),
'recommendation' => ''
);
// PHP Memory Limit
$memory_limit = ini_get('memory_limit');
$server_info['php_memory_limit'] = array(
'label' => __('PHP Memory Limit', 'seoprostack'),
'value' => $memory_limit,
'recommendation' => __('256M or higher recommended', 'seoprostack')
);
// Max Upload Size
$upload_max_filesize = ini_get('upload_max_filesize');
$server_info['upload_max_filesize'] = array(
'label' => __('Max Upload Size', 'seoprostack'),
'value' => $upload_max_filesize,
'recommendation' => __('64M or higher recommended', 'seoprostack')
);
return $server_info;
}
/**
* Get hosting providers
*
* @return array The hosting providers data
*/
private function get_hosting_providers() {
return array(
'kinsta' => array(
'name' => 'Kinsta',
'description' => 'Premium WordPress hosting with excellent performance, security, and customer support.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://kinsta.com/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://kinsta.com/plans/'
)
)
),
'wpengine' => array(
'name' => 'WP Engine',
'description' => 'Managed WordPress hosting provider with solid performance and security features.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://wpengine.com/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://wpengine.com/plans/'
)
)
),
'siteground' => array(
'name' => 'SiteGround',
'description' => 'Popular WordPress hosting with good performance and customer support.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.siteground.com/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.siteground.com/wordpress-hosting.htm'
)
)
),
'hostinger' => array(
'name' => 'Hostinger',
'description' => 'Affordable WordPress hosting with good performance and user-friendly management tools.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.hostinger.com/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.hostinger.com/wordpress-hosting'
)
)
),
'hetzner' => array(
'name' => 'Hetzner Cloud',
'description' => 'High-performance cloud servers with excellent price-to-performance ratio for self-managed WordPress hosting.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.hetzner.com/cloud/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.hetzner.com/cloud#pricing'
)
)
),
'simplehost' => array(
'name' => 'SimpleHost',
'description' => 'Streamlined WordPress hosting with a focus on simplicity and performance.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://simplehost.so/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://simplehost.so/#pricing'
)
)
),
'cloudflare' => array(
'name' => 'Cloudflare',
'description' => 'Global cloud platform that provides CDN, security, and performance optimization services.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.cloudflare.com/en-gb/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.cloudflare.com/en-gb/plans/'
)
)
),
'spaceship' => array(
'name' => 'Spaceship',
'description' => 'Modern hosting platform with advanced features for WordPress sites.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.spaceship.com/',
'primary' => true
)
)
),
'101domain' => array(
'name' => '101Domain',
'description' => 'Domain registration and management service with support for hundreds of TLDs.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.101domain.com/',
'primary' => true
)
)
),
'namecheap' => array(
'name' => 'Namecheap',
'description' => 'Domain registrar and web hosting provider with competitive pricing and good support.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.namecheap.com/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.namecheap.com/hosting/shared/'
)
)
),
'updownio' => array(
'name' => 'Updown.io',
'description' => 'Simple and affordable website monitoring service with uptime checks and performance metrics.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://updown.io/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://updown.io/pricing'
)
)
)
);
}
/**
* Get the tab description
*
* @return string The tab description
*/
public function get_description() {
return __('Details about your current hosting environment and recommendations for improvement.', 'seoprostack');
}
/**
* Get additional hosting providers for specialized cases
*
* @return array Array of additional hosting providers
*/
private function get_additional_hosting_providers() {
return array(
'closte' => array(
'name' => 'Closte',
'description' => 'Managed WordPress hosting with advanced performance optimization and auto-scaling.',
'features' => array(
'Auto-scaling architecture',
'Global CDN included',
'Advanced caching',
'Free SSL certificates'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://closte.com/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://closte.com/pricing'
)
)
),
'cloudron' => array(
'name' => 'Cloudron',
'description' => 'Self-hosted platform that makes it easy to run web applications like WordPress on your server.',
'features' => array(
'One-click installation',
'Automatic updates',
'Built-in backups',
'SSL certificate management'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.cloudron.io/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.cloudron.io/pricing.html'
)
)
),
'hostinger' => array(
'name' => 'Hostinger',
'description' => 'Affordable WordPress hosting with good performance and user-friendly management tools.',
'features' => array(
'Free domain name',
'Managed WordPress features',
'LiteSpeed cache',
'Weekly backups'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.hostinger.com/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.hostinger.com/wordpress-hosting'
)
)
),
'hetzner' => array(
'name' => 'Hetzner Cloud',
'description' => 'High-performance cloud servers with excellent price-to-performance ratio for self-managed WordPress hosting.',
'features' => array(
'Scalable cloud instances',
'Per-minute billing',
'Snapshots and backups',
'Global data centers'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.hetzner.com/cloud/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.hetzner.com/cloud#pricing'
)
)
),
'simplehost' => array(
'name' => 'SimpleHost',
'description' => 'Streamlined WordPress hosting with a focus on simplicity and performance.',
'features' => array(
'Simplified hosting dashboard',
'Pre-optimized WordPress',
'Automated backups',
'Email hosting included'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://simplehost.so/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://simplehost.so/#pricing'
)
)
),
'cloudflare' => array(
'name' => 'Cloudflare',
'description' => 'Global cloud platform that provides CDN, security, and performance optimization services.',
'features' => array(
'Global CDN network',
'DDoS protection',
'Web application firewall',
'Performance optimization'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.cloudflare.com/en-gb/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.cloudflare.com/en-gb/plans/'
)
)
),
'spaceship' => array(
'name' => 'Spaceship',
'description' => 'Modern hosting platform with advanced features for WordPress sites.',
'features' => array(
'Advanced WordPress tools',
'Optimized for speed',
'Developer-friendly features',
'Smart caching system'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.spaceship.com/',
'primary' => true
)
)
),
'101domain' => array(
'name' => '101Domain',
'description' => 'Domain registration and management service with support for hundreds of TLDs.',
'features' => array(
'Extensive TLD selection',
'Domain privacy protection',
'Expert domain support',
'Bulk domain management'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.101domain.com/',
'primary' => true
)
)
),
'namecheap' => array(
'name' => 'Namecheap',
'description' => 'Domain registrar and web hosting provider with competitive pricing and good support.',
'features' => array(
'Free WhoisGuard protection',
'Competitive domain pricing',
'Reliable hosting services',
'Excellent support'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://www.namecheap.com/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://www.namecheap.com/hosting/shared/'
)
)
),
'updownio' => array(
'name' => 'Updown.io',
'description' => 'Simple and affordable website monitoring service with uptime checks and performance metrics.',
'features' => array(
'Real-time monitoring',
'Performance metrics',
'Notification alerts',
'Detailed reports'
),
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://updown.io/',
'primary' => true
),
array(
'text' => 'Pricing',
'url' => 'https://updown.io/pricing'
)
)
)
);
}
/**
* Render the tab content.
*/
public function render() {
// Use the self-contained data
$server_info = $this->server_info;
$hosting_providers = $this->hosting_providers;
echo '<div class="tab-content" id="' . esc_attr($this->tab_id) . '">;
if (function_exists('wp_seoprostack_get_hosting_providers') && empty($GLOBALS['_wp_seoprostack_hosting_loaded'])) {
// Optional: merge with any providers from the external function to ensure none are lost
$external_providers = wp_seoprostack_get_hosting_providers();
$hosting_providers = array_merge($external_providers, $hosting_providers);
$GLOBALS['_wp_seoprostack_hosting_loaded'] = true;
}
?>
<div class="seoprostack-settings-content tab-content" id="<?php echo esc_attr($this->get_tab_id()); ?>">
<div class="seoprostack-setting-section">
<h2><?php esc_html_e('Hosting Information', 'seoprostack'); ?></h2>
<p class="description"><?php echo esc_html($this->get_description()); ?></p>
<div class="seoprostack-server-info">
<h3><?php esc_html_e('Server Environment', 'seoprostack'); ?></h3>
<table class="seoprostack-info-table">
<tr>
<th><?php esc_html_e('PHP Version', 'seoprostack'); ?></th>
<td>
<?php echo esc_html($server_info['php_version']); ?>
<?php echo $this->get_status_icon($server_info['php_status']); ?>
</td>
<td class="seoprostack-info-note">
<?php echo esc_html($server_info['php_note']); ?>
</td>
</tr>
<tr>
<th><?php esc_html_e('MySQL Version', 'seoprostack'); ?></th>
<td>
<?php echo esc_html($server_info['mysql_version']); ?>
<?php echo $this->get_status_icon($server_info['mysql_status']); ?>
</td>
<td class="seoprostack-info-note">
<?php echo esc_html($server_info['mysql_note']); ?>
</td>
</tr>
<tr>
<th><?php esc_html_e('WordPress Version', 'seoprostack'); ?></th>
<td>
<?php echo esc_html($server_info['wp_version']); ?>
<?php echo $this->get_status_icon($server_info['wp_status']); ?>
</td>
<td class="seoprostack-info-note">
<?php echo esc_html($server_info['wp_note']); ?>
</td>
</tr>
<tr>
<th><?php esc_html_e('Memory Limit', 'seoprostack'); ?></th>
<td>
<?php echo esc_html($server_info['memory_limit']); ?>
<?php echo $this->get_status_icon($server_info['memory_status']); ?>
</td>
<td class="seoprostack-info-note">
<?php echo esc_html($server_info['memory_note']); ?>
</td>
</tr>
<tr>
<th><?php esc_html_e('Max Execution Time', 'seoprostack'); ?></th>
<td>
<?php echo esc_html($server_info['max_execution_time']); ?> seconds
<?php echo $this->get_status_icon($server_info['execution_status']); ?>
</td>
<td class="seoprostack-info-note">
<?php echo esc_html($server_info['execution_note']); ?>
</td>
</tr>
</table>
</div>
<div class="seoprostack-hosting-recommendations">
<h3><?php esc_html_e('Recommended Hosting Providers', 'seoprostack'); ?></h3>
<p><?php esc_html_e('These hosting providers offer excellent performance for WordPress sites and are recommended for optimal SEO results.', 'seoprostack'); ?></p>
<div class="seoprostack-hosting-grid">
<?php foreach ($hosting_providers as $key => $provider) : ?>
<div class="seoprostack-hosting-card">
<div class="seoprostack-hosting-card-header">
<h4><?php echo esc_html($provider['name']); ?></h4>
</div>
<div class="seoprostack-hosting-card-content">
<p><?php echo esc_html($provider['description']); ?></p>
<?php if (!empty($provider['features'])) : ?>
<ul class="seoprostack-hosting-features">
<?php foreach ($provider['features'] as $feature) : ?>
<li><?php echo esc_html($feature); ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
<div class="seoprostack-hosting-card-footer">
<?php foreach ($provider['button_group'] as $button) : ?>
<a href="<?php echo esc_url($button['url']); ?>" class="seoprostack-button<?php echo ($button['primary']) ? ' primary' : ''; ?>" target="_blank">
<?php echo esc_html($button['text']); ?>
</a>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
</div>
<?php
}
/**
* Get server information.
*
* @return array Server information.
*/
private function get_server_info() {
global $wpdb;
// PHP version
$php_version = phpversion();
$php_status = version_compare($php_version, '7.4', '>=') ? 'good' : (version_compare($php_version, '7.0', '>=') ? 'warning' : 'bad');
$php_note = version_compare($php_version, '7.4', '>=') ? __('Your PHP version is up to date.', 'seoprostack') : __('We recommend PHP 7.4 or higher for optimal performance and security.', 'seoprostack');
// MySQL version
$mysql_version = $wpdb->db_version();
$mysql_status = version_compare($mysql_version, '5.6', '>=') ? 'good' : 'warning';
$mysql_note = version_compare($mysql_version, '5.6', '>=') ? __('Your MySQL version is sufficient.', 'seoprostack') : __('We recommend MySQL 5.6 or higher for better performance.', 'seoprostack');
// WordPress version
$wp_version = get_bloginfo('version');
$wp_status = version_compare($wp_version, '5.8', '>=') ? 'good' : (version_compare($wp_version, '5.5', '>=') ? 'warning' : 'bad');
$wp_note = version_compare($wp_version, '5.8', '>=') ? __('Your WordPress version is up to date.', 'seoprostack') : __('We recommend updating to the latest version of WordPress.', 'seoprostack');
// Memory limit
$memory_limit = ini_get('memory_limit');
$memory_limit_bytes = wp_convert_hr_to_bytes($memory_limit);
$memory_status = $memory_limit_bytes >= 256 * 1024 * 1024 ? 'good' : ($memory_limit_bytes >= 128 * 1024 * 1024 ? 'warning' : 'bad');
$memory_note = $memory_limit_bytes >= 256 * 1024 * 1024 ? __('Your memory limit is sufficient.', 'seoprostack') : __('We recommend a memory limit of at least 256MB.', 'seoprostack');
// Max execution time
$max_execution_time = ini_get('max_execution_time');
$execution_status = $max_execution_time >= 180 || $max_execution_time == 0 ? 'good' : ($max_execution_time >= 60 ? 'warning' : 'bad');
$execution_note = $max_execution_time >= 180 || $max_execution_time == 0 ? __('Your max execution time is sufficient.', 'seoprostack') : __('We recommend a max execution time of at least 180 seconds.', 'seoprostack');
return array(
'php_version' => $php_version,
'php_status' => $php_status,
'php_note' => $php_note,
'mysql_version' => $mysql_version,
'mysql_status' => $mysql_status,
'mysql_note' => $mysql_note,
'wp_version' => $wp_version,
'wp_status' => $wp_status,
'wp_note' => $wp_note,
'memory_limit' => $memory_limit,
'memory_status' => $memory_status,
'memory_note' => $memory_note,
'max_execution_time' => $max_execution_time,
'execution_status' => $execution_status,
'execution_note' => $execution_note
);
}
/**
* Get a status icon based on the status.
*
* @param string $status Status (good, warning, or bad).
* @return string Status icon HTML.
*/
private function get_status_icon($status) {
switch ($status) {
case 'good':
return '<span class="seoprostack-status-icon good dashicons dashicons-yes-alt"></span>';
case 'warning':
return '<span class="seoprostack-status-icon warning dashicons dashicons-warning"></span>';
case 'bad':
return '<span class="seoprostack-status-icon bad dashicons dashicons-dismiss"></span>';
default:
return '';
}
}
}

View File

@ -0,0 +1,176 @@
<?php
/**
* The Pro Plugins tab for plugin settings.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/Tabs
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The Pro Plugins tab for plugin settings.
*/
class SEOProStack_Tab_Pro_Plugins {
/**
* Render the tab content.
*/
public function render() {
?>
<div class="seoprostack-settings-content tab-content" id="pro-plugins">
<div class="seoprostack-setting-section">
<h2><?php esc_html_e('Premium WordPress Plugins', 'seoprostack'); ?></h2>
<p class="description"><?php esc_html_e('These premium plugins enhance your WordPress site with advanced features and functionality.', 'seoprostack'); ?></p>
<div class="seoprostack-plugin-filters" id="seoprostack-plugin-filters">
<a href="#" class="button current" data-category="all"><?php esc_html_e('All', 'seoprostack'); ?></a>
<a href="#" class="button" data-category="seo"><?php esc_html_e('SEO', 'seoprostack'); ?></a>
<a href="#" class="button" data-category="performance"><?php esc_html_e('Performance', 'seoprostack'); ?></a>
<a href="#" class="button" data-category="analytics"><?php esc_html_e('Analytics', 'seoprostack'); ?></a>
</div>
<div class="seoprostack-loading" style="text-align: center; padding: 30px; display: none;">
<span class="spinner is-active"></span>
<p><?php esc_html_e('Loading plugins...', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-plugin-list" id="seoprostack-plugin-list">
<!-- Plugins will be loaded here via AJAX -->
</div>
<div class="seoprostack-no-plugins" style="display: none;">
<p><?php esc_html_e('No plugins found matching your criteria.', 'seoprostack'); ?></p>
</div>
</div>
<script type="text/javascript">
jQuery(document).ready(function($) {
// Function to load plugins
function loadProPlugins(category) {
var $container = $('#seoprostack-plugin-list');
var $loading = $('.seoprostack-loading');
var $noPlugins = $('.seoprostack-no-plugins');
// Reset container and show loading
$container.empty();
$noPlugins.hide();
$loading.show();
// Make AJAX request
$.ajax({
url: seoProStack.ajaxurl,
type: 'POST',
data: {
action: 'seoprostack_get_pro_plugins',
category: category,
nonce: seoProStack.nonce
},
success: function(response) {
$loading.hide();
if (response.success && response.data.plugins && response.data.plugins.length > 0) {
// Render plugins
$.each(response.data.plugins, function(index, plugin) {
var $pluginCard = $('<div class="seoprostack-plugin-card" />');
// Plugin header
var $header = $('<div class="seoprostack-plugin-header" />');
$header.append('<h3>' + plugin.name + '</h3>');
$header.append('<span class="seoprostack-plugin-version">v' + plugin.version + '</span>');
$pluginCard.append($header);
// Plugin content
var $content = $('<div class="seoprostack-plugin-content" />');
$content.append('<p>' + plugin.description + '</p>');
// Plugin actions
var $actions = $('<div class="seoprostack-plugin-actions" />');
if (plugin.status === 'installed') {
if (plugin.active) {
$actions.append('<span class="button button-disabled">Active</span>');
} else {
$actions.append('<a href="#" class="button activate-plugin" data-plugin="' + plugin.path + '">Activate</a>');
}
} else {
$actions.append('<a href="' + plugin.url + '" class="button button-primary" target="_blank">Get Plugin</a>');
}
$content.append($actions);
$pluginCard.append($content);
// Add card to container
$container.append($pluginCard);
});
} else {
$noPlugins.show();
}
},
error: function() {
$loading.hide();
$noPlugins.show();
}
});
}
// Handle category filter clicks
$('#seoprostack-plugin-filters a').on('click', function(e) {
e.preventDefault();
// Update active filter
$('#seoprostack-plugin-filters a').removeClass('current');
$(this).addClass('current');
// Load plugins
var category = $(this).data('category');
loadProPlugins(category);
});
// Load initial plugins
loadProPlugins('all');
// Delegate plugin activation
$(document).on('click', '.activate-plugin', function(e) {
e.preventDefault();
var $button = $(this);
var pluginPath = $button.data('plugin');
$button.text('Activating...').addClass('updating-message');
$.ajax({
url: seoProStack.ajaxurl,
type: 'POST',
data: {
action: 'seoprostack_activate_plugin',
plugin: pluginPath,
nonce: seoProStack.nonce
},
success: function(response) {
if (response.success) {
$button.removeClass('updating-message')
.removeClass('activate-plugin')
.addClass('button-disabled')
.text('Active')
.prop('disabled', true);
} else {
$button.removeClass('updating-message').text('Activate');
alert(response.data.message || 'Error activating plugin');
}
},
error: function() {
$button.removeClass('updating-message').text('Activate');
alert('Error connecting to server');
}
});
});
});
</script>
</div>
<?php
}
}

View File

@ -0,0 +1,617 @@
<?php
/**
* The Recommended Plugins tab for plugin settings.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/Tabs
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The Recommended Plugins tab for plugin settings.
* Self-contained class with integrated data and functionality
*/
class SEOProStack_Tab_Recommended_Plugins {
/**
* Tab identifier
*
* @var string
*/
private $tab_id = 'recommended-plugins';
/**
* Plugin details cache.
*
* @var array
*/
private $plugin_details = array();
/**
* Initialize the class.
* Register any hooks or actions here.
*/
public function __construct() {
// Register AJAX handler for plugin installation
add_action('wp_ajax_seoprostack_install_plugins', array($this, 'ajax_install_plugins'));
// Define plugin names and descriptions for common plugins
$this->plugin_details = array(
'wordpress-seo' => array(
'name' => 'Yoast SEO (Free)',
'description' => 'The #1 WordPress SEO plugin that helps you with content optimization, XML sitemaps, and more.'
),
'autoptimize' => array(
'name' => 'Autoptimize',
'description' => 'Optimizes your website, concatenating scripts and styles, minifying and compressing them.'
),
'wp-fastest-cache' => array(
'name' => 'WP Fastest Cache',
'description' => 'This plugin creates static html files from your dynamic WordPress site to speed up your website.'
),
'updraftplus' => array(
'name' => 'UpdraftPlus',
'description' => 'Backup your website with ease, including files and database, and restore with one click.'
),
'google-site-kit' => array(
'name' => 'Site Kit by Google',
'description' => 'Get insights from multiple Google products directly in your WordPress dashboard.'
),
'wordfence' => array(
'name' => 'Wordfence Security',
'description' => 'Protect your site from malicious hackers with firewall and malware scanner.'
),
'rank-math-seo' => array(
'name' => 'Rank Math SEO',
'description' => 'SEO plugin that helps you rank higher in search engines with its powerful features and easy-to-use interface.'
),
'all-in-one-seo-pack' => array(
'name' => 'All in One SEO Pack',
'description' => 'Complete SEO solution for WordPress including on-page SEO optimization, XML sitemaps and more.'
),
'compressx' => array(
'name' => 'CompressX',
'description' => 'Comprehensive image optimization plugin for WordPress that improves page load speed.'
),
'wp-rocket' => array(
'name' => 'WP Rocket',
'description' => 'Premium caching plugin that improves site performance and page loading speed.'
),
'contact-form-7' => array(
'name' => 'Contact Form 7',
'description' => 'Simple but flexible contact form plugin with extensive customization options.'
)
);
}
/**
* Get the tab ID
*
* @return string The tab ID
*/
public function get_tab_id() {
return $this->tab_id;
}
/**
* Get the tab title
*
* @return string The tab title
*/
public function get_title() {
return __('Recommended Plugins', 'seoprostack');
}
/**
* Get the tab description
*
* @return string The tab description
*/
public function get_description() {
return __('These free plugins work well with SEO Pro Stack to enhance your WordPress site.', 'seoprostack');
}
/**
* Get recommended plugins
* This internalizes the data previously retrieved from wp_seoprostack_get_recommended_plugins()
*
* @return array Array of recommended plugins categorized by use case
*/
public function get_recommended_plugins() {
return array(
'minimal' => array(
'antispam-bee',
'compressx',
'fluent-smtp',
'kadence-blocks',
'simple-cloudflare-turnstile'
),
'admin' => array(
'admin-bar-dashboard-control',
'codepress-admin-columns',
'admin-menu-editor',
'hide-admin-notices',
'mainwp-child',
'mainwp-child-reports',
'magic-login',
'manage-notification-emails',
'plugin-groups',
'plugin-toggle'
),
'affiliates' => array(
'pretty-links',
'simple-urls',
'slicewp'
),
'ai' => array(
'ai-engine',
),
'cms' => array(
'auto-post-scheduler',
'block-options',
'bookmark-card',
'browser-shots',
'bulk-actions-select-all',
'bulk-edit-categories-tags',
'bulk-edit-user-profiles-in-spreadsheet',
'carbon-copy',
'code-block-pro',
'iframe-block',
'ics-calendar',
'mammoth-docx-converter',
'nav-menu-roles',
'ninja-tables',
'post-draft-preview',
'post-type-switcher',
'simple-custom-post-order',
'simple-icons',
'sticky-posts-switch',
'term-management-tools',
'the-paste',
'ultimate-addons-for-gutenberg',
'wikipedia-preview',
'wp-sheet-editor-bulk-spreadsheet-editor-for-posts-and-pages'
),
'compliance' => array(
'avatar-privacy',
'complianz-gdpr',
'complianz-terms-conditions',
'really-simple-ssl'
),
'crm' => array(
'fluent-boards',
'fluent-booking',
'fluent-community',
'fluent-crm',
'fluentform',
'fluentforms-pdf',
'fluentform-block',
'fluent-support'
),
'ecommerce' => array(
'woocommerce',
'woo-bulk-edit-products',
'woo-coupons-bulk-editor',
'woocommerce-gateway-gocardless',
'kadence-woocommerce-email-designer',
'pymntpl-paypal-woocommerce',
'woo-stripe-payment'
),
'lms' => array(
'fluent-community',
'masterstudy-lms-learning-management-system',
'tutor'
),
'media' => array(
'easy-watermark',
'enable-media-replace',
'image-copytrack',
'imsanity',
'media-file-renamer',
'safe-svg'
),
'seo' => array(
'burst-statistics',
'pretty-link',
'revive-so',
'seo-by-rank-math',
'syndication-links',
'ultimate-410',
'webmention'
),
'setup' => array(
'kadence-starter-templates',
'wordpress-importer'
),
'social' => array(
'bit-social',
'easy-video-reviews',
'social-engine',
'wp-social-ninja',
'wp-social-reviews'
),
'speed' => array(
'disable-wordpress-updates',
'flying-analytics',
'flying-pages',
'flying-scripts',
'freesoul-deactivate-plugins',
'index-wp-mysql-for-speed',
'litespeed-cache',
'performant-translations',
'wp-optimize',
'wp-widget-disable'
),
'translation' => array(
'hreflang-manager-lite',
'performant-translations',
'translatepress-multilingual'
),
'advanced' => array(
'acf-better-search',
'advanced-custom-fields',
'automatorwp',
'bit-pi',
'bit-integrations',
'code-snippets',
'easy-code-manager',
'favorites',
'remove-cpt-base',
'remove-old-slugspermalinks',
'secure-custom-fields',
'yellow-pencil-visual-theme-customizer'
),
'debug' => array(
'advanced-database-cleaner',
'debug-log-manager',
'gotmls',
'query-monitor',
'string-locator',
'user-switching',
'wp-crontrol'
)
);
}
/**
* Render the tab content.
*/
public function render() {
// Get recommended plugins from the internal method
$recommended_plugins = $this->get_recommended_plugins();
// For backward compatibility, make recommended plugins available through global function
if (function_exists('wp_seoprostack_get_recommended_plugins') && empty($GLOBALS['_wp_seoprostack_recommended_plugins_loaded'])) {
// Optional: merge with any plugins from the external function to ensure none are lost
$external_plugins = wp_seoprostack_get_recommended_plugins();
$recommended_plugins = array_merge_recursive($external_plugins, $recommended_plugins);
$GLOBALS['_wp_seoprostack_recommended_plugins_loaded'] = true;
}
?>
<div class="seoprostack-settings-content tab-content" id="<?php echo esc_attr($this->get_tab_id()); ?>">
<div class="seoprostack-setting-section">
<h2><?php esc_html_e('Recommended Free Plugins', 'seoprostack'); ?></h2>
<p class="description"><?php echo esc_html($this->get_description()); ?></p>
<?php
// Display SEO plugins section
if (!empty($recommended_plugins['seo'])) {
echo '<h3>' . esc_html__('SEO Plugins', 'seoprostack') . '</h3>';
echo '<div class="seoprostack-plugin-grid">';
foreach ($recommended_plugins['seo'] as $plugin_slug) {
$this->render_plugin_card($plugin_slug);
}
echo '</div>';
}
// Display Cache plugins section
if (!empty($recommended_plugins['speed'])) {
echo '<h3>' . esc_html__('Cache & Performance', 'seoprostack') . '</h3>';
echo '<div class="seoprostack-plugin-grid">';
foreach ($recommended_plugins['speed'] as $plugin_slug) {
$this->render_plugin_card($plugin_slug);
}
echo '</div>';
}
// Display Security plugins section
if (!empty($recommended_plugins['security'])) {
echo '<h3>' . esc_html__('Security', 'seoprostack') . '</h3>';
echo '<div class="seoprostack-plugin-grid">';
foreach ($recommended_plugins['security'] as $plugin_slug) {
$this->render_plugin_card($plugin_slug);
}
echo '</div>';
}
// Display Image optimization plugins section
if (!empty($recommended_plugins['media'])) {
echo '<h3>' . esc_html__('Image Optimization', 'seoprostack') . '</h3>';
echo '<div class="seoprostack-plugin-grid">';
foreach ($recommended_plugins['media'] as $plugin_slug) {
$this->render_plugin_card($plugin_slug);
}
echo '</div>';
}
// Display Backup plugins section
if (!empty($recommended_plugins['backup'])) {
echo '<h3>' . esc_html__('Backup & Migration', 'seoprostack') . '</h3>';
echo '<div class="seoprostack-plugin-grid">';
foreach ($recommended_plugins['backup'] as $plugin_slug) {
$this->render_plugin_card($plugin_slug);
}
echo '</div>';
}
?>
<div class="seoprostack-bulk-actions">
<button class="button button-primary" id="seoprostack-install-selected">
<?php esc_html_e('Install Selected Plugins', 'seoprostack'); ?>
</button>
<span class="spinner"></span>
</div>
<div id="seoprostack-install-response"></div>
<script type="text/javascript">
jQuery(document).ready(function($) {
// Handle bulk installation
$('#seoprostack-install-selected').on('click', function(e) {
e.preventDefault();
var $button = $(this);
var $spinner = $button.next('.spinner');
var $response = $('#seoprostack-install-response');
var selected = [];
// Get selected plugins
$('.seoprostack-plugin-check:checked').each(function() {
selected.push($(this).val());
});
if (selected.length === 0) {
$response.html('<div class="seoprostack-notice seoprostack-notice-warning">Please select at least one plugin to install</div>');
return;
}
// Show loading
$button.prop('disabled', true);
$spinner.css('visibility', 'visible');
$response.html('<div class="seoprostack-notice seoprostack-notice-loading">Installing plugins...</div>');
// Send AJAX request
$.ajax({
url: wpSeoProStack.ajaxurl,
type: 'POST',
data: {
action: 'seoprostack_install_plugins',
plugins: selected,
nonce: wpSeoProStack.nonce
},
success: function(response) {
// Hide loading
$button.prop('disabled', false);
$spinner.css('visibility', 'hidden');
if (response.success) {
var html = '<div class="seoprostack-notice seoprostack-notice-success">';
html += '<p>Installation completed:</p><ul>';
$.each(response.data.installed, function(i, plugin) {
html += '<li>' + plugin + ' installed and activated successfully</li>';
// Update UI
$('.seoprostack-plugin-card[data-slug="' + plugin + '"]')
.find('.plugin-status')
.removeClass('not-installed')
.addClass('active')
.text('Active');
});
if (response.data.failed.length > 0) {
html += '</ul><p>Installation failed:</p><ul>';
$.each(response.data.failed, function(i, fail) {
html += '<li>' + fail.plugin + ': ' + fail.message + '</li>';
});
}
html += '</ul></div>';
$response.html(html);
} else {
$response.html('<div class="seoprostack-notice seoprostack-notice-error">' + response.data.message + '</div>');
}
},
error: function() {
// Hide loading
$button.prop('disabled', false);
$spinner.css('visibility', 'hidden');
// Show error
$response.html('<div class="seoprostack-notice seoprostack-notice-error">Error connecting to server</div>');
}
});
});
});
</script>
</div>
</div>
<?php
}
/**
* Render a plugin card.
*
* @param string $slug The plugin slug.
*/
private function render_plugin_card($slug) {
// Get plugin details
$name = isset($this->plugin_details[$slug]['name']) ? $this->plugin_details[$slug]['name'] : $this->get_readable_name($slug);
$description = isset($this->plugin_details[$slug]['description']) ? $this->plugin_details[$slug]['description'] : '';
// Check if plugin is installed and active
$status = 'not-installed';
$status_text = 'Not Installed';
if (file_exists(WP_PLUGIN_DIR . '/' . $slug)) {
$status = 'installed';
$status_text = 'Installed';
include_once ABSPATH . 'wp-admin/includes/plugin.php';
if (is_plugin_active($slug . '/' . $slug . '.php') || is_plugin_active($slug . '/index.php')) {
$status = 'active';
$status_text = 'Active';
}
}
?>
<div class="seoprostack-plugin-card" data-slug="<?php echo esc_attr($slug); ?>">
<div class="seoprostack-plugin-card-header">
<label class="seoprostack-checkbox-container">
<input type="checkbox" class="seoprostack-plugin-check" value="<?php echo esc_attr($slug); ?>" <?php disabled($status === 'active', true); ?>>
<span class="seoprostack-checkbox-checkmark"></span>
</label>
<span class="plugin-status <?php echo esc_attr($status); ?>"><?php echo esc_html($status_text); ?></span>
</div>
<div class="seoprostack-plugin-card-content">
<h3><?php echo esc_html($name); ?></h3>
<?php if (!empty($description)) : ?>
<p><?php echo esc_html($description); ?></p>
<?php endif; ?>
<div class="seoprostack-plugin-card-footer">
<a href="https://wordpress.org/plugins/<?php echo esc_attr($slug); ?>/" class="button button-secondary" target="_blank">
<?php esc_html_e('View Details', 'seoprostack'); ?>
</a>
</div>
</div>
</div>
<?php
}
/**
* Get a readable name from a plugin slug.
*
* @param string $slug The plugin slug.
* @return string The readable name.
*/
private function get_readable_name($slug) {
$name = str_replace(array('-', '_'), ' ', $slug);
return ucwords($name);
}
/**
* AJAX handler for plugin installation
*/
public function ajax_install_plugins() {
// Check nonce for security
check_ajax_referer('wp-seoprostack-nonce', 'nonce');
// Ensure user has permission
if (!current_user_can('install_plugins')) {
wp_send_json_error(array('message' => __('You do not have permission to install plugins.', 'seoprostack')));
}
// Get selected plugins
$plugins = isset($_POST['plugins']) ? (array) $_POST['plugins'] : array();
if (empty($plugins)) {
wp_send_json_error(array('message' => __('No plugins selected.', 'seoprostack')));
}
// Include required files for plugin installation
require_once ABSPATH . 'wp-admin/includes/plugin.php';
require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
// Set up the upgrader
$skin = new WP_Ajax_Upgrader_Skin();
$upgrader = new Plugin_Upgrader($skin);
$installed = array();
$failed = array();
// Install and activate each plugin
foreach ($plugins as $plugin) {
// Skip if already active
if (is_plugin_active($plugin . '/' . $plugin . '.php') || is_plugin_active($plugin . '/index.php')) {
continue;
}
// Get plugin info from wordpress.org
$api = plugins_api('plugin_information', array(
'slug' => $plugin,
'fields' => array(
'short_description' => false,
'sections' => false,
'requires' => false,
'rating' => false,
'ratings' => false,
'downloaded' => false,
'last_updated' => false,
'added' => false,
'tags' => false,
'compatibility' => false,
'homepage' => false,
'donate_link' => false,
),
));
if (is_wp_error($api)) {
$failed[] = array(
'plugin' => $plugin,
'message' => $api->get_error_message()
);
continue;
}
// Install the plugin
$result = $upgrader->install($api->download_link);
if (is_wp_error($result)) {
$failed[] = array(
'plugin' => $plugin,
'message' => $result->get_error_message()
);
continue;
}
if ($result === false) {
$failed[] = array(
'plugin' => $plugin,
'message' => __('Failed to install plugin.', 'seoprostack')
);
continue;
}
// Activate the plugin
$activate = activate_plugin(WP_PLUGIN_DIR . '/' . $plugin . '/' . $plugin . '.php');
if (is_wp_error($activate)) {
// Try alternative file path
$activate = activate_plugin(WP_PLUGIN_DIR . '/' . $plugin . '/index.php');
if (is_wp_error($activate)) {
$failed[] = array(
'plugin' => $plugin,
'message' => $activate->get_error_message()
);
continue;
}
}
$installed[] = $plugin;
}
// Send success response
wp_send_json_success(array(
'installed' => $installed,
'failed' => $failed
));
}
}

View File

@ -0,0 +1,92 @@
<?php
/**
* The Theme tab for plugin settings.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/Tabs
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The Theme tab for plugin settings.
*/
class SEOProStack_Tab_Theme {
/**
* Render the tab content.
*/
public function render() {
// Get current theme
$current_theme = wp_get_theme();
?>
<div class="seoprostack-settings-content tab-content" id="theme">
<div class="seoprostack-setting-section">
<h2><?php esc_html_e('Theme Recommendations', 'seoprostack'); ?></h2>
<p class="description"><?php esc_html_e('These themes are fast, SEO-friendly, and work well with SEO Pro Stack.', 'seoprostack'); ?></p>
<div class="seoprostack-theme-info">
<h3><?php esc_html_e('Your Current Theme', 'seoprostack'); ?></h3>
<div class="seoprostack-current-theme">
<?php if ($current_theme->get_screenshot()) : ?>
<div class="seoprostack-theme-screenshot">
<img src="<?php echo esc_url($current_theme->get_screenshot()); ?>" alt="<?php echo esc_attr($current_theme->display('Name')); ?>">
</div>
<?php endif; ?>
<div class="seoprostack-theme-details">
<h4><?php echo esc_html($current_theme->display('Name')); ?></h4>
<div class="seoprostack-theme-version"><?php printf(esc_html__('Version: %s', 'seoprostack'), $current_theme->display('Version')); ?></div>
<div class="seoprostack-theme-author"><?php printf(esc_html__('By %s', 'seoprostack'), $current_theme->display('Author')); ?></div>
<p class="description"><?php echo esc_html($current_theme->display('Description')); ?></p>
</div>
</div>
</div>
<div class="seoprostack-recommended-themes">
<h3><?php esc_html_e('Recommended Themes', 'seoprostack'); ?></h3>
<div class="seoprostack-theme-grid">
<!-- Astra Theme -->
<div class="seoprostack-theme-card">
<div class="seoprostack-theme-card-header">
<img src="<?php echo esc_url(SEOPROSTACK_PLUGIN_URL . 'admin/images/themes/astra.jpg'); ?>" alt="Astra Theme">
</div>
<div class="seoprostack-theme-card-content">
<h4>Astra</h4>
<p><?php esc_html_e('Fast, lightweight and customizable WordPress theme suitable for blogs, personal portfolios and business websites.', 'seoprostack'); ?></p>
<a href="https://wpastra.com/" class="button" target="_blank"><?php esc_html_e('Learn More', 'seoprostack'); ?></a>
</div>
</div>
<!-- GeneratePress Theme -->
<div class="seoprostack-theme-card">
<div class="seoprostack-theme-card-header">
<img src="<?php echo esc_url(SEOPROSTACK_PLUGIN_URL . 'admin/images/themes/generatepress.jpg'); ?>" alt="GeneratePress Theme">
</div>
<div class="seoprostack-theme-card-content">
<h4>GeneratePress</h4>
<p><?php esc_html_e('Lightweight WordPress theme focused on speed, stability, and accessibility.', 'seoprostack'); ?></p>
<a href="https://generatepress.com/" class="button" target="_blank"><?php esc_html_e('Learn More', 'seoprostack'); ?></a>
</div>
</div>
<!-- Kadence Theme -->
<div class="seoprostack-theme-card">
<div class="seoprostack-theme-card-header">
<img src="<?php echo esc_url(SEOPROSTACK_PLUGIN_URL . 'admin/images/themes/kadence.jpg'); ?>" alt="Kadence Theme">
</div>
<div class="seoprostack-theme-card-content">
<h4>Kadence</h4>
<p><?php esc_html_e('Fast, lightweight, and extremely customizable WordPress theme.', 'seoprostack'); ?></p>
<a href="https://www.kadencewp.com/kadence-theme/" class="button" target="_blank"><?php esc_html_e('Learn More', 'seoprostack'); ?></a>
</div>
</div>
</div>
</div>
</div>
</div>
<?php
}
}

View File

@ -0,0 +1,299 @@
<?php
/**
* The Tools tab for plugin settings.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/Tabs
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The Tools tab for plugin settings.
* Self-contained class with integrated data and functionality
*/
class SEOProStack_Tab_Tools {
/**
* Tab identifier
*
* @var string
*/
private $tab_id = 'tools';
/**
* Initialize the class.
* Register any hooks or actions here.
*/
public function __construct() {
// Register AJAX handler for database optimization
add_action('wp_ajax_seoprostack_optimize_database', array($this, 'ajax_optimize_database'));
}
/**
* Get the tab ID
*
* @return string The tab ID
*/
public function get_tab_id() {
return $this->tab_id;
}
/**
* Get the tab title
*
* @return string The tab title
*/
public function get_title() {
return __('Tools', 'seoprostack');
}
/**
* Get the tab description
*
* @return string The tab description
*/
public function get_description() {
return __('Useful tools and resources to help improve your website\'s SEO and performance.', 'seoprostack');
}
/**
* Get the tools data
* This internalizes the data previously retrieved from wp_seoprostack_get_tools()
*
* @return array Array of tools with their details
*/
public function get_tools() {
return array(
'advise' => array(
'name' => 'Advise.so',
'description' => 'Accelerate website growth with AI-powered content optimization and topic recommendations.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://advise.so/',
'primary' => true
),
array(
'text' => 'App',
'url' => 'https://app.advise.so/'
)
)
),
'seoutils' => array(
'name' => 'SEO Utils',
'description' => 'Rich collection of online SEO tools for keyword research, SERP analysis, and content optimization.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://seoutils.com/',
'primary' => true
)
)
),
'dataforseo' => array(
'name' => 'DataForSEO',
'description' => 'Comprehensive SEO APIs for rank tracking, SERP analysis, and keyword research.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://dataforseo.com/',
'primary' => true
),
array(
'text' => 'Dashboard',
'url' => 'https://app.dataforseo.com/'
)
)
),
// For brevity, I'm including only a few tools here
// In production, you would include all tools or dynamically load them
'ahrefs' => array(
'name' => 'Ahrefs',
'description' => 'Comprehensive SEO toolset for backlink analysis, keyword research, and competitor analysis.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://ahrefs.com/',
'primary' => true
),
array(
'text' => 'Dashboard',
'url' => 'https://app.ahrefs.com/'
)
)
),
'localrank' => array(
'name' => 'LocalRank',
'description' => 'Track keyword rankings for multiple locations to better understand local SEO performance.',
'button_group' => array(
array(
'text' => 'Home Page',
'url' => 'https://app.localrank.io/',
'primary' => true
)
)
),
// Additional tools would be listed here...
);
}
/**
* Render the tab content.
*/
public function render() {
// Get tools from the internal method
$tools = $this->get_tools();
// For backward compatibility, make tools available through the global function
if (function_exists('wp_seoprostack_get_tools') && empty($GLOBALS['_wp_seoprostack_tools_loaded'])) {
// Optional: merge with any tools from the external function to ensure none are lost
$external_tools = wp_seoprostack_get_tools();
$tools = array_merge($external_tools, $tools);
$GLOBALS['_wp_seoprostack_tools_loaded'] = true;
}
?>
<div class="seoprostack-settings-content tab-content" id="<?php echo esc_attr($this->get_tab_id()); ?>">
<div class="seoprostack-setting-section">
<h2><?php esc_html_e('SEO Tools', 'seoprostack'); ?></h2>
<p class="description"><?php echo esc_html($this->get_description()); ?></p>
<div class="seoprostack-tools-grid">
<?php foreach ($tools as $key => $tool) : ?>
<div class="seoprostack-tool-card">
<div class="seoprostack-tool-card-header">
<span class="dashicons dashicons-admin-tools"></span>
</div>
<div class="seoprostack-tool-card-content">
<h3><?php echo esc_html($tool['name']); ?></h3>
<p><?php echo esc_html($tool['description']); ?></p>
<?php if (!empty($tool['button_group'])) : ?>
<?php foreach ($tool['button_group'] as $button) : ?>
<a href="<?php echo esc_url($button['url']); ?>" class="button<?php echo ($button['primary']) ? ' button-primary' : ''; ?>" target="_blank">
<?php echo esc_html($button['text']); ?>
</a>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="seoprostack-setting-section">
<h3><?php esc_html_e('Database Optimization', 'seoprostack'); ?></h3>
<p class="description"><?php esc_html_e('Clean up your WordPress database to improve performance.', 'seoprostack'); ?></p>
<div id="seoprostack-db-cleanup-response"></div>
<div class="seoprostack-db-actions">
<button type="button" class="button button-primary" id="seoprostack-optimize-db">
<?php esc_html_e('Optimize Database', 'seoprostack'); ?>
</button>
<span class="spinner"></span>
</div>
<script type="text/javascript">
jQuery(document).ready(function($) {
$('#seoprostack-optimize-db').on('click', function(e) {
e.preventDefault();
var $button = $(this);
var $spinner = $button.next('.spinner');
var $response = $('#seoprostack-db-cleanup-response');
// Show loading
$button.prop('disabled', true);
$spinner.css('visibility', 'visible');
// Send AJAX request
$.ajax({
url: wpSeoProStack.ajaxurl,
type: 'POST',
data: {
action: 'seoprostack_optimize_database',
nonce: wpSeoProStack.nonce
},
success: function(response) {
// Hide loading
$button.prop('disabled', false);
$spinner.css('visibility', 'hidden');
if (response.success) {
$response.html('<div class="seoprostack-notice seoprostack-notice-success">' + response.data.message + '</div>');
} else {
$response.html('<div class="seoprostack-notice seoprostack-notice-error">' + response.data.message + '</div>');
}
},
error: function() {
// Hide loading
$button.prop('disabled', false);
$spinner.css('visibility', 'hidden');
// Show error
$response.html('<div class="seoprostack-notice seoprostack-notice-error">Error connecting to server</div>');
}
});
});
});
</script>
</div>
</div>
</div>
<?php
}
/**
* AJAX handler for database optimization
*/
public function ajax_optimize_database() {
// Check nonce for security
check_ajax_referer('wp-seoprostack-nonce', 'nonce');
// Ensure user has permission
if (!current_user_can('manage_options')) {
wp_send_json_error(array('message' => __('You do not have permission to perform this action.', 'seoprostack')));
}
global $wpdb;
// Optimize database tables
$tables = $wpdb->get_results('SHOW TABLES', ARRAY_N);
$optimized = 0;
foreach ($tables as $table) {
if (0 === strpos($table[0], $wpdb->prefix)) {
$wpdb->query("OPTIMIZE TABLE {$table[0]}");
$optimized++;
}
}
// Clean up post revisions
$deleted_revisions = $wpdb->query("DELETE FROM $wpdb->posts WHERE post_type = 'revision'");
// Clean up auto drafts
$deleted_drafts = $wpdb->query("DELETE FROM $wpdb->posts WHERE post_status = 'auto-draft'");
// Clean up orphaned postmeta
$deleted_postmeta = $wpdb->query("
DELETE pm
FROM $wpdb->postmeta pm
LEFT JOIN $wpdb->posts p ON p.ID = pm.post_id
WHERE p.ID IS NULL
");
// Send success response
wp_send_json_success(array(
'message' => sprintf(
__('Database optimization complete. Optimized %d tables, deleted %d revisions, %d auto-drafts, and %d orphaned postmeta entries.', 'seoprostack'),
$optimized,
$deleted_revisions,
$deleted_drafts,
$deleted_postmeta
)
));
}
}

View File

@ -0,0 +1,132 @@
<?php
/**
* The Workflow tab for plugin settings.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Admin/Settings/Tabs
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The Workflow tab for plugin settings.
*/
class SEOProStack_Tab_Workflow {
/**
* Render the tab content.
*/
public function render() {
$options = get_option('seoprostack_workflow_options', array(
'auto_upload_images' => true,
'max_width' => 1200,
'max_height' => 1200,
'exclude_urls' => '',
'image_name_pattern' => '%filename%',
'image_alt_pattern' => '%filename%'
));
?>
<div class="seoprostack-settings-content tab-content" id="workflow">
<form method="post" action="options.php" id="seoprostack-workflow-form">
<?php settings_fields('seoprostack_settings'); ?>
<div class="seoprostack-setting-section">
<h2><?php esc_html_e('Image Auto-Upload Settings', 'seoprostack'); ?></h2>
<p class="description"><?php esc_html_e('Configure how external images are automatically uploaded to your media library.', 'seoprostack'); ?></p>
<div class="seoprostack-toggle">
<div class="seoprostack-toggle-header">
<div class="seoprostack-toggle-main">
<div class="seoprostack-toggle-left">
<div class="wp-toggle-switch">
<input type="checkbox"
id="auto_upload_images"
name="seoprostack_workflow_options[auto_upload_images]"
value="1"
<?php checked(isset($options['auto_upload_images']) ? $options['auto_upload_images'] : true); ?>
/>
<label for="auto_upload_images" class="toggle-label"></label>
</div>
<label for="auto_upload_images">
<?php esc_html_e('Enable Auto Upload Images', 'seoprostack'); ?>
</label>
</div>
</div>
<p class="seoprostack-setting-description">
<?php esc_html_e('Import images that have external URLs into your Media Library when saving content. Consider disabling during large data imports with many external image URLs.', 'seoprostack'); ?>
</p>
</div>
<div class="seoprostack-toggle-settings">
<div class="seoprostack-setting-row">
<label for="max_width"><?php esc_html_e('Max Width', 'seoprostack'); ?></label>
<input type="number"
id="max_width"
name="seoprostack_workflow_options[max_width]"
value="<?php echo esc_attr(isset($options['max_width']) ? $options['max_width'] : 1200); ?>"
/>
<p class="description"><?php esc_html_e('Maximum width for uploaded images in pixels.', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-setting-row">
<label for="max_height"><?php esc_html_e('Max Height', 'seoprostack'); ?></label>
<input type="number"
id="max_height"
name="seoprostack_workflow_options[max_height]"
value="<?php echo esc_attr(isset($options['max_height']) ? $options['max_height'] : 1200); ?>"
/>
<p class="description"><?php esc_html_e('Maximum height for uploaded images in pixels.', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-setting-row">
<label for="exclude_urls"><?php esc_html_e('Exclude URLs', 'seoprostack'); ?></label>
<textarea id="exclude_urls"
name="seoprostack_workflow_options[exclude_urls]"
rows="3"
class="large-text"
><?php echo esc_textarea(isset($options['exclude_urls']) ? $options['exclude_urls'] : ''); ?></textarea>
<p class="description"><?php esc_html_e('Enter domains to exclude (one per line). Images from these domains will not be imported.', 'seoprostack'); ?></p>
</div>
<div class="seoprostack-setting-row">
<label for="image_name_pattern"><?php esc_html_e('Image Name Pattern', 'seoprostack'); ?></label>
<input type="text"
id="image_name_pattern"
name="seoprostack_workflow_options[image_name_pattern]"
value="<?php echo esc_attr(isset($options['image_name_pattern']) ? $options['image_name_pattern'] : '%filename%'); ?>"
class="regular-text"
/>
<p class="description">
<?php esc_html_e('Available patterns:', 'seoprostack'); ?> %filename%, %post_id%, %postname%, %timestamp%, %date%, %year%, %month%, %day%
</p>
</div>
<div class="seoprostack-setting-row">
<label for="image_alt_pattern"><?php esc_html_e('Image Alt Pattern', 'seoprostack'); ?></label>
<input type="text"
id="image_alt_pattern"
name="seoprostack_workflow_options[image_alt_pattern]"
value="<?php echo esc_attr(isset($options['image_alt_pattern']) ? $options['image_alt_pattern'] : '%filename%'); ?>"
class="regular-text"
/>
<p class="description">
<?php esc_html_e('Available patterns:', 'seoprostack'); ?> %filename%, %post_title%, %post_id%, %postname%, %timestamp%
</p>
</div>
</div>
</div>
<div class="seoprostack-setting-actions">
<button type="submit" class="button button-primary">
<?php esc_html_e('Save Changes', 'seoprostack'); ?>
</button>
</div>
</div>
</form>
</div>
<?php
}
}

View File

@ -2,10 +2,19 @@
/** /**
* Auto Upload Images functionality * Auto Upload Images functionality
* *
* @package WP_Allstars * @package SEO_Pro_Stack
* @deprecated 1.0.0 Use the class in includes/features/auto-upload/class-seoprostack-auto-upload.php instead
*/ */
class WP_Allstars_Auto_Upload { // If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* @deprecated 1.0.0 Use SEOProStack_Auto_Upload instead
*/
class SEOProStack_Auto_Upload_Legacy {
/** /**
* Initialize the class * Initialize the class
*/ */
@ -118,7 +127,7 @@ class WP_Allstars_Auto_Upload {
*/ */
public function log_error($url, $error) { public function log_error($url, $error) {
error_log(sprintf( error_log(sprintf(
'[WP ALLSTARS] Auto Upload Images Error - URL: %s, Error: %s', '[SEO Pro Stack] Auto Upload Images Error - URL: %s, Error: %s',
$url, $url,
$error $error
)); ));

View File

@ -0,0 +1,69 @@
<?php
/**
* Autoloader for SEO Pro Stack plugin.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Core
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* Class SEOProStack_Autoloader
*
* Handles autoloading of plugin classes.
*/
class SEOProStack_Autoloader {
/**
* Register the autoloader
*/
public static function register() {
spl_autoload_register(array(self::class, 'autoload'));
}
/**
* Autoload a class file based on its name
*
* @param string $class_name The name of the class to load.
*/
public static function autoload($class_name) {
// Check if the class should be loaded by this autoloader
if (false === strpos($class_name, 'SEOProStack')) {
return;
}
// Convert class name to filename
$file_path = str_replace('SEOProStack_', '', $class_name);
$file_path = str_replace('_', '-', $file_path);
$file_path = strtolower($file_path);
// Add 'class-' prefix
$file_path = 'class-' . $file_path . '.php';
// Base paths to check for classes
$base_paths = array(
SEOPROSTACK_PLUGIN_DIR . 'includes/',
SEOPROSTACK_PLUGIN_DIR . 'includes/core/',
SEOPROSTACK_PLUGIN_DIR . 'includes/features/',
SEOPROSTACK_PLUGIN_DIR . 'includes/features/auto-upload/',
SEOPROSTACK_PLUGIN_DIR . 'admin/',
SEOPROSTACK_PLUGIN_DIR . 'admin/settings/',
SEOPROSTACK_PLUGIN_DIR . 'admin/settings/ajax/',
SEOPROSTACK_PLUGIN_DIR . 'admin/settings/tabs/',
);
// Try to find and load the file
foreach ($base_paths as $base_path) {
$full_path = $base_path . $file_path;
if (file_exists($full_path)) {
require_once $full_path;
return;
}
}
}
}
SEOProStack_Autoloader::register();

View File

@ -0,0 +1,102 @@
<?php
/**
* Register all actions and filters for the plugin.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Core
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* Register all actions and filters for the plugin.
*/
class SEOProStack_Loader {
/**
* The array of actions registered with WordPress.
*
* @var array $actions The actions registered with WordPress.
*/
protected $actions;
/**
* The array of filters registered with WordPress.
*
* @var array $filters The filters registered with WordPress.
*/
protected $filters;
/**
* Initialize the collections used to maintain the actions and filters.
*/
public function __construct() {
$this->actions = array();
$this->filters = array();
}
/**
* Add a new action to the collection.
*
* @param string $hook The name of the WordPress action that is being registered.
* @param object $component A reference to the instance of the object.
* @param string $callback The name of the function definition on the component.
* @param int $priority Optional. The priority at which the function should be fired. Default is 10.
* @param int $accepted_args Optional. The number of arguments that should be passed to the callback. Default is 1.
*/
public function add_action($hook, $component, $callback, $priority = 10, $accepted_args = 1) {
$this->actions = $this->add($this->actions, $hook, $component, $callback, $priority, $accepted_args);
}
/**
* Add a new filter to the collection.
*
* @param string $hook The name of the WordPress filter that is being registered.
* @param object $component A reference to the instance of the object.
* @param string $callback The name of the function definition on the component.
* @param int $priority Optional. The priority at which the function should be fired. Default is 10.
* @param int $accepted_args Optional. The number of arguments that should be passed to the callback. Default is 1.
*/
public function add_filter($hook, $component, $callback, $priority = 10, $accepted_args = 1) {
$this->filters = $this->add($this->filters, $hook, $component, $callback, $priority, $accepted_args);
}
/**
* A utility function that is used to register the actions and hooks.
*
* @param array $hooks The collection of hooks that is being registered.
* @param string $hook The name of the WordPress filter that is being registered.
* @param object $component A reference to the instance of the object.
* @param string $callback The name of the function definition on the component.
* @param int $priority The priority at which the function should be fired.
* @param int $accepted_args The number of arguments that should be passed to the callback.
* @return array The collection of actions and filters registered.
*/
private function add($hooks, $hook, $component, $callback, $priority, $accepted_args) {
$hooks[] = array(
'hook' => $hook,
'component' => $component,
'callback' => $callback,
'priority' => $priority,
'accepted_args' => $accepted_args,
);
return $hooks;
}
/**
* Register the filters and actions with WordPress.
*/
public function run() {
foreach ($this->filters as $hook) {
add_filter($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'], $hook['accepted_args']);
}
foreach ($this->actions as $hook) {
add_action($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'], $hook['accepted_args']);
}
}
}

View File

@ -0,0 +1,69 @@
<?php
/**
* The core plugin class.
*
* @package SEO_Pro_Stack
* @subpackage SEO_Pro_Stack/Core
*/
// If this file is called directly, abort.
if (!defined('ABSPATH')) {
exit;
}
/**
* The core plugin class.
*/
class SEOProStack_Plugin {
/**
* The loader that's responsible for maintaining and registering all hooks.
*
* @var SEOProStack_Loader $loader Maintains and registers all hooks.
*/
protected $loader;
/**
* Define the core functionality of the plugin.
*/
public function __construct() {
$this->load_dependencies();
$this->define_admin_hooks();
$this->define_features();
}
/**
* Load the required dependencies for this plugin.
*/
private function load_dependencies() {
// The class responsible for orchestrating the actions and filters
require_once SEOPROSTACK_PLUGIN_DIR . 'includes/core/class-seoprostack-loader.php';
$this->loader = new SEOProStack_Loader();
}
/**
* Register all of the hooks related to the admin area.
*/
private function define_admin_hooks() {
// Admin functionality
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/class-seoprostack-admin.php';
$admin = new SEOProStack_Admin();
$admin->initialize();
}
/**
* Register all of the hooks related to plugin features.
*/
private function define_features() {
// Auto Upload feature
require_once SEOPROSTACK_PLUGIN_DIR . 'includes/features/auto-upload/class-seoprostack-auto-upload.php';
$auto_upload = new SEOProStack_Auto_Upload();
}
/**
* Run the loader to execute all of the hooks with WordPress.
*/
public function run() {
$this->loader->run();
}
}

View File

@ -0,0 +1,136 @@
<?php
/**
* Auto Upload Images functionality
*
* @package SEO_Pro_Stack
*/
class SEOProStack_Auto_Upload {
/**
* Initialize the class
*/
public function __construct() {
add_filter('content_save_pre', array($this, 'process_content'), 10, 1);
// New action name
add_action('wp_seoprostack_image_upload_error', array($this, 'log_error'), 10, 2);
// Backward compatibility
add_action('wp_allstars_image_upload_error', array($this, 'log_error'), 10, 2);
}
/**
* Process content for external images
*
* @param string $content The post content
* @return string Modified content with local image URLs
*/
public function process_content($content) {
// Check if auto upload is enabled - support both option names for backward compatibility
$seoprostack_options = get_option('wp_seoprostack_workflow_options', null);
$allstars_options = get_option('wp_allstars_workflow_options', array('auto_upload_images' => false));
// Use new options if they exist, otherwise fall back to old options
$options = $seoprostack_options !== null ? $seoprostack_options : $allstars_options;
if (!$options['auto_upload_images']) {
return $content;
}
// Regular expression to find image URLs
$pattern = '/<img[^>]+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) {
// Fire both actions for backward compatibility
do_action('wp_seoprostack_image_upload_error', $url, $e->getMessage());
do_action('wp_allstars_image_upload_error', $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
*/
private function upload_image($url) {
// Get file info
$file_array = array();
$file_array['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
$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
$attachment_id = media_handle_sideload($file_array, 0);
if (is_wp_error($attachment_id)) {
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) {
error_log(sprintf(
'[SEO Pro Stack] Auto Upload Images Error - URL: %s, Error: %s',
$url,
$error
));
}
}

View File

@ -1,97 +0,0 @@
<?php
/**
* Plugin Name: WP ALLSTARS Plugin
* Plugin URI: https://www.wpallstars.com
* Description: WP ALLSTARS Plugin for WordPress. Speed Matters.
* Version: 0.1.0 (Beta)
* Author: WP ALLSTARS
* Author URI: https://www.wpallstars.com
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
* Text Domain: wp-allstars
* Domain Path: /languages
* Requires at least: 5.0
* Requires PHP: 7.2
*/
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
// Define plugin version - extract from plugin header
if (!function_exists('get_plugin_data')) {
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
}
// Define the version constant - first try get_plugin_data() if available,
// otherwise fall back to direct string extraction
if (function_exists('get_plugin_data')) {
$plugin_data = get_plugin_data(__FILE__, false, false);
define('WP_ALLSTARS_VERSION', $plugin_data['Version']);
} else {
// Manual extraction as fallback
$plugin_file = file_get_contents(__FILE__);
preg_match('/Version:\s*([^\s]+)/i', $plugin_file, $matches);
define('WP_ALLSTARS_VERSION', isset($matches[1]) ? $matches[1] : '0.1.0 (Beta)');
}
// Activation hook
function wp_allstars_activate() {
// Add activation logic later if needed
}
register_activation_hook( __FILE__, 'wp_allstars_activate' );
// Load core functionality
require_once plugin_dir_path(__FILE__) . 'includes/class-wp-allstars-auto-upload.php';
// Load admin UI and configurations
if ( is_admin() ) {
require_once plugin_dir_path( __FILE__ ) . 'admin/pro-plugins-config.php';
require_once plugin_dir_path( __FILE__ ) . 'admin/settings.php';
}
// This function is not needed as we're localizing in wp_allstars_admin_assets
// function wp_allstars_localize_script() {
// wp_localize_script( 'wp-allstars-admin', 'wpAllstars', [
// 'ajaxurl' => admin_url( 'admin-ajax.php' ),
// 'nonce' => wp_create_nonce( 'wp-allstars-nonce' )
// ] );
// }
// add_action( 'admin_enqueue_scripts', 'wp_allstars_localize_script' );
// Admin assets
function wp_allstars_admin_assets() {
// Enqueue styles
wp_enqueue_style(
'wp-allstars-admin',
plugins_url( 'admin/css/wp-allstars-admin.css', __FILE__ ),
array(),
WP_ALLSTARS_VERSION
);
// Enqueue script
// Enqueue WordPress updates script for theme installation
wp_enqueue_script('updates');
wp_enqueue_script(
'wp-allstars-admin',
plugins_url( 'admin/js/wp-allstars-admin.js', __FILE__ ),
array('jquery', 'updates'),
WP_ALLSTARS_VERSION,
true
);
// Localize script for AJAX
$ajax_data = array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'adminUrl' => admin_url(),
'nonce' => wp_create_nonce( 'wp-allstars-nonce' ),
'updateNonce' => wp_create_nonce( 'updates' )
);
wp_localize_script( 'wp-allstars-admin', 'wpAllstars', $ajax_data );
}
add_action( 'admin_enqueue_scripts', 'wp_allstars_admin_assets' );
// Initialize classes
$wp_allstars_auto_upload = new WP_Allstars_Auto_Upload();

93
wp-seoprostack-plugin.php Normal file
View File

@ -0,0 +1,93 @@
<?php
/**
* Plugin Name: SEO Pro Stack
* Plugin URI: https://www.seoprostack.com
* Description: SEO Pro Stack Plugin for WordPress. Speed Matters.
* Version: 1.0.0
* Author: SEO Pro Stack
* Author URI: https://www.seoprostack.com
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
* Text Domain: seoprostack
* Domain Path: /languages
* Requires at least: 5.0
* Requires PHP: 7.2
*/
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
// Define plugin version - extract from plugin header
if (!function_exists('get_plugin_data')) {
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
}
// Define the version constant - first try get_plugin_data() if available,
// otherwise fall back to direct string extraction
if (function_exists('get_plugin_data')) {
$plugin_data = get_plugin_data(__FILE__, false, false);
define('SEOPROSTACK_VERSION', $plugin_data['Version']);
} else {
// Manual extraction as fallback
$plugin_file = file_get_contents(__FILE__);
preg_match('/Version:\s*([^\s]+)/i', $plugin_file, $matches);
define('SEOPROSTACK_VERSION', isset($matches[1]) ? $matches[1] : '1.0.0');
}
define('SEOPROSTACK_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('SEOPROSTACK_PLUGIN_URL', plugin_dir_url(__FILE__));
define('SEOPROSTACK_PLUGIN_BASENAME', plugin_basename(__FILE__));
// Activation hook
function seoprostack_activate() {
// Add activation logic later if needed
}
register_activation_hook( __FILE__, 'seoprostack_activate' );
// Load core functionality
require_once SEOPROSTACK_PLUGIN_DIR . 'includes/features/auto-upload/class-seoprostack-auto-upload.php';
// Load admin UI and configurations
if ( is_admin() ) {
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/pro-plugins-config.php';
require_once SEOPROSTACK_PLUGIN_DIR . 'admin/settings.php';
}
// Admin assets
function seoprostack_admin_assets() {
// Enqueue styles
wp_enqueue_style(
'seoprostack-admin',
SEOPROSTACK_PLUGIN_URL . 'admin/css/seoprostack-admin.css',
array(),
SEOPROSTACK_VERSION
);
// Enqueue WordPress updates script for theme installation
wp_enqueue_script('updates');
wp_enqueue_script(
'seoprostack-admin',
SEOPROSTACK_PLUGIN_URL . 'admin/js/seoprostack-admin.js',
array('jquery', 'updates'),
SEOPROSTACK_VERSION,
true
);
// Localize script for AJAX
$ajax_data = array(
'ajaxurl' => admin_url('admin-ajax.php'),
'adminUrl' => admin_url(),
'nonce' => wp_create_nonce('seoprostack-nonce'),
'updateNonce' => wp_create_nonce('updates')
);
wp_localize_script('seoprostack-admin', 'wpSeoProStack', $ajax_data);
}
add_action('admin_enqueue_scripts', 'seoprostack_admin_assets');
// Initialize classes
$seoprostack_auto_upload = new SEOProStack_Auto_Upload();