Compare commits
148 Commits
main
...
v0.2.3.1-s
Author | SHA1 | Date | |
---|---|---|---|
d490604513 | |||
e57f22f277 | |||
bae13ca936 | |||
c597f21818 | |||
0fdb2a60e2 | |||
b74d8112ca | |||
05ff272b51 | |||
e19dfecd6c | |||
ff306ed32c | |||
bcb4a7e05b | |||
0d3c497b23 | |||
e2bfefc6f6 | |||
5652ae2ad3 | |||
394cefa3cf | |||
d9a06e3813 | |||
f5a17e343e | |||
63c2b7231a | |||
e1e8e19946 | |||
291cbe34f5 | |||
62f368756a | |||
4153564acb | |||
7eef6caab8 | |||
d464d4cbe8 | |||
817b564813 | |||
4f88de74f6 | |||
2998604468 | |||
d89ecc5548 | |||
89009dca92 | |||
a374f26e34 | |||
d9b136f925 | |||
576d79b1e7 | |||
a467a6aa10 | |||
1f885f1745 | |||
2158855a1a | |||
233006f155 | |||
4e951f1fb7 | |||
fd78d35186 | |||
fba03d6e43 | |||
9b307f1b9d | |||
894a31d5b6 | |||
01740ed72c | |||
bbb0dc377a | |||
8e6371fe9d | |||
d9413aff1c | |||
f1c3087900 | |||
2d644e9c37 | |||
fbb4cb69ba | |||
7a3b8a948f | |||
d8130b1e19 | |||
b069bf3f3c | |||
ba0878b230 | |||
4f391f0cda | |||
d5a4a29ae9 | |||
daccb54342 | |||
90f6969e1b | |||
f7b8629926 | |||
aac7ac1195 | |||
6528d8e79a | |||
21b0ef599d | |||
5f45ea85fa | |||
c3d1aff49f | |||
d389f92bd6 | |||
23c5d0adce | |||
1384145138 | |||
169b226a39 | |||
69ad1d55a7 | |||
42150fe694 | |||
6040c1b5bd | |||
1224937955 | |||
34b09de04e | |||
41adfb56e4 | |||
f03da91142 | |||
69623d2660 | |||
e90f6168ed | |||
eb768d9090 | |||
1b548a59e2 | |||
03d9511f4b | |||
2b01f3523f | |||
016f6000a6 | |||
1cf243d5e1 | |||
09aebfcc98 | |||
e00c627410 | |||
c16e1d62fd | |||
ad2aba88a3 | |||
4de39fbd85 | |||
ea881f7691 | |||
19cd4d3355 | |||
5a28089043 | |||
9cd079206f | |||
a82bd8b3f4 | |||
7c6afdc8c7 | |||
f8c098b5a1 | |||
1eb732684b | |||
a4b594c0e2 | |||
5f90586044 | |||
a2b7ba6d72 | |||
e83dbcfff7 | |||
28f87f689e | |||
5f195f8cfb | |||
d2e8cc858c | |||
dc6b1a046f | |||
221eefab9e | |||
a81b6ac5a7 | |||
634f29eee7 | |||
e94a1d902d | |||
1c477aa0f2 | |||
9108a5345c | |||
16d0d5e2ef | |||
8fa4b67da9 | |||
673d4a60fd | |||
4d671d5901 | |||
0c96faaf60 | |||
83d7debe54 | |||
ccc57dc72b | |||
f0d00accaf | |||
19e6455abb | |||
f7fb0c6545 | |||
9e1c077080 | |||
4bbcbe3d12 | |||
46696eff87 | |||
8cef4c8868 | |||
da5d08587c | |||
c2276f4ebd | |||
b267156b68 | |||
ddd64643c4 | |||
ddd2846171 | |||
4fe9d45eba | |||
ad489bddb5 | |||
5fdc3e277c | |||
096c9be284 | |||
2b4e3cecd3 | |||
d280ec197b | |||
5352b38348 | |||
2405f98eb8 | |||
24ffdf8950 | |||
93c3290b63 | |||
436a829646 | |||
20fb06a29e | |||
8fa2b00d7a | |||
f0ffa7e552 | |||
55d092d568 | |||
1b02e8eb24 | |||
c8835de92f | |||
d9c710969b | |||
2c68b66dbc | |||
9b0e7acd2d | |||
930530cc96 | |||
ecd3887bb9 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -38,7 +38,7 @@ $RECYCLE.BIN/
|
|||||||
.git_status_temp.txt
|
.git_status_temp.txt
|
||||||
project-documents/
|
project-documents/
|
||||||
reference-plugins/
|
reference-plugins/
|
||||||
*.bak
|
*.bak*
|
||||||
node_modules/
|
node_modules/
|
||||||
composer.lock
|
composer.lock
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
111
DEVELOPMENT.md
Normal file
111
DEVELOPMENT.md
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
# WP Allstars Plugin Development Workflow
|
||||||
|
|
||||||
|
This document outlines the development workflow for the WP Allstars Plugin to ensure stable and reliable feature implementation.
|
||||||
|
|
||||||
|
## Development Principles
|
||||||
|
|
||||||
|
1. **Stability First**: The primary goal is maintaining a stable plugin that works reliably
|
||||||
|
2. **Incremental Changes**: Implement changes in small, manageable increments
|
||||||
|
3. **Complete Testing**: Every change must be thoroughly tested before integration
|
||||||
|
4. **Documentation**: All features and changes must be well-documented
|
||||||
|
|
||||||
|
## Branch Structure
|
||||||
|
|
||||||
|
- `main` - Production-ready code, always stable
|
||||||
|
- `v0.2.3-stable` - Our current stable development branch
|
||||||
|
- `feature/v0.2.3-stable/{feature-name}` - Feature branches for new development
|
||||||
|
|
||||||
|
## Development Workflow
|
||||||
|
|
||||||
|
### 1. Feature Planning
|
||||||
|
|
||||||
|
1. Identify a feature from the ROADMAP.md file to implement
|
||||||
|
2. Review any existing implementation in unstable versions
|
||||||
|
3. Document the implementation plan in ROADMAP.md
|
||||||
|
4. Create a new feature branch from the stable base
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout v0.2.3-stable
|
||||||
|
git checkout -b feature/v0.2.3-stable/sync-guard
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Feature Implementation
|
||||||
|
|
||||||
|
1. Start with the smallest possible functional change
|
||||||
|
2. Commit frequently with descriptive commit messages including stability classification
|
||||||
|
3. Example commit message format:
|
||||||
|
```
|
||||||
|
[EXPERIMENTAL] Add basic sync guard detection functionality
|
||||||
|
|
||||||
|
- Adds file existence check for .syncing flag
|
||||||
|
- Implements conditional loading based on flag
|
||||||
|
- Does not yet handle admin notices
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Reference the ROADMAP.md and TESTING.md documents while implementing
|
||||||
|
|
||||||
|
### 3. Testing
|
||||||
|
|
||||||
|
1. Complete all relevant tests from TESTING.md
|
||||||
|
2. Add feature-specific tests if needed
|
||||||
|
3. Test in a clean WordPress environment
|
||||||
|
4. Test with WP_DEBUG enabled
|
||||||
|
5. Document any issues found and fix them
|
||||||
|
|
||||||
|
### 4. Code Review
|
||||||
|
|
||||||
|
1. Self-review code for:
|
||||||
|
- PHP best practices
|
||||||
|
- WordPress coding standards
|
||||||
|
- Security considerations
|
||||||
|
- Performance implications
|
||||||
|
- Error handling
|
||||||
|
|
||||||
|
2. Consider peer review if possible
|
||||||
|
|
||||||
|
### 5. Integration
|
||||||
|
|
||||||
|
1. Create a pull request to merge into the stable branch
|
||||||
|
2. Summarize changes, testing performed, and any caveats
|
||||||
|
3. Once approved, merge using `--no-ff` to preserve feature history
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout v0.2.3-stable
|
||||||
|
git merge --no-ff feature/v0.2.3-stable/sync-guard
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Tag new version if appropriate:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git tag v0.2.3.1-stable
|
||||||
|
git push origin v0.2.3.1-stable
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Update STABILITY.md with the new version information
|
||||||
|
|
||||||
|
### 6. Post-Integration
|
||||||
|
|
||||||
|
1. Deploy to test environment and confirm functionality
|
||||||
|
2. Update ROADMAP.md to reflect the implemented feature
|
||||||
|
3. Clean up feature branch if no longer needed
|
||||||
|
|
||||||
|
## Handling Unstable Code References
|
||||||
|
|
||||||
|
When examining code from unstable versions:
|
||||||
|
|
||||||
|
1. **Never copy-paste directly** - Understand the approach and reimplement
|
||||||
|
2. **Isolate problematic code** - Identify why it might have failed
|
||||||
|
3. **Take the best ideas** - Implement the concept, not the exact implementation
|
||||||
|
4. **Document the reference** - Note which version inspired each implementation
|
||||||
|
|
||||||
|
## Versioning Scheme
|
||||||
|
|
||||||
|
- `vX.Y.Z` - Major.Minor.Patch
|
||||||
|
- `vX.Y.Z-stable` - Stable development branches
|
||||||
|
- `vX.Y.Z.N-stable` - Minor updates to stable branches
|
||||||
|
|
||||||
|
## Continuous Improvement
|
||||||
|
|
||||||
|
- Regularly review and update these development procedures
|
||||||
|
- Document lessons learned
|
||||||
|
- Improve testing procedures based on discoveries
|
144
README.md
144
README.md
@ -1,19 +1,19 @@
|
|||||||
# SEO Pro Stack
|
# WP Allstars
|
||||||
|
|
||||||
A WordPress plugin that enhances your WordPress site's SEO capabilities with curated tools, themes, hosting recommendations, and optimization features.
|
A WordPress plugin that enhances your WordPress experience with curated plugins, themes, and optimization tools.
|
||||||
|
Testing a stable v0.2.3 version with rsync deployment.
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Pro Plugin Recommendations**: Browse and discover premium SEO and performance plugins with detailed information.
|
- **Curated Plugin Recommendations**: Browse and install recommended free plugins organized by category.
|
||||||
- **Theme Recommendations**: Find SEO-friendly themes that are optimized for performance and user experience.
|
- **Pro Plugin Showcase**: Discover premium plugins with direct links to purchase.
|
||||||
- **Hosting Recommendations**: Choose the best hosting providers optimized for WordPress and SEO performance.
|
- **Theme Integration**: Easily install and activate the Kadence theme.
|
||||||
- **Advanced Settings**: Fine-tune your WordPress installation with SEO-focused configuration options.
|
- **Workflow Optimization**: Tools to streamline your WordPress workflow.
|
||||||
- **Tools**: Optimize your database, generate robots.txt, and access other helpful SEO utilities.
|
- **Advanced Settings**: Fine-tune your WordPress installation with advanced configuration options.
|
||||||
- **Auto Upload**: Automatically upload and organize images for better content management.
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@ -24,86 +24,90 @@ SEO Pro Stack is a powerful WordPress plugin designed to help site owners and de
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
After activation, you'll find the SEO Pro Stack menu in your WordPress admin sidebar. The plugin includes several tabs:
|
After activation, you'll find the WP Allstars menu in your WordPress admin sidebar. The plugin includes several tabs:
|
||||||
|
|
||||||
### Pro Plugins
|
### General
|
||||||
|
|
||||||
Discover premium plugins specifically chosen to enhance your site's SEO performance:
|
Basic settings for the plugin, including:
|
||||||
- SEO Plugins
|
- Auto Upload Images
|
||||||
- Performance Plugins
|
- Image Optimization
|
||||||
- Content Plugins
|
- Cache Management
|
||||||
- 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
|
|
||||||
|
|
||||||
### Recommended Plugins
|
- Performance Settings
|
||||||
|
- Security Enhancements
|
||||||
|
- Development Tools
|
||||||
|
|
||||||
Free and beneficial plugins that complement the SEO Pro Stack ecosystem:
|
### Workflow
|
||||||
- Essential plugin recommendations
|
|
||||||
- Plugin compatibility information
|
|
||||||
- Simplified installation process
|
|
||||||
|
|
||||||
### Hosting
|
Tools to improve your WordPress workflow:
|
||||||
|
|
||||||
Recommendations for WordPress hosting providers optimized for SEO:
|
- Content Management
|
||||||
- Managed WordPress hosting
|
- Media Handling
|
||||||
- Performance-focused hosting
|
- Site Maintenance
|
||||||
- Hosting provider comparisons
|
|
||||||
- Special offers and discounts
|
|
||||||
|
|
||||||
### Tools
|
### Free Plugins
|
||||||
|
|
||||||
Utilities to help optimize your WordPress site:
|
Browse and install recommended free plugins organized by categories:
|
||||||
- Database optimization
|
|
||||||
- Robots.txt generator
|
|
||||||
- SEO audit tools
|
|
||||||
- Cache management
|
|
||||||
|
|
||||||
## File Structure
|
- Minimal
|
||||||
|
- Admin
|
||||||
|
- AI
|
||||||
|
- CMS
|
||||||
|
- Compliance
|
||||||
|
- CRM
|
||||||
|
- Ecommerce
|
||||||
|
- LMS
|
||||||
|
- Media
|
||||||
|
- SEO
|
||||||
|
- Setup
|
||||||
|
- Social
|
||||||
|
- Speed
|
||||||
|
- Translation
|
||||||
|
- Advanced
|
||||||
|
- Debug
|
||||||
|
|
||||||
The plugin follows a modular structure for better maintainability:
|
### Pro Plugins
|
||||||
|
|
||||||
```
|
Discover premium plugins with direct links to purchase.
|
||||||
wp-seoprostack-plugin/
|
|
||||||
├── admin/
|
|
||||||
│ ├── css/
|
|
||||||
│ ├── images/
|
|
||||||
│ │ ├── hosting/
|
|
||||||
│ │ └── themes/
|
|
||||||
│ ├── js/
|
|
||||||
│ └── settings/
|
|
||||||
│ ├── ajax/
|
|
||||||
│ └── tabs/
|
|
||||||
├── includes/
|
|
||||||
│ ├── core/
|
|
||||||
│ └── features/
|
|
||||||
└── public/
|
|
||||||
```
|
|
||||||
|
|
||||||
## Requirements
|
### Theme
|
||||||
|
|
||||||
- WordPress 5.0 or higher
|
Easily install and activate the Kadence theme.
|
||||||
- PHP 7.2 or higher
|
|
||||||
|
|
||||||
## Changelog
|
## Development
|
||||||
|
|
||||||
### 1.0.0
|
### Requirements
|
||||||
- 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 Marcus QuinnTest sync after hook update
|
Developed by [Your Name/Company]
|
||||||
|
|
||||||
|
## 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`
|
||||||
|
|
||||||
|
#
|
51
ROADMAP.md
Normal file
51
ROADMAP.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# WP Allstars Plugin Development Roadmap
|
||||||
|
|
||||||
|
This document outlines features from later versions that we plan to integrate into our stable development branch. The goal is to incrementally implement these features in a stable manner, without introducing critical errors.
|
||||||
|
|
||||||
|
## Feature Backlog
|
||||||
|
|
||||||
|
| Feature | Source Version | Priority | Complexity | Risk | Status |
|
||||||
|
|---------|----------------|----------|------------|------|--------|
|
||||||
|
| Multisite Category | v0.2.6 | High | Low | Low | ✅ Implemented in v0.2.3-stable |
|
||||||
|
| Sync Guard | v0.2.6-fix | High | Low | Low | 🔄 To be implemented |
|
||||||
|
| More Robust File Loading | v0.2.6-fix | High | Low | Low | ✅ Implemented in v0.2.3-stable |
|
||||||
|
| Enhanced Admin UI | v0.2.4+ | Medium | Medium | Medium | 🔄 To be implemented |
|
||||||
|
| Plugin Dashboard | v0.2.6-fix | Medium | Medium | Medium | 🔄 To be implemented |
|
||||||
|
| New Category Pages | v0.2.4+ | Medium | Low | Low | 🔄 To be implemented |
|
||||||
|
|
||||||
|
## Implementation Strategy
|
||||||
|
|
||||||
|
### Multisite Category with Network Plugin Auditor
|
||||||
|
- **Description**: Add a "Multisite" filter after Advanced and include network-plugin-auditor
|
||||||
|
- **Why it failed before**: Didn't properly update all required files for the feature
|
||||||
|
- **Implementation plan**: Add to free-plugins.php and update class-free-plugins-manager.php to display the category correctly
|
||||||
|
- **Testing criteria**: Verify category appears in UI and plugin can be installed
|
||||||
|
|
||||||
|
### Sync Guard
|
||||||
|
- **Description**: Prevent plugin loading during rsync operations to avoid partial file loading
|
||||||
|
- **Why it failed before**: Added to wrong location, dependent on missing files
|
||||||
|
- **Implementation plan**:
|
||||||
|
1. Create a simpler version of the sync guard
|
||||||
|
2. Update post-commit hook to handle sync operations better
|
||||||
|
3. Use file flag to signal when sync is in progress
|
||||||
|
- **Testing criteria**: Verify plugin doesn't attempt to load during sync operations
|
||||||
|
|
||||||
|
### Enhanced Admin UI
|
||||||
|
- **Description**: Improve the admin interface with better styling and more intuitive navigation
|
||||||
|
- **Why it failed before**: Too many changes at once without proper testing
|
||||||
|
- **Implementation plan**:
|
||||||
|
1. Small, incremental UI improvements
|
||||||
|
2. Focus on one component at a time
|
||||||
|
3. Thorough testing after each change
|
||||||
|
- **Testing criteria**: UI changes shouldn't affect functionality, should be responsive
|
||||||
|
|
||||||
|
## Development Order
|
||||||
|
|
||||||
|
The suggested implementation order is:
|
||||||
|
|
||||||
|
1. Sync Guard
|
||||||
|
2. Enhanced Admin UI (component by component)
|
||||||
|
3. Plugin Dashboard improvements
|
||||||
|
4. New Category Pages
|
||||||
|
|
||||||
|
Each feature should be developed in its own branch and only merged after thorough testing.
|
32
STABILITY.md
Normal file
32
STABILITY.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# WP Allstars Plugin Stability Status
|
||||||
|
|
||||||
|
This document tracks the stability status of different versions of the WP Allstars Plugin.
|
||||||
|
|
||||||
|
## Stability Classification
|
||||||
|
|
||||||
|
- **[STABLE]**: Thoroughly tested, works as expected in production environments
|
||||||
|
- **[FUNCTIONAL]**: Works but may have minor issues or incomplete features
|
||||||
|
- **[EXPERIMENTAL]**: Contains new features that are not fully tested
|
||||||
|
- **[UNSTABLE]**: Known to have critical issues that affect functionality
|
||||||
|
|
||||||
|
## Version Status
|
||||||
|
|
||||||
|
| Version | Status | Notes |
|
||||||
|
|---------|--------|-------|
|
||||||
|
| v0.2.3-stable-base | **[STABLE]** | Base stable version with robust file loading. All core functionality works properly. |
|
||||||
|
| v0.2.4 | **[UNSTABLE]** | Contains critical errors - reference only for feature ideas. |
|
||||||
|
| v0.2.6 | **[UNSTABLE]** | Contains file structure issues and critical errors - reference only for feature ideas. |
|
||||||
|
| v0.2.6-fix | **[UNSTABLE]** | Attempted fixes but still has issues - reference only. |
|
||||||
|
| v0.2.6-revert | **[UNSTABLE]** | Failed attempt to revert to stable version - do not use. |
|
||||||
|
|
||||||
|
## Current Development
|
||||||
|
|
||||||
|
Current development is based on the v0.2.3-stable-base version. Features from later versions are being analyzed and reimplemented in a stable manner.
|
||||||
|
|
||||||
|
## Stability Guidelines
|
||||||
|
|
||||||
|
1. All new features must be developed in isolated feature branches
|
||||||
|
2. Comprehensive testing is required before merging
|
||||||
|
3. Each feature should be implemented as a series of small, atomic commits
|
||||||
|
4. All commits should include a stability classification in commit messages: [STABLE], [FUNCTIONAL], etc.
|
||||||
|
5. Full testing checklist must be completed before marking a version as [STABLE]
|
70
TESTING.md
Normal file
70
TESTING.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# WP Allstars Plugin Testing Procedures
|
||||||
|
|
||||||
|
This document outlines the testing procedures for the WP Allstars Plugin to ensure stability and reliability.
|
||||||
|
|
||||||
|
## Pre-Merge Testing Checklist
|
||||||
|
|
||||||
|
### Basic Functionality Tests
|
||||||
|
|
||||||
|
- [ ] Plugin activates without errors
|
||||||
|
- [ ] Plugin deactivates without errors
|
||||||
|
- [ ] Admin menu appears correctly
|
||||||
|
- [ ] All submenu items load without errors
|
||||||
|
- [ ] Settings can be saved without errors
|
||||||
|
- [ ] Plugin works with WordPress debug mode enabled
|
||||||
|
|
||||||
|
### Feature-Specific Tests
|
||||||
|
|
||||||
|
Each new feature should have its own testing checklist added here.
|
||||||
|
|
||||||
|
#### Multisite Category Feature
|
||||||
|
|
||||||
|
- [ ] "Multisite" category appears in the correct location in the UI
|
||||||
|
- [ ] Network Plugin Auditor appears in the Multisite category
|
||||||
|
- [ ] Category filter works when clicked
|
||||||
|
- [ ] Plugin can be installed from the category
|
||||||
|
|
||||||
|
#### Sync Guard Feature
|
||||||
|
|
||||||
|
- [ ] Plugin doesn't load when .syncing file is present
|
||||||
|
- [ ] .syncing file is created during sync operations
|
||||||
|
- [ ] .syncing file is removed after sync completes
|
||||||
|
- [ ] User is notified when plugin is in sync mode
|
||||||
|
|
||||||
|
### Compatibility Tests
|
||||||
|
|
||||||
|
- [ ] Plugin works with latest WordPress version
|
||||||
|
- [ ] Plugin works with PHP 7.4+
|
||||||
|
- [ ] Plugin works with common themes (Twenty Twenty-Three, Kadence)
|
||||||
|
- [ ] Plugin co-exists with other popular plugins without conflicts
|
||||||
|
|
||||||
|
### Browser Compatibility
|
||||||
|
|
||||||
|
- [ ] UI works correctly in Chrome
|
||||||
|
- [ ] UI works correctly in Firefox
|
||||||
|
- [ ] UI works correctly in Safari
|
||||||
|
- [ ] UI works correctly in Edge
|
||||||
|
|
||||||
|
### Mobile Responsiveness
|
||||||
|
|
||||||
|
- [ ] Admin interface is usable on mobile devices
|
||||||
|
- [ ] No layout issues on small screens
|
||||||
|
|
||||||
|
## Testing Process
|
||||||
|
|
||||||
|
1. Create a clean WordPress installation for testing
|
||||||
|
2. Install and activate the plugin
|
||||||
|
3. Enable WordPress debug mode (WP_DEBUG = true)
|
||||||
|
4. Complete all tests in the checklist
|
||||||
|
5. Document any issues found
|
||||||
|
6. Fix issues and retest
|
||||||
|
7. Only mark as [STABLE] when all tests pass
|
||||||
|
|
||||||
|
## Continuous Integration
|
||||||
|
|
||||||
|
For future implementation:
|
||||||
|
|
||||||
|
- [ ] Automated unit tests
|
||||||
|
- [ ] Integration tests
|
||||||
|
- [ ] End-to-end tests
|
||||||
|
- [ ] Code quality checks
|
@ -1,123 +0,0 @@
|
|||||||
<?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();
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
1576
admin/css/wp-allstars-admin.css
Normal file
1576
admin/css/wp-allstars-admin.css
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,45 +1,65 @@
|
|||||||
/* Plugin Browser Styles */
|
/* Plugin Browser Styles */
|
||||||
.seoprostack-wrap .seoprostack-plugin-browser {
|
.wp-allstars-wrap .wp-allstars-plugin-browser {
|
||||||
margin: 0 -8px !important;
|
margin: 0 !important;
|
||||||
padding: 0 8px !important;
|
padding: 0 !important;
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
max-width: 100% !important;
|
max-width: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Plugin List Container */
|
/* Plugin List Container */
|
||||||
.seoprostack-wrap #seoprostack-plugin-list {
|
.wp-allstars-wrap #wpa-plugin-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
width: 100%;
|
padding: 20px;
|
||||||
|
max-width: 700px;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Filter Bar */
|
/* Filter Bar - Full Width */
|
||||||
.seoprostack-wrap #seoprostack-plugin-filters.wp-filter {
|
.wp-allstars-wrap #wpa-plugin-filters.wp-filter {
|
||||||
margin-left: 0;
|
margin: 0 0 11px 0 !important;
|
||||||
margin-right: 0;
|
width: 100% !important;
|
||||||
width: 100%;
|
max-width: 100% !important;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Standard WordPress Plugin Grid Layout - exactly matching core */
|
/* Center filter links */
|
||||||
.seoprostack-wrap .wp-list-table.plugin-install {
|
.wp-filter .filter-links {
|
||||||
margin-top: 20px;
|
|
||||||
clear: both;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.seoprostack-wrap #the-list {
|
|
||||||
margin: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
padding: 0;
|
justify-content: center;
|
||||||
|
float: none !important;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Plugin Cards - essential layout only */
|
.wp-filter .filter-links li {
|
||||||
|
float: none;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive filters */
|
||||||
|
@media screen and (max-width: 782px) {
|
||||||
|
.wp-filter .filter-links li > a {
|
||||||
|
padding: 12px 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
.wp-filter .filter-links li > a {
|
||||||
|
padding: 10px 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Plugin Cards - Use consistent layout similar to 768px width for all screens */
|
||||||
.plugin-card {
|
.plugin-card {
|
||||||
margin: 0 8px 16px;
|
margin: 0 0 24px 0 !important;
|
||||||
width: calc(50% - 16px);
|
width: 100% !important;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 1px solid #dcdcde;
|
border: 1px solid #dcdcde;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@ -47,6 +67,13 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-card:last-child {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.plugin-card:hover {
|
.plugin-card:hover {
|
||||||
@ -54,23 +81,123 @@
|
|||||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure the right edge aligns with the navigation above */
|
/* Card Content */
|
||||||
.plugin-card:nth-child(even) {
|
.plugin-card-top {
|
||||||
margin-right: 0;
|
padding: 24px !important;
|
||||||
|
position: relative;
|
||||||
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.plugin-card:nth-child(odd) {
|
.plugin-icon {
|
||||||
margin-left: 0;
|
position: relative !important;
|
||||||
|
float: left !important;
|
||||||
|
width: 64px !important;
|
||||||
|
height: 64px !important;
|
||||||
|
margin: 0 20px 15px 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Consistent styling for all widths */
|
/* Name and description positioning - 768px style */
|
||||||
/* Force equal spacing between all cards */
|
.name.column-name {
|
||||||
.plugin-card:nth-child(odd) {
|
margin: 0 0 12px 84px !important;
|
||||||
margin-right: 8px;
|
margin-right: 0 !important; /* Full width content */
|
||||||
}
|
}
|
||||||
|
|
||||||
.plugin-card:nth-child(even) {
|
.name.column-name h3 {
|
||||||
margin-left: 8px;
|
font-size: 16px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
line-height: 1.4 !important;
|
||||||
|
margin: 0 0 12px !important;
|
||||||
|
color: #1d2327 !important;
|
||||||
|
word-wrap: break-word !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc.column-description {
|
||||||
|
margin: 0 0 20px 84px !important;
|
||||||
|
margin-right: 0 !important; /* Full width content */
|
||||||
|
font-size: 14px !important;
|
||||||
|
line-height: 1.6 !important;
|
||||||
|
color: #50575e !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Action Links - Position below content */
|
||||||
|
.action-links {
|
||||||
|
position: relative !important;
|
||||||
|
width: 100% !important;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: row !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: flex-end !important;
|
||||||
|
gap: 8px !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
margin-top: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-action-buttons {
|
||||||
|
margin: 0 !important;
|
||||||
|
float: none !important;
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-action-buttons .button {
|
||||||
|
width: auto !important;
|
||||||
|
min-width: 120px !important;
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card Bottom - Right aligned compatibility text */
|
||||||
|
.plugin-card-bottom {
|
||||||
|
background: #f6f7f7 !important;
|
||||||
|
padding: 15px 20px !important;
|
||||||
|
border-top: 1px solid #ddd !important;
|
||||||
|
text-align: right !important;
|
||||||
|
margin-top: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading Overlay without white background */
|
||||||
|
.wp-allstars-loading-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: transparent !important;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extra small screens only */
|
||||||
|
@media screen and (max-width: 480px) {
|
||||||
|
.plugin-card {
|
||||||
|
padding-top: 80px !important; /* Space for icon at top */
|
||||||
|
}
|
||||||
|
|
||||||
|
.name.column-name,
|
||||||
|
.desc.column-description {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-icon {
|
||||||
|
position: absolute !important;
|
||||||
|
top: 16px !important;
|
||||||
|
left: 16px !important;
|
||||||
|
float: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-links {
|
||||||
|
flex-direction: column !important;
|
||||||
|
align-items: stretch !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-action-buttons {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-action-buttons .button {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Global plugin icon positioning that applies to all viewport sizes */
|
/* Global plugin icon positioning that applies to all viewport sizes */
|
||||||
@ -144,7 +271,7 @@ body.wp-admin .wp-list-table.plugin-install #the-list .plugin-card .plugin-card-
|
|||||||
min-height: 100px !important;
|
min-height: 100px !important;
|
||||||
position: relative !important;
|
position: relative !important;
|
||||||
padding: 20px !important;
|
padding: 20px !important;
|
||||||
padding-top: 20px !important; /* Force top padding to stay at 20px */
|
padding-top: 22px !important; /* Force top padding to stay at 22px */
|
||||||
overflow: hidden !important;
|
overflow: hidden !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +279,7 @@ body.wp-admin .wp-list-table.plugin-install #the-list .plugin-card .plugin-card-
|
|||||||
@supports (display: flex) {
|
@supports (display: flex) {
|
||||||
body.wp-admin .wp-list-table.plugin-install #the-list .plugin-card .plugin-card-top {
|
body.wp-admin .wp-list-table.plugin-install #the-list .plugin-card .plugin-card-top {
|
||||||
padding: 20px !important;
|
padding: 20px !important;
|
||||||
padding-top: 20px !important;
|
padding-top: 22px !important;
|
||||||
min-height: 100px !important;
|
min-height: 100px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,13 +363,6 @@ body.wp-admin .plugin-card-bottom {
|
|||||||
margin-top: 0 !important;
|
margin-top: 0 !important;
|
||||||
text-align: left !important;
|
text-align: left !important;
|
||||||
margin-left: 0 !important;
|
margin-left: 0 !important;
|
||||||
margin-right: 0 !important;
|
|
||||||
max-width: none !important;
|
|
||||||
clear: both !important;
|
|
||||||
width: 100% !important;
|
|
||||||
box-sizing: border-box !important;
|
|
||||||
border-bottom-left-radius: 8px !important;
|
|
||||||
border-bottom-right-radius: 8px !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove excessive spacing between elements */
|
/* Remove excessive spacing between elements */
|
||||||
@ -329,6 +449,40 @@ body.wp-admin .wp-list-table.plugin-install #the-list .plugin-card .action-links
|
|||||||
line-height: 28px !important;
|
line-height: 28px !important;
|
||||||
padding-top: 0 !important;
|
padding-top: 0 !important;
|
||||||
padding-bottom: 0 !important;
|
padding-bottom: 0 !important;
|
||||||
|
background-color: #d35400 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
border-color: #c24e00 !important;
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2) !important;
|
||||||
|
position: relative !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.wp-admin .wp-list-table.plugin-install #the-list .plugin-card .action-links .button.go-pro::before {
|
||||||
|
content: '' !important;
|
||||||
|
position: absolute !important;
|
||||||
|
top: 0 !important;
|
||||||
|
left: -100% !important;
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent) !important;
|
||||||
|
transition: all 0.5s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.wp-admin .wp-list-table.plugin-install #the-list .plugin-card .action-links .button.go-pro:hover {
|
||||||
|
background-color: #aa4300 !important;
|
||||||
|
border-color: #953b00 !important;
|
||||||
|
transform: translateY(-2px) !important;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.wp-admin .wp-list-table.plugin-install #the-list .plugin-card .action-links .button.go-pro:hover::before {
|
||||||
|
left: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.wp-admin .wp-list-table.plugin-install #the-list .plugin-card .action-links .button.go-pro:active {
|
||||||
|
transform: translateY(0) !important;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure consistent layout for action buttons */
|
/* Ensure consistent layout for action buttons */
|
||||||
@ -370,7 +524,6 @@ body.wp-admin .plugin-card-bottom .compatibility-untested *,
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.plugin-card:hover {
|
.plugin-card:hover {
|
||||||
border-color: #999;
|
border-color: #999;
|
||||||
}
|
}
|
||||||
@ -523,7 +676,7 @@ body.wp-admin .plugin-card-bottom .compatibility-untested *,
|
|||||||
.wp-filter {
|
.wp-filter {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin: 12px 0 25px;
|
margin: 12px 0 0;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border: 1px solid #dcdcde;
|
border: 1px solid #dcdcde;
|
||||||
@ -617,6 +770,12 @@ body.wp-admin .plugin-card-bottom .compatibility-untested *,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Theme Browser */
|
/* Theme Browser */
|
||||||
|
.theme-browser {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.theme-browser .theme {
|
.theme-browser .theme {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
float: left;
|
float: left;
|
||||||
@ -750,4 +909,11 @@ body.wp-admin .plugin-card-bottom .compatibility-untested *,
|
|||||||
|
|
||||||
.theme-browser .theme:nth-child(2n) {
|
.theme-browser .theme:nth-child(2n) {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Theme browser proper layout */
|
||||||
|
.theme-browser .theme:nth-child(2n) {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove media query for wider screens since we're using consistent layout */
|
161
admin/data/free-plugins.php
Normal file
161
admin/data/free-plugins.php
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Recommended plugins data for WP ALLSTARS plugin
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Define recommended plugins
|
||||||
|
function wp_allstars_get_free_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'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
@ -1,32 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Hosting providers data for SEO Pro Stack
|
* Hosting providers data for WP ALLSTARS plugin
|
||||||
*
|
|
||||||
* @package SEO_Pro_Stack
|
|
||||||
* @subpackage SEO_Pro_Stack/Admin/Settings/Data
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// If this file is called directly, abort.
|
// Define hosting providers
|
||||||
if (!defined('ABSPATH')) {
|
function wp_allstars_get_hosting_providers() {
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define hosting providers
|
|
||||||
*
|
|
||||||
* @return array Array of hosting providers with their details
|
|
||||||
*/
|
|
||||||
function wp_seoprostack_get_hosting_providers() {
|
|
||||||
return array(
|
return array(
|
||||||
'closte' => array(
|
'closte' => array(
|
||||||
'name' => 'Closte',
|
'name' => 'Closte',
|
||||||
'description' => 'Managed WordPress hosting with advanced performance optimization and auto-scaling.',
|
'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(
|
'button_group' => array(
|
||||||
array(
|
array(
|
||||||
'text' => 'Home Page',
|
'text' => 'Home Page',
|
||||||
@ -42,12 +24,6 @@ function wp_seoprostack_get_hosting_providers() {
|
|||||||
'cloudron' => array(
|
'cloudron' => array(
|
||||||
'name' => 'Cloudron',
|
'name' => 'Cloudron',
|
||||||
'description' => 'Self-hosted platform that makes it easy to run web applications like WordPress on your server.',
|
'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(
|
'button_group' => array(
|
||||||
array(
|
array(
|
||||||
'text' => 'Home Page',
|
'text' => 'Home Page',
|
||||||
@ -63,12 +39,6 @@ function wp_seoprostack_get_hosting_providers() {
|
|||||||
'hostinger' => array(
|
'hostinger' => array(
|
||||||
'name' => 'Hostinger',
|
'name' => 'Hostinger',
|
||||||
'description' => 'Affordable WordPress hosting with good performance and user-friendly management tools.',
|
'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(
|
'button_group' => array(
|
||||||
array(
|
array(
|
||||||
'text' => 'Home Page',
|
'text' => 'Home Page',
|
||||||
@ -84,12 +54,6 @@ function wp_seoprostack_get_hosting_providers() {
|
|||||||
'hetzner' => array(
|
'hetzner' => array(
|
||||||
'name' => 'Hetzner Cloud',
|
'name' => 'Hetzner Cloud',
|
||||||
'description' => 'High-performance cloud servers with excellent price-to-performance ratio for self-managed WordPress hosting.',
|
'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(
|
'button_group' => array(
|
||||||
array(
|
array(
|
||||||
'text' => 'Home Page',
|
'text' => 'Home Page',
|
||||||
@ -105,12 +69,6 @@ function wp_seoprostack_get_hosting_providers() {
|
|||||||
'simplehost' => array(
|
'simplehost' => array(
|
||||||
'name' => 'SimpleHost',
|
'name' => 'SimpleHost',
|
||||||
'description' => 'Streamlined WordPress hosting with a focus on simplicity and performance.',
|
'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(
|
'button_group' => array(
|
||||||
array(
|
array(
|
||||||
'text' => 'Home Page',
|
'text' => 'Home Page',
|
||||||
@ -126,12 +84,6 @@ function wp_seoprostack_get_hosting_providers() {
|
|||||||
'cloudflare' => array(
|
'cloudflare' => array(
|
||||||
'name' => 'Cloudflare',
|
'name' => 'Cloudflare',
|
||||||
'description' => 'Global cloud platform that provides CDN, security, and performance optimization services.',
|
'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(
|
'button_group' => array(
|
||||||
array(
|
array(
|
||||||
'text' => 'Home Page',
|
'text' => 'Home Page',
|
||||||
@ -147,12 +99,6 @@ function wp_seoprostack_get_hosting_providers() {
|
|||||||
'spaceship' => array(
|
'spaceship' => array(
|
||||||
'name' => 'Spaceship',
|
'name' => 'Spaceship',
|
||||||
'description' => 'Modern hosting platform with advanced features for WordPress sites.',
|
'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(
|
'button_group' => array(
|
||||||
array(
|
array(
|
||||||
'text' => 'Home Page',
|
'text' => 'Home Page',
|
||||||
@ -164,12 +110,6 @@ function wp_seoprostack_get_hosting_providers() {
|
|||||||
'101domain' => array(
|
'101domain' => array(
|
||||||
'name' => '101Domain',
|
'name' => '101Domain',
|
||||||
'description' => 'Domain registration and management service with support for hundreds of TLDs.',
|
'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(
|
'button_group' => array(
|
||||||
array(
|
array(
|
||||||
'text' => 'Home Page',
|
'text' => 'Home Page',
|
||||||
@ -181,12 +121,6 @@ function wp_seoprostack_get_hosting_providers() {
|
|||||||
'namecheap' => array(
|
'namecheap' => array(
|
||||||
'name' => 'Namecheap',
|
'name' => 'Namecheap',
|
||||||
'description' => 'Domain registrar and web hosting provider with competitive pricing and good support.',
|
'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(
|
'button_group' => array(
|
||||||
array(
|
array(
|
||||||
'text' => 'Home Page',
|
'text' => 'Home Page',
|
||||||
@ -202,12 +136,6 @@ function wp_seoprostack_get_hosting_providers() {
|
|||||||
'updownio' => array(
|
'updownio' => array(
|
||||||
'name' => 'Updown.io',
|
'name' => 'Updown.io',
|
||||||
'description' => 'Simple and affordable website monitoring service with uptime checks and performance metrics.',
|
'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(
|
'button_group' => array(
|
||||||
array(
|
array(
|
||||||
'text' => 'Home Page',
|
'text' => 'Home Page',
|
||||||
@ -219,11 +147,21 @@ function wp_seoprostack_get_hosting_providers() {
|
|||||||
'url' => 'https://updown.io/pricing'
|
'url' => 'https://updown.io/pricing'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
),
|
||||||
|
'coolify' => array(
|
||||||
|
'name' => 'Coolify',
|
||||||
|
'description' => 'Self-hostable Heroku & Netlify alternative for developers. Deploy your apps, databases, and services with ease.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://coolify.io/',
|
||||||
|
'primary' => true
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'text' => 'Pricing',
|
||||||
|
'url' => 'https://coolify.io/pricing/'
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alias for backward compatibility with the old codebase
|
|
||||||
function wp_allstars_get_hosting_providers() {
|
|
||||||
return wp_seoprostack_get_hosting_providers();
|
|
||||||
}
|
|
@ -3,7 +3,7 @@
|
|||||||
* Pro Plugins Configuration
|
* Pro Plugins Configuration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function wp_seoprostack_get_pro_plugins_config() {
|
function wp_allstars_get_pro_plugins() {
|
||||||
return array(
|
return array(
|
||||||
'magic-login-pro' => array(
|
'magic-login-pro' => array(
|
||||||
'name' => 'Magic Login Pro',
|
'name' => 'Magic Login Pro',
|
||||||
@ -775,9 +775,4 @@ function wp_seoprostack_get_pro_plugins_config() {
|
|||||||
'free_slug' => 'gotmls'
|
'free_slug' => 'gotmls'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backward compatibility alias
|
|
||||||
function wp_allstars_get_pro_plugins_config() {
|
|
||||||
return wp_seoprostack_get_pro_plugins_config();
|
|
||||||
}
|
|
46
admin/data/readme.php
Normal file
46
admin/data/readme.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Read Me data for WP ALLSTARS plugin
|
||||||
|
* Content is pulled from the README.md file
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define readme content
|
||||||
|
function wp_allstars_get_readme_content() {
|
||||||
|
// Get README.md content
|
||||||
|
$readme_path = WP_PLUGIN_DIR . '/wpa-superstar-plugin/README.md';
|
||||||
|
$readme_content = '';
|
||||||
|
|
||||||
|
if (file_exists($readme_path)) {
|
||||||
|
$readme_content = file_get_contents($readme_path);
|
||||||
|
} else {
|
||||||
|
// Fallback content if README.md is not found
|
||||||
|
$readme_content = <<<MARKDOWN
|
||||||
|
# WP Allstars
|
||||||
|
|
||||||
|
A WordPress plugin that enhances your WordPress experience with curated plugins, themes, and optimization tools.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Curated Plugin Recommendations**: Browse and install recommended free plugins organized by category.
|
||||||
|
- **Pro Plugin Showcase**: Discover premium plugins with direct links to purchase.
|
||||||
|
- **Theme Integration**: Easily install and activate the Kadence theme.
|
||||||
|
- **Workflow Optimization**: Tools to streamline your WordPress workflow.
|
||||||
|
- **Advanced Settings**: Fine-tune your WordPress installation with advanced configuration options.
|
||||||
|
|
||||||
|
Version: {WP_ALLSTARS_VERSION}
|
||||||
|
MARKDOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'title' => 'Read Me',
|
||||||
|
'content' => $readme_content
|
||||||
|
];
|
||||||
|
}
|
@ -1,22 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Recommended plugins data for SEO Pro Stack
|
* Recommended plugins data for WP ALLSTARS plugin
|
||||||
*
|
|
||||||
* @package SEO_Pro_Stack
|
|
||||||
* @subpackage SEO_Pro_Stack/Admin/Settings/Data
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// If this file is called directly, abort.
|
// Define recommended plugins
|
||||||
if (!defined('ABSPATH')) {
|
function wp_allstars_get_recommended_plugins() {
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define recommended plugins
|
|
||||||
*
|
|
||||||
* @return array Array of recommended plugins categorized by use case
|
|
||||||
*/
|
|
||||||
function wp_seoprostack_get_recommended_plugins() {
|
|
||||||
return array(
|
return array(
|
||||||
'minimal' => array(
|
'minimal' => array(
|
||||||
'antispam-bee',
|
'antispam-bee',
|
||||||
@ -171,13 +159,3 @@ function wp_seoprostack_get_recommended_plugins() {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
@ -1,22 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Tools data for SEO Pro Stack
|
* Tools data for WP ALLSTARS plugin
|
||||||
*
|
|
||||||
* @package SEO_Pro_Stack
|
|
||||||
* @subpackage SEO_Pro_Stack/Admin/Settings/Data
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// If this file is called directly, abort.
|
// Define tools
|
||||||
if (!defined('ABSPATH')) {
|
function wp_allstars_get_tools() {
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define tools
|
|
||||||
*
|
|
||||||
* @return array Array of tools with their details
|
|
||||||
*/
|
|
||||||
function wp_seoprostack_get_tools() {
|
|
||||||
return array(
|
return array(
|
||||||
'advise' => array(
|
'advise' => array(
|
||||||
'name' => 'Advise.so',
|
'name' => 'Advise.so',
|
||||||
@ -183,6 +171,83 @@ function wp_seoprostack_get_tools() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
'pixelmator' => array(
|
||||||
|
'name' => 'Pixelmator Pro',
|
||||||
|
'description' => 'Professional image editing software for Mac with powerful tools and an intuitive interface.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://www.pixelmator.com/pro/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'upscayl' => array(
|
||||||
|
'name' => 'Upscayl',
|
||||||
|
'description' => 'Open-source AI image upscaler that enhances and enlarges images with improved quality.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://upscayl.org/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'sitesucker' => array(
|
||||||
|
'name' => 'SiteSucker',
|
||||||
|
'description' => 'Website downloading tool that allows you to save entire websites for offline viewing.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://ricks-apps.com/osx/sitesucker/index.html',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'virustotal' => array(
|
||||||
|
'name' => 'VirusTotal',
|
||||||
|
'description' => 'Free service that analyzes files and URLs for viruses, worms, trojans, and other malicious content.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://www.virustotal.com/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'transmit' => array(
|
||||||
|
'name' => 'Transmit',
|
||||||
|
'description' => 'File transfer client for macOS with support for FTP, SFTP, WebDAV, and cloud services.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://panic.com/transmit/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'iterm2' => array(
|
||||||
|
'name' => 'iTerm2',
|
||||||
|
'description' => 'Terminal emulator for macOS with advanced features beyond the default Terminal app.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://iterm2.com/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'cloudron' => array(
|
||||||
|
'name' => 'Cloudron',
|
||||||
|
'description' => 'Self-hosted platform that makes it easy to run web applications like WordPress on your server.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://www.cloudron.io/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
'urlmonitor' => array(
|
'urlmonitor' => array(
|
||||||
'name' => 'URL Monitor',
|
'name' => 'URL Monitor',
|
||||||
'description' => 'Website monitoring service that tracks uptime, performance, and alerts you to issues.',
|
'description' => 'Website monitoring service that tracks uptime, performance, and alerts you to issues.',
|
||||||
@ -260,6 +325,50 @@ function wp_seoprostack_get_tools() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
'muraena' => array(
|
||||||
|
'name' => 'Muraena AI',
|
||||||
|
'description' => 'AI-powered writing assistant for creating and optimizing content.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://muraena.ai/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'googlebusiness' => array(
|
||||||
|
'name' => 'Google Business Profile',
|
||||||
|
'description' => 'Free tool to manage your business presence on Google Search and Maps.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://business.google.com/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'chatgptdetector' => array(
|
||||||
|
'name' => 'ChatGPT Detector',
|
||||||
|
'description' => 'Tool to detect AI-generated content from models like ChatGPT.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://textvisualization.app/chatgpt-detector/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'zerogpt' => array(
|
||||||
|
'name' => 'ZeroGPT',
|
||||||
|
'description' => 'AI content detector that identifies text generated by AI models.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://zerogpt.tools/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
'zerogptplus' => array(
|
'zerogptplus' => array(
|
||||||
'name' => 'ZeroGPT Plus',
|
'name' => 'ZeroGPT Plus',
|
||||||
'description' => 'Advanced AI content detector with improved accuracy and additional features.',
|
'description' => 'Advanced AI content detector with improved accuracy and additional features.',
|
||||||
@ -293,6 +402,22 @@ function wp_seoprostack_get_tools() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
'searchatlas' => array(
|
||||||
|
'name' => 'Search Atlas',
|
||||||
|
'description' => 'Comprehensive SEO platform with keyword research, rank tracking, and content optimization tools.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://searchatlas.com/',
|
||||||
|
'primary' => true
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'text' => 'Pricing',
|
||||||
|
'url' => 'https://searchatlas.com/pricing/',
|
||||||
|
'primary' => false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
'seoptimer' => array(
|
'seoptimer' => array(
|
||||||
'name' => 'SEOptimer',
|
'name' => 'SEOptimer',
|
||||||
'description' => 'Website audit tool that provides SEO, usability, and performance recommendations.',
|
'description' => 'Website audit tool that provides SEO, usability, and performance recommendations.',
|
||||||
@ -315,6 +440,61 @@ function wp_seoprostack_get_tools() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
'appsumo' => array(
|
||||||
|
'name' => 'AppSumo',
|
||||||
|
'description' => 'Marketplace for discounted digital products and services for entrepreneurs.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://appsumo.com/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'screenstudio' => array(
|
||||||
|
'name' => 'Screen Studio',
|
||||||
|
'description' => 'Screen recording software with automatic editing and professional results.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://screen.studio/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'screenflow' => array(
|
||||||
|
'name' => 'ScreenFlow',
|
||||||
|
'description' => 'Professional screen recording and video editing software for macOS.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://www.telestream.net/screenflow/overview.htm',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'acronis' => array(
|
||||||
|
'name' => 'Acronis Cyber Protect Connect',
|
||||||
|
'description' => 'Remote desktop and support solution for secure access to remote computers.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://www.acronis.com/en-us/products/cyber-protect-connect/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'espocrm' => array(
|
||||||
|
'name' => 'EspoCRM',
|
||||||
|
'description' => 'Open-source customer relationship management (CRM) application.',
|
||||||
|
'button_group' => array(
|
||||||
|
array(
|
||||||
|
'text' => 'Home Page',
|
||||||
|
'url' => 'https://www.espocrm.com/',
|
||||||
|
'primary' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
'libreoffice' => array(
|
'libreoffice' => array(
|
||||||
'name' => 'LibreOffice',
|
'name' => 'LibreOffice',
|
||||||
'description' => 'Free and open-source office suite compatible with Microsoft Office formats.',
|
'description' => 'Free and open-source office suite compatible with Microsoft Office formats.',
|
||||||
@ -361,13 +541,3 @@ function wp_seoprostack_get_tools() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 279 KiB |
313
admin/includes/class-admin-manager.php
Normal file
313
admin/includes/class-admin-manager.php
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* WP ALLSTARS Admin Manager
|
||||||
|
*
|
||||||
|
* @package WP_ALLSTARS
|
||||||
|
* @since 0.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WP_Allstars_Admin_Manager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the class and register hooks
|
||||||
|
*/
|
||||||
|
public static function init() {
|
||||||
|
add_action('admin_menu', array(__CLASS__, 'register_admin_menu'));
|
||||||
|
add_action('wp_ajax_wp_allstars_update_option', array(__CLASS__, 'update_option'));
|
||||||
|
add_action('admin_init', array(__CLASS__, 'register_settings'));
|
||||||
|
add_action('admin_enqueue_scripts', array(__CLASS__, 'enqueue_admin_scripts'));
|
||||||
|
|
||||||
|
// Initialize all manager classes
|
||||||
|
WP_Allstars_Settings_Manager::init();
|
||||||
|
WP_Allstars_Theme_Manager::init();
|
||||||
|
WP_Allstars_Workflow_Manager::init();
|
||||||
|
WP_Allstars_Pro_Plugins_Manager::init();
|
||||||
|
WP_Allstars_Tools_Manager::init();
|
||||||
|
WP_Allstars_Hosting_Manager::init();
|
||||||
|
WP_Allstars_Free_Plugins_Manager::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue admin scripts and styles
|
||||||
|
*
|
||||||
|
* @param string $hook The current admin page hook
|
||||||
|
*/
|
||||||
|
public static function enqueue_admin_scripts($hook) {
|
||||||
|
if ('settings_page_wp-allstars' !== $hook) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enqueue admin stylesheet
|
||||||
|
wp_enqueue_style(
|
||||||
|
'wp-allstars-admin',
|
||||||
|
plugins_url('css/wp-allstars-admin.css', dirname(__FILE__)),
|
||||||
|
array(),
|
||||||
|
WP_ALLSTARS_VERSION
|
||||||
|
);
|
||||||
|
|
||||||
|
// Enqueue admin JavaScript
|
||||||
|
wp_enqueue_script(
|
||||||
|
'wp-allstars-admin',
|
||||||
|
plugins_url('js/wp-allstars-admin.js', dirname(__FILE__)),
|
||||||
|
array('jquery'),
|
||||||
|
WP_ALLSTARS_VERSION,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Localize the script with necessary data for AJAX
|
||||||
|
wp_localize_script('wp-allstars-admin', 'wpAllstars', array(
|
||||||
|
'nonce' => wp_create_nonce('wp-allstars-nonce'),
|
||||||
|
'ajaxurl' => admin_url('admin-ajax.php')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register core plugin settings
|
||||||
|
*/
|
||||||
|
public static function register_settings() {
|
||||||
|
// Core settings groups - tab-specific settings are registered in their respective manager classes
|
||||||
|
register_setting('wp_allstars_general', 'wp_allstars_general_settings');
|
||||||
|
register_setting('wp_allstars_advanced', 'wp_allstars_advanced_settings');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AJAX handler for updating options
|
||||||
|
*/
|
||||||
|
public static function update_option() {
|
||||||
|
// Verify nonce for security
|
||||||
|
check_ajax_referer('wp-allstars-nonce', 'nonce');
|
||||||
|
|
||||||
|
// Check if user has proper permissions
|
||||||
|
if (!current_user_can('manage_options')) {
|
||||||
|
wp_send_json_error('Insufficient permissions');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate and sanitize input
|
||||||
|
if (!isset($_POST['option']) || !isset($_POST['value'])) {
|
||||||
|
wp_send_json_error('Missing required parameters');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$option = sanitize_text_field($_POST['option']);
|
||||||
|
|
||||||
|
// Different sanitization based on expected value type
|
||||||
|
$value = $_POST['value'];
|
||||||
|
if (is_numeric($value)) {
|
||||||
|
$value = intval($value);
|
||||||
|
} elseif (is_string($value)) {
|
||||||
|
$value = sanitize_text_field($value);
|
||||||
|
} elseif (is_array($value)) {
|
||||||
|
$value = array_map('sanitize_text_field', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whitelist of allowed options to update for security
|
||||||
|
$allowed_options = array(
|
||||||
|
'wp_allstars_simple_setting',
|
||||||
|
'wp_allstars_auto_upload_images',
|
||||||
|
'wp_allstars_max_width',
|
||||||
|
'wp_allstars_max_height',
|
||||||
|
'wp_allstars_exclude_urls',
|
||||||
|
'wp_allstars_image_name_pattern',
|
||||||
|
'wp_allstars_image_alt_pattern'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!in_array($option, $allowed_options)) {
|
||||||
|
wp_send_json_error('Invalid option');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the option
|
||||||
|
$result = update_option($option, $value);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
wp_send_json_success(array(
|
||||||
|
'message' => 'Option updated successfully',
|
||||||
|
'option' => $option,
|
||||||
|
'value' => $value
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
wp_send_json_success(array(
|
||||||
|
'message' => 'No changes made to option',
|
||||||
|
'option' => $option
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the admin menu item
|
||||||
|
*/
|
||||||
|
public static function register_admin_menu() {
|
||||||
|
add_options_page(
|
||||||
|
'WP ALLSTARS Settings',
|
||||||
|
'WP ALLSTARS',
|
||||||
|
'manage_options',
|
||||||
|
'wp-allstars',
|
||||||
|
array(__CLASS__, 'render_settings_page')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the settings page
|
||||||
|
*/
|
||||||
|
public static function render_settings_page() {
|
||||||
|
global $tabs;
|
||||||
|
|
||||||
|
$active_tab = isset($_GET['tab']) ? $_GET['tab'] : 'general';
|
||||||
|
$active_category = isset($_GET['category']) ? $_GET['category'] : 'minimal';
|
||||||
|
|
||||||
|
// Tab-specific resources
|
||||||
|
if ($active_tab === 'recommended') {
|
||||||
|
WP_Allstars_Plugin_Manager::clear_plugin_cache();
|
||||||
|
wp_enqueue_script('plugin-install');
|
||||||
|
wp_enqueue_script('updates');
|
||||||
|
add_thickbox();
|
||||||
|
wp_enqueue_style('wp-allstars-plugins', plugins_url('css/wp-allstars-plugins.css', dirname(__FILE__)));
|
||||||
|
|
||||||
|
// Add inline script to load plugins on page load
|
||||||
|
wp_add_inline_script('wp-allstars-admin', '
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
if ($("#wpa-plugin-list").length && $("#wpa-plugin-list").is(":empty")) {
|
||||||
|
var category = "' . esc_js($active_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);
|
||||||
|
|
||||||
|
// AJAX request to get plugins
|
||||||
|
$.ajax({
|
||||||
|
url: ajaxurl,
|
||||||
|
type: "POST",
|
||||||
|
data: {
|
||||||
|
action: "wp_allstars_get_plugins",
|
||||||
|
category: category,
|
||||||
|
_wpnonce: wpAllstars.nonce
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
$loadingOverlay.remove();
|
||||||
|
if (response.success) {
|
||||||
|
$container.html(response.data);
|
||||||
|
// Initialize plugin action buttons
|
||||||
|
if (typeof initPluginActions === "function") {
|
||||||
|
initPluginActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spinners have been removed from individual cards
|
||||||
|
} else {
|
||||||
|
$container.html("<div class=\"notice notice-error\"><p>" + response.data + "</p></div>");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
$loadingOverlay.remove();
|
||||||
|
$container.html("<div class=\"notice notice-error\"><p>Failed to load plugins. Please try again. Error: " + error + "</p></div>");
|
||||||
|
console.error("AJAX Error:", xhr.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
');
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<div class="wrap wp-allstars-wrap">
|
||||||
|
<div class="wp-allstars-header">
|
||||||
|
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
|
||||||
|
<div class="wp-allstars-header-actions">
|
||||||
|
<span class="wp-allstars-version"><?php echo esc_html(WP_ALLSTARS_VERSION); ?></span>
|
||||||
|
<a href="https://www.wpallstars.com/" target="_blank" class="button button-secondary green-button-secondary green-visit-website">
|
||||||
|
<?php esc_html_e('Visit Website', 'wp-allstars'); ?>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wp-allstars-tabs-wrapper">
|
||||||
|
<h2 class="nav-tab-wrapper">
|
||||||
|
<a href="?page=wp-allstars&tab=general" class="nav-tab <?php echo $active_tab === 'general' ? 'nav-tab-active' : ''; ?>">
|
||||||
|
<?php esc_html_e('General', 'wp-allstars'); ?>
|
||||||
|
</a>
|
||||||
|
<a href="?page=wp-allstars&tab=advanced" class="nav-tab <?php echo $active_tab === 'advanced' ? 'nav-tab-active' : ''; ?>">
|
||||||
|
<?php esc_html_e('Advanced', 'wp-allstars'); ?>
|
||||||
|
</a>
|
||||||
|
<a href="?page=wp-allstars&tab=workflow" class="nav-tab <?php echo $active_tab === 'workflow' ? 'nav-tab-active' : ''; ?>">
|
||||||
|
<?php esc_html_e('Workflow', 'wp-allstars'); ?>
|
||||||
|
</a>
|
||||||
|
<a href="?page=wp-allstars&tab=theme" class="nav-tab <?php echo $active_tab === 'theme' ? 'nav-tab-active' : ''; ?>">
|
||||||
|
<?php esc_html_e('Theme', 'wp-allstars'); ?>
|
||||||
|
</a>
|
||||||
|
<a href="?page=wp-allstars&tab=recommended" class="nav-tab <?php echo $active_tab === 'recommended' ? 'nav-tab-active' : ''; ?>">
|
||||||
|
<?php esc_html_e('Free Plugins', 'wp-allstars'); ?>
|
||||||
|
</a>
|
||||||
|
<a href="?page=wp-allstars&tab=pro" class="nav-tab <?php echo $active_tab === 'pro' ? 'nav-tab-active' : ''; ?>">
|
||||||
|
<?php esc_html_e('Pro Plugins', 'wp-allstars'); ?>
|
||||||
|
</a>
|
||||||
|
<a href="?page=wp-allstars&tab=hosting" class="nav-tab <?php echo $active_tab === 'hosting' ? 'nav-tab-active' : ''; ?>">
|
||||||
|
<?php esc_html_e('Hosting', 'wp-allstars'); ?>
|
||||||
|
</a>
|
||||||
|
<a href="?page=wp-allstars&tab=tools" class="nav-tab <?php echo $active_tab === 'tools' ? 'nav-tab-active' : ''; ?>">
|
||||||
|
<?php esc_html_e('Tools', 'wp-allstars'); ?>
|
||||||
|
</a>
|
||||||
|
<a href="?page=wp-allstars&tab=readme" class="nav-tab <?php echo $active_tab === 'readme' ? 'nav-tab-active' : ''; ?>">
|
||||||
|
<?php esc_html_e('Read Me', 'wp-allstars'); ?>
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="wp-allstars-tab-content">
|
||||||
|
<?php
|
||||||
|
// Each tab's content is handled by its respective manager class
|
||||||
|
switch ($active_tab) {
|
||||||
|
case 'general':
|
||||||
|
WP_Allstars_Settings_Manager::display_general_tab();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'advanced':
|
||||||
|
WP_Allstars_Settings_Manager::display_advanced_tab();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'workflow':
|
||||||
|
WP_Allstars_Workflow_Manager::display_tab_content();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'theme':
|
||||||
|
WP_Allstars_Theme_Manager::display_tab_content();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'recommended':
|
||||||
|
WP_Allstars_Free_Plugins_Manager::display_tab_content();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'pro':
|
||||||
|
WP_Allstars_Pro_Plugins_Manager::display_tab_content();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'hosting':
|
||||||
|
WP_Allstars_Hosting_Manager::display_tab_content();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'tools':
|
||||||
|
WP_Allstars_Tools_Manager::display_tab_content();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'readme':
|
||||||
|
WP_Allstars_Readme_Manager::display_tab_content();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias for enqueue_admin_scripts to maintain compatibility with settings.php
|
||||||
|
*
|
||||||
|
* @param string $hook The current admin page hook
|
||||||
|
*/
|
||||||
|
public static function enqueue_scripts($hook) {
|
||||||
|
self::enqueue_admin_scripts($hook);
|
||||||
|
}
|
||||||
|
}
|
186
admin/includes/class-free-plugins-manager.php
Normal file
186
admin/includes/class-free-plugins-manager.php
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* WP ALLSTARS Free Plugins Manager
|
||||||
|
*
|
||||||
|
* Manages the Free Plugins tab including:
|
||||||
|
* - Category filtering system
|
||||||
|
* - Plugin recommendations by use case
|
||||||
|
* - Plugin installation functionality
|
||||||
|
*
|
||||||
|
* @package WP_ALLSTARS
|
||||||
|
* @since 0.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit; // Exit if accessed directly
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WP_Allstars_Free_Plugins_Manager class
|
||||||
|
*
|
||||||
|
* Provides categorized plugin recommendations based on website needs
|
||||||
|
*/
|
||||||
|
class WP_Allstars_Free_Plugins_Manager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the class and register hooks if needed
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function init() {
|
||||||
|
// We'll implement AJAX handlers in a future update if needed
|
||||||
|
// add_action('wp_ajax_wp_allstars_load_free_plugins', array(self::class, 'ajax_load_free_plugins'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the free plugins tab content
|
||||||
|
*
|
||||||
|
* Renders the category filter bar and plugin list container.
|
||||||
|
* Initial view shows 'minimal' category plugins by default.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function display_tab_content() {
|
||||||
|
// Get the active category from query params or use default
|
||||||
|
$active_category = isset($_GET['category']) ? sanitize_text_field($_GET['category']) : 'minimal';
|
||||||
|
|
||||||
|
// Get all available plugin categories from the data file
|
||||||
|
$plugin_categories = wp_allstars_get_free_plugins();
|
||||||
|
|
||||||
|
// Define all categories in the desired display order
|
||||||
|
$priority_categories = array(
|
||||||
|
'minimal', 'admin', 'affiliates', 'ai', 'cms',
|
||||||
|
'compliance', 'crm', 'ecommerce', 'lms', 'media',
|
||||||
|
'seo', 'setup', 'social', 'speed', 'translation',
|
||||||
|
'advanced', 'debug'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Start HTML output
|
||||||
|
?>
|
||||||
|
<div class="wp-allstars-settings-content tab-content" id="recommended">
|
||||||
|
<div id="wpa-plugin-filters" class="wp-filter">
|
||||||
|
<ul class="filter-links">
|
||||||
|
<?php
|
||||||
|
// First output priority categories
|
||||||
|
foreach ($priority_categories as $category) {
|
||||||
|
if (isset($plugin_categories[$category])) {
|
||||||
|
$category_name = ucfirst($category);
|
||||||
|
if ($category == 'cms') $category_name = 'CMS';
|
||||||
|
if ($category == 'crm') $category_name = 'CRM';
|
||||||
|
if ($category == 'ecommerce') $category_name = 'eCommerce';
|
||||||
|
if ($category == 'lms') $category_name = 'LMS';
|
||||||
|
if ($category == 'seo') $category_name = 'SEO';
|
||||||
|
?>
|
||||||
|
<li><a href="#" data-category="<?php echo esc_attr($category); ?>" class="<?php echo $active_category == $category ? 'current' : ''; ?>">
|
||||||
|
<?php echo esc_html($category_name); ?>
|
||||||
|
</a></li>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add any new categories that might have been added to the data file but aren't in our priority list
|
||||||
|
$remaining_categories = array_diff(array_keys($plugin_categories), $priority_categories);
|
||||||
|
sort($remaining_categories);
|
||||||
|
|
||||||
|
foreach ($remaining_categories as $category) {
|
||||||
|
$category_name = ucfirst($category);
|
||||||
|
if ($category == 'cms') $category_name = 'CMS';
|
||||||
|
if ($category == 'crm') $category_name = 'CRM';
|
||||||
|
if ($category == 'ecommerce') $category_name = 'eCommerce';
|
||||||
|
if ($category == 'lms') $category_name = 'LMS';
|
||||||
|
if ($category == 'seo') $category_name = 'SEO';
|
||||||
|
?>
|
||||||
|
<li><a href="#" data-category="<?php echo esc_attr($category); ?>" class="<?php echo $active_category == $category ? 'current' : ''; ?>">
|
||||||
|
<?php echo esc_html($category_name); ?>
|
||||||
|
</a></li>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wp-allstars-plugin-browser" style="margin-top: 22px;">
|
||||||
|
<div id="wpa-plugin-list" class="wpa-plugin-container" style="position: relative; min-height: 200px;">
|
||||||
|
<!-- Plugin content will be loaded via AJAX -->
|
||||||
|
<div class="wp-allstars-loading-overlay">
|
||||||
|
<span class="spinner is-active"></span>
|
||||||
|
<p>Loading plugin data...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
// Filter tab click handler
|
||||||
|
$('#wpa-plugin-filters .filter-links a').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var category = $(this).data('category');
|
||||||
|
var $container = $('#wpa-plugin-list');
|
||||||
|
|
||||||
|
// Update filter UI
|
||||||
|
$('#wpa-plugin-filters .filter-links a').removeClass('current');
|
||||||
|
$(this).addClass('current');
|
||||||
|
|
||||||
|
// Create new loading overlay
|
||||||
|
$container.empty();
|
||||||
|
var $loadingOverlay = $('<div class="wp-allstars-loading-overlay"><span class="spinner is-active"></span><p>Loading plugin data...</p></div>');
|
||||||
|
$container.append($loadingOverlay);
|
||||||
|
|
||||||
|
// Load plugins in selected category
|
||||||
|
$.ajax({
|
||||||
|
url: ajaxurl,
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
action: 'wp_allstars_get_plugins',
|
||||||
|
category: category,
|
||||||
|
_wpnonce: '<?php echo wp_create_nonce('wp-allstars-nonce'); ?>'
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
$loadingOverlay.remove();
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
// Add plugins to the container
|
||||||
|
$container.html(response.data);
|
||||||
|
|
||||||
|
// Initialize plugin action buttons (fix for AJAX install/activate functionality)
|
||||||
|
if (typeof initPluginActions === "function") {
|
||||||
|
initPluginActions();
|
||||||
|
} else if (typeof window.initPluginActions === "function") {
|
||||||
|
window.initPluginActions();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$container.html('<div class="notice notice-error"><p>' + response.data + '</p></div>');
|
||||||
|
console.error('Error loading plugins:', response.data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
$loadingOverlay.remove();
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load initial category (minimal or from URL)
|
||||||
|
$('#wpa-plugin-filters .filter-links a.current').trigger('click');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the recommended plugins data
|
||||||
|
*
|
||||||
|
* @return array Array of recommended plugins by category
|
||||||
|
*/
|
||||||
|
public static function get_recommended_plugins() {
|
||||||
|
// Define the plugins data if it hasn't been included yet
|
||||||
|
if (!function_exists('wp_allstars_get_free_plugins')) {
|
||||||
|
require_once dirname(dirname(__FILE__)) . '/data/free-plugins.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
return wp_allstars_get_free_plugins();
|
||||||
|
}
|
||||||
|
}
|
138
admin/includes/class-hosting-manager.php
Normal file
138
admin/includes/class-hosting-manager.php
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* WP ALLSTARS Hosting Manager
|
||||||
|
*
|
||||||
|
* Manages the hosting providers tab and functionality
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit; // Exit if accessed directly
|
||||||
|
}
|
||||||
|
|
||||||
|
class WP_Allstars_Hosting_Manager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the class
|
||||||
|
*/
|
||||||
|
public static function init() {
|
||||||
|
add_action('admin_enqueue_scripts', array(__CLASS__, 'enqueue_styles'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the hosting tab content
|
||||||
|
*/
|
||||||
|
public static function display_tab_content() {
|
||||||
|
?>
|
||||||
|
<div class="wp-allstars-settings-content tab-content" id="hosting">
|
||||||
|
<div class="wpa-pro-plugins">
|
||||||
|
<?php
|
||||||
|
$hosting_providers = self::get_hosting_providers();
|
||||||
|
// Sort providers alphabetically by name
|
||||||
|
uasort($hosting_providers, function($a, $b) {
|
||||||
|
return strcasecmp($a['name'], $b['name']);
|
||||||
|
});
|
||||||
|
foreach ($hosting_providers as $provider) {
|
||||||
|
?>
|
||||||
|
<div class="wpa-pro-plugin">
|
||||||
|
<h3><?php echo esc_html($provider['name']); ?></h3>
|
||||||
|
<p><?php echo esc_html($provider['description']); ?></p>
|
||||||
|
<?php if (isset($provider['button_group'])): ?>
|
||||||
|
<div class="button-group">
|
||||||
|
<?php foreach ($provider['button_group'] as $button): ?>
|
||||||
|
<?php
|
||||||
|
$button_class = 'button';
|
||||||
|
if (isset($button['primary']) && $button['primary']) {
|
||||||
|
$button_class .= ' button-primary go-pro-button';
|
||||||
|
} else {
|
||||||
|
// Add green styling to secondary buttons
|
||||||
|
$button_class .= ' green-button-secondary';
|
||||||
|
// Special handling for Pricing buttons
|
||||||
|
if ($button['text'] === 'Pricing') {
|
||||||
|
$button_class .= ' pricing-button';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<a href="<?php echo esc_url($button['url']); ?>" target="_blank" class="<?php echo esc_attr($button_class); ?>">
|
||||||
|
<?php echo esc_html($button['text']); ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of hosting providers
|
||||||
|
*
|
||||||
|
* @return array Array of hosting providers
|
||||||
|
*/
|
||||||
|
public static function get_hosting_providers() {
|
||||||
|
// Define the providers data if it hasn't been included yet
|
||||||
|
if (!function_exists('wp_allstars_get_hosting_providers')) {
|
||||||
|
require_once dirname(dirname(__FILE__)) . '/data/hosting-providers.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
return wp_allstars_get_hosting_providers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue styles for the hosting tab
|
||||||
|
*
|
||||||
|
* @param string $hook Current admin page hook
|
||||||
|
*/
|
||||||
|
public static function enqueue_styles($hook) {
|
||||||
|
if ('settings_page_wp-allstars' !== $hook) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_enqueue_style(
|
||||||
|
'wp-allstars-admin',
|
||||||
|
plugins_url('css/wp-allstars-admin.css', dirname(__FILE__)),
|
||||||
|
array(),
|
||||||
|
WP_ALLSTARS_VERSION
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add inline CSS for hosting to match the single column layout
|
||||||
|
$custom_css = '
|
||||||
|
#hosting .wpa-pro-plugins {
|
||||||
|
padding: 15px 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
max-width: 700px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
#hosting .wpa-pro-plugin {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
#hosting .wpa-pro-plugin:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
#hosting .wpa-pro-plugin:hover {
|
||||||
|
border-color: #2271b1;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
#hosting .wpa-pro-plugin .button-group {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
';
|
||||||
|
|
||||||
|
wp_add_inline_style('wp-allstars-admin', $custom_css);
|
||||||
|
}
|
||||||
|
}
|
363
admin/includes/class-plugin-manager.php
Normal file
363
admin/includes/class-plugin-manager.php
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* WP ALLSTARS Plugin Manager
|
||||||
|
*
|
||||||
|
* Core class for handling WordPress plugin data and operations:
|
||||||
|
* - Plugin data retrieval and caching mechanism
|
||||||
|
* - AJAX handlers for asynchronous plugin data loading
|
||||||
|
* - Plugin card UI generation with install/update actions
|
||||||
|
* - Cache clearing on plugin changes
|
||||||
|
*
|
||||||
|
* @package WP_ALLSTARS
|
||||||
|
* @since 0.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WP_Allstars_Plugin_Manager class
|
||||||
|
*
|
||||||
|
* Manages the Free Plugins tab and provides core plugin functionality
|
||||||
|
* for other plugin-related managers.
|
||||||
|
*/
|
||||||
|
class WP_Allstars_Plugin_Manager {
|
||||||
|
/**
|
||||||
|
* Initialize the class and register all action hooks
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function init() {
|
||||||
|
// Register AJAX handler for plugin data retrieval
|
||||||
|
add_action('wp_ajax_wp_allstars_get_plugins', [self::class, 'ajax_get_plugins']);
|
||||||
|
|
||||||
|
// Register hooks for automatic cache clearing when plugins change
|
||||||
|
add_action('upgrader_process_complete', [self::class, 'clear_plugin_cache'], 10, 0);
|
||||||
|
add_action('activated_plugin', [self::class, 'clear_plugin_cache']);
|
||||||
|
add_action('deactivated_plugin', [self::class, 'clear_plugin_cache']);
|
||||||
|
add_action('deleted_plugin', [self::class, 'clear_plugin_cache']);
|
||||||
|
add_action('update_option_active_plugins', [self::class, 'clear_plugin_cache']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cached plugin data for a specific category
|
||||||
|
*
|
||||||
|
* Uses the WordPress transients API to store plugin data
|
||||||
|
* for improved performance and reduced API calls.
|
||||||
|
*
|
||||||
|
* @param string $category The plugin category to retrieve (e.g., 'featured', 'popular')
|
||||||
|
* @return mixed Array of plugin data if cache exists, false otherwise
|
||||||
|
*/
|
||||||
|
public static function get_cached_plugins($category) {
|
||||||
|
$cache_key = 'wp_allstars_plugins_' . sanitize_key($category);
|
||||||
|
$cached_data = get_transient($cache_key);
|
||||||
|
|
||||||
|
if ($cached_data !== false) {
|
||||||
|
return $cached_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set cached plugin data for a category
|
||||||
|
*
|
||||||
|
* @param string $category The plugin category
|
||||||
|
* @param mixed $data The data to cache
|
||||||
|
*/
|
||||||
|
public static function set_cached_plugins($category, $data) {
|
||||||
|
$cache_key = 'wp_allstars_plugins_' . $category;
|
||||||
|
set_transient($cache_key, $data, 12 * HOUR_IN_SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AJAX handler for getting plugin data
|
||||||
|
*/
|
||||||
|
public static function ajax_get_plugins() {
|
||||||
|
// Check nonce with the correct action name
|
||||||
|
if (!check_ajax_referer('wp-allstars-nonce', false, false)) {
|
||||||
|
wp_send_json_error('Invalid security token sent.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!current_user_can('install_plugins')) {
|
||||||
|
wp_die(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$category = isset($_POST['category']) ? sanitize_key($_POST['category']) : 'minimal';
|
||||||
|
|
||||||
|
require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
|
||||||
|
|
||||||
|
// Get our recommended plugins for this category
|
||||||
|
$recommended_plugins = wp_allstars_get_free_plugins();
|
||||||
|
if (!isset($recommended_plugins[$category])) {
|
||||||
|
wp_send_json_error('Invalid category: ' . $category);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to get cached data first
|
||||||
|
$cached_data = self::get_cached_plugins($category);
|
||||||
|
if ($cached_data !== false) {
|
||||||
|
error_log('Using cached data for category: ' . $category);
|
||||||
|
try {
|
||||||
|
// Generate plugin cards HTML
|
||||||
|
$html = self::generate_plugin_cards($cached_data->plugins);
|
||||||
|
wp_send_json_success($html);
|
||||||
|
return;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('Error displaying cached plugins: ' . $e->getMessage());
|
||||||
|
// Fall through to fetch fresh data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log('Fetching fresh data for category: ' . $category);
|
||||||
|
error_log('Plugins to fetch: ' . implode(', ', $recommended_plugins[$category]));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$plugins = array();
|
||||||
|
|
||||||
|
// Only fetch plugins that are in our recommended list for this category
|
||||||
|
foreach ($recommended_plugins[$category] as $slug) {
|
||||||
|
try {
|
||||||
|
error_log('Fetching plugin data for: ' . $slug);
|
||||||
|
$plugin_data = plugins_api('plugin_information', array(
|
||||||
|
'slug' => $slug,
|
||||||
|
'fields' => array(
|
||||||
|
'short_description' => true,
|
||||||
|
'sections' => false,
|
||||||
|
'requires' => true,
|
||||||
|
'rating' => true,
|
||||||
|
'ratings' => false,
|
||||||
|
'downloaded' => true,
|
||||||
|
'last_updated' => true,
|
||||||
|
'added' => false,
|
||||||
|
'tags' => false,
|
||||||
|
'compatibility' => false,
|
||||||
|
'homepage' => true,
|
||||||
|
'versions' => false,
|
||||||
|
'donate_link' => false,
|
||||||
|
'reviews' => false,
|
||||||
|
'banners' => false,
|
||||||
|
'icons' => true,
|
||||||
|
'active_installs' => true,
|
||||||
|
'group' => false,
|
||||||
|
'contributors' => false,
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
if (is_wp_error($plugin_data)) {
|
||||||
|
error_log('Error fetching plugin data for ' . $slug . ': ' . $plugin_data->get_error_message());
|
||||||
|
} else {
|
||||||
|
$plugins[] = $plugin_data;
|
||||||
|
error_log('Successfully fetched data for: ' . $slug);
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('Exception fetching plugin data for ' . $slug . ': ' . $e->getMessage());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($plugins)) {
|
||||||
|
wp_send_json_error('No plugin data could be retrieved for category: ' . $category);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log('Total plugins fetched: ' . count($plugins));
|
||||||
|
|
||||||
|
// Create response object
|
||||||
|
$res = (object) array(
|
||||||
|
'info' => array(
|
||||||
|
'page' => 1,
|
||||||
|
'pages' => 1,
|
||||||
|
'results' => count($plugins),
|
||||||
|
),
|
||||||
|
'plugins' => $plugins
|
||||||
|
);
|
||||||
|
|
||||||
|
// Cache the results
|
||||||
|
self::set_cached_plugins($category, $res);
|
||||||
|
|
||||||
|
// Generate plugin cards HTML
|
||||||
|
$html = self::generate_plugin_cards($plugins);
|
||||||
|
wp_send_json_success($html);
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('Failed to fetch plugin data: ' . $e->getMessage());
|
||||||
|
wp_send_json_error('Failed to fetch plugin data: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate HTML for plugin cards
|
||||||
|
*
|
||||||
|
* @param array $plugins Array of plugin data
|
||||||
|
* @return string HTML for the plugin cards
|
||||||
|
*/
|
||||||
|
public static function generate_plugin_cards($plugins) {
|
||||||
|
if (empty($plugins)) {
|
||||||
|
return '<div class="notice notice-error"><p>No plugins found.</p></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
?>
|
||||||
|
<div class="wp-list-table widefat plugin-install">
|
||||||
|
<div id="the-list">
|
||||||
|
<?php foreach ($plugins as $plugin): ?>
|
||||||
|
<div class="plugin-card plugin-card-<?php echo esc_attr($plugin->slug); ?>">
|
||||||
|
<div class="plugin-card-top">
|
||||||
|
<div class="name column-name">
|
||||||
|
<h3>
|
||||||
|
<?php echo esc_html($plugin->name); ?>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="action-links">
|
||||||
|
<ul class="plugin-action-buttons">
|
||||||
|
<?php
|
||||||
|
$status = install_plugin_install_status($plugin);
|
||||||
|
switch ($status['status']) {
|
||||||
|
case 'install':
|
||||||
|
echo '<li><a class="button install-now" data-slug="' . esc_attr($plugin->slug) . '" href="' . esc_url($status['url']) . '" aria-label="' . esc_attr(sprintf(__('Install %s now'), $plugin->name)) . '">' . __('Install now') . '</a></li>';
|
||||||
|
break;
|
||||||
|
case 'update_available':
|
||||||
|
echo '<li><a class="button button-primary update-now" data-plugin="' . esc_attr($status['file']) . '" data-slug="' . esc_attr($plugin->slug) . '" href="' . esc_url($status['url']) . '" aria-label="' . esc_attr(sprintf(__('Update %s now'), $plugin->name)) . '">' . __('Update Now') . '</a></li>';
|
||||||
|
break;
|
||||||
|
case 'latest_installed':
|
||||||
|
case 'newer_installed':
|
||||||
|
if (is_plugin_active($status['file'])) {
|
||||||
|
echo '<li><button type="button" class="button button-disabled" disabled="disabled">' . __('Active') . '</button></li>';
|
||||||
|
} else {
|
||||||
|
echo '<li><a class="button button-primary activate-now" href="' . esc_url(wp_nonce_url('plugins.php?action=activate&plugin=' . $status['file'], 'activate-plugin_' . $status['file'])) . '" aria-label="' . esc_attr(sprintf(__('Activate %s'), $plugin->name)) . '">' . __('Activate') . '</a></li>';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add PRO button if available
|
||||||
|
self::add_pro_button($plugin);
|
||||||
|
|
||||||
|
// Add "More Details" link
|
||||||
|
echo '<li><a class="thickbox open-plugin-details-modal" href="' . esc_url(admin_url('plugin-install.php?tab=plugin-information&plugin=' . $plugin->slug . '&TB_iframe=true&width=600&height=550')) . '" aria-label="' . esc_attr(sprintf(__('More information about %s'), $plugin->name)) . '">' . __('More Details') . '</a></li>';
|
||||||
|
?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<?php if (!empty($plugin->icons) && !empty($plugin->icons['1x'])): ?>
|
||||||
|
<div class="plugin-icon">
|
||||||
|
<img src="<?php echo esc_url($plugin->icons['1x']); ?>" alt="">
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="desc column-description">
|
||||||
|
<p><?php echo esc_html($plugin->short_description); ?></p>
|
||||||
|
<p class="authors">
|
||||||
|
<cite><?php printf(__('By %s'), $plugin->author); ?></cite>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="plugin-card-bottom">
|
||||||
|
<div class="vers column-rating">
|
||||||
|
<?php wp_star_rating(array('rating' => $plugin->rating, 'type' => 'percent', 'number' => $plugin->num_ratings)); ?>
|
||||||
|
<span class="num-ratings" aria-hidden="true">(<?php echo number_format_i18n($plugin->num_ratings); ?>)</span>
|
||||||
|
</div>
|
||||||
|
<div class="column-updated">
|
||||||
|
<strong><?php _e('Last Updated:'); ?></strong>
|
||||||
|
<?php printf(__('%s ago'), human_time_diff(strtotime($plugin->last_updated))); ?>
|
||||||
|
</div>
|
||||||
|
<div class="column-downloaded">
|
||||||
|
<?php
|
||||||
|
if ($plugin->active_installs >= 1000000) {
|
||||||
|
$active_installs_millions = floor($plugin->active_installs / 1000000);
|
||||||
|
$active_installs_text = sprintf(
|
||||||
|
_n('%s+ Million Active Installations', '%s+ Million Active Installations', $active_installs_millions),
|
||||||
|
number_format_i18n($active_installs_millions)
|
||||||
|
);
|
||||||
|
} elseif (0 == $plugin->active_installs) {
|
||||||
|
$active_installs_text = _x('Less Than 10 Active Installations', 'Active plugin installations');
|
||||||
|
} else {
|
||||||
|
$active_installs_text = sprintf(
|
||||||
|
_n('%s+ Active Installation', '%s+ Active Installations', $plugin->active_installs),
|
||||||
|
number_format_i18n($plugin->active_installs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/* translators: %s: number of active installations */
|
||||||
|
echo esc_html($active_installs_text);
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<div class="column-compatibility">
|
||||||
|
<?php
|
||||||
|
$version = get_bloginfo('version');
|
||||||
|
if (!empty($plugin->tested) && version_compare($version, $plugin->tested, '>')) {
|
||||||
|
echo '<span class="compatibility-untested">' . __('Untested with your version of WordPress') . '</span>';
|
||||||
|
} elseif (!empty($plugin->requires) && version_compare($version, $plugin->requires, '<')) {
|
||||||
|
echo '<span class="compatibility-incompatible">' . __('Incompatible with your version of WordPress') . '</span>';
|
||||||
|
} else {
|
||||||
|
echo '<span class="compatibility-compatible">' . __('Compatible with your version of WordPress') . '</span>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add PRO button to plugin cards if a pro version exists
|
||||||
|
*
|
||||||
|
* @param object $plugin The plugin object
|
||||||
|
*/
|
||||||
|
public static function add_pro_button($plugin) {
|
||||||
|
$pro_plugins = wp_allstars_get_pro_plugins();
|
||||||
|
|
||||||
|
if (isset($pro_plugins[$plugin->slug])) {
|
||||||
|
$pro_plugin = $pro_plugins[$plugin->slug];
|
||||||
|
$pro_url = self::get_pro_plugin_url($pro_plugin);
|
||||||
|
|
||||||
|
if (!empty($pro_url)) {
|
||||||
|
echo '<li><a href="' . esc_url($pro_url) . '" target="_blank" class="button button-primary go-pro-button">' . esc_html__('Go Pro', 'wp-allstars') . '</a></li>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the URL for a pro plugin from its config
|
||||||
|
*
|
||||||
|
* @param array $pro_plugin The pro plugin configuration array
|
||||||
|
* @return string The URL for the pro plugin
|
||||||
|
*/
|
||||||
|
public static function get_pro_plugin_url($pro_plugin) {
|
||||||
|
// First check if there's a button_group defined
|
||||||
|
if (isset($pro_plugin['button_group']) && is_array($pro_plugin['button_group'])) {
|
||||||
|
foreach ($pro_plugin['button_group'] as $button) {
|
||||||
|
// Return the URL for the primary button if available
|
||||||
|
if (isset($button['primary']) && $button['primary'] && !empty($button['url'])) {
|
||||||
|
return $button['url'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no primary button found, return the first button URL
|
||||||
|
if (!empty($pro_plugin['button_group'][0]['url'])) {
|
||||||
|
return $pro_plugin['button_group'][0]['url'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to the main URL if available
|
||||||
|
if (!empty($pro_plugin['url'])) {
|
||||||
|
return $pro_plugin['url'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear plugin cache when plugins are updated, activated, or deactivated
|
||||||
|
*/
|
||||||
|
public static function clear_plugin_cache() {
|
||||||
|
$recommended_plugins = wp_allstars_get_free_plugins();
|
||||||
|
foreach (array_keys($recommended_plugins) as $category) {
|
||||||
|
delete_transient('wp_allstars_plugins_' . $category);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
227
admin/includes/class-pro-plugins-manager.php
Normal file
227
admin/includes/class-pro-plugins-manager.php
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* WP ALLSTARS Pro Plugins Manager
|
||||||
|
*
|
||||||
|
* Handles premium plugin recommendations including:
|
||||||
|
* - Premium plugin information display
|
||||||
|
* - Purchase links and affiliate management
|
||||||
|
* - Plugin feature highlighting
|
||||||
|
* - Price and promotion display
|
||||||
|
*
|
||||||
|
* @package WP_ALLSTARS
|
||||||
|
* @since 0.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
// If this file is called directly, abort.
|
||||||
|
if (!defined('WPINC')) {
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WP_Allstars_Pro_Plugins_Manager class
|
||||||
|
*
|
||||||
|
* Responsible for the Pro Plugins tab in the plugin interface.
|
||||||
|
*/
|
||||||
|
class WP_Allstars_Pro_Plugins_Manager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the class and register required hooks
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function init() {
|
||||||
|
// Enqueue pro plugins specific styles
|
||||||
|
add_action('admin_enqueue_scripts', array(self::class, 'enqueue_styles'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all pro plugin configurations
|
||||||
|
*
|
||||||
|
* Retrieves premium plugin information from configuration,
|
||||||
|
* including pricing, features, and purchase links.
|
||||||
|
*
|
||||||
|
* @return array Array of premium plugin data
|
||||||
|
*/
|
||||||
|
public static function get_pro_plugins() {
|
||||||
|
// Load pro plugin configuration from the data file
|
||||||
|
return wp_allstars_get_pro_plugins();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the pro plugins tab content
|
||||||
|
*
|
||||||
|
* Renders the premium plugins tab with plugin cards
|
||||||
|
* in alphabetical order by name.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function display_tab_content() {
|
||||||
|
// Get premium plugin data
|
||||||
|
$pro_plugins = self::get_pro_plugins();
|
||||||
|
|
||||||
|
// Sort plugins alphabetically by name for consistent display
|
||||||
|
uasort($pro_plugins, function($a, $b) {
|
||||||
|
return strcasecmp($a['name'], $b['name']);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start the tab content container
|
||||||
|
echo '<div class="wp-allstars-settings-content tab-content" id="pro"><div class="wpa-pro-plugins">';
|
||||||
|
|
||||||
|
// Render each plugin card
|
||||||
|
foreach ($pro_plugins as $plugin) {
|
||||||
|
self::display_plugin_card($plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the container
|
||||||
|
echo '</div></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a single plugin card
|
||||||
|
*
|
||||||
|
* @param array $plugin Plugin configuration
|
||||||
|
*/
|
||||||
|
public static function display_plugin_card($plugin) {
|
||||||
|
?>
|
||||||
|
<div class="wpa-pro-plugin">
|
||||||
|
<h3><?php echo esc_html($plugin['name']); ?></h3>
|
||||||
|
<p><?php echo esc_html($plugin['description']); ?></p>
|
||||||
|
<?php if (isset($plugin['button_group'])): ?>
|
||||||
|
<div class="button-group">
|
||||||
|
<?php foreach ($plugin['button_group'] as $button): ?>
|
||||||
|
<?php
|
||||||
|
$button_class = 'button';
|
||||||
|
if (isset($button['primary']) && $button['primary']) {
|
||||||
|
$button_class .= ' button-primary';
|
||||||
|
// Add green color to 'Go Pro' buttons
|
||||||
|
if ($button['text'] === 'Go Pro') {
|
||||||
|
$button_class .= ' go-pro-button';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Add green styling to secondary buttons
|
||||||
|
$button_class .= ' green-button-secondary';
|
||||||
|
// Special handling for Pricing buttons
|
||||||
|
if ($button['text'] === 'Pricing') {
|
||||||
|
$button_class .= ' pricing-button';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<a href="<?php echo esc_url($button['url']); ?>" target="_blank" class="<?php echo esc_attr($button_class); ?>">
|
||||||
|
<?php echo esc_html($button['text']); ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="button-group">
|
||||||
|
<?php if (!empty($plugin['demo_url'])): ?>
|
||||||
|
<a href="<?php echo esc_url($plugin['demo_url']); ?>" class="button green-button-secondary" 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 go-pro-button" target="_blank">
|
||||||
|
<?php esc_html_e('Learn More', 'wp-allstars'); ?>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue styles specific to pro plugins
|
||||||
|
*/
|
||||||
|
public static function enqueue_styles($hook) {
|
||||||
|
// Only load on the plugin settings page
|
||||||
|
if (strpos($hook, 'wp-allstars') === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add inline CSS for pro plugins
|
||||||
|
$custom_css = '
|
||||||
|
.wpa-pro-plugins {
|
||||||
|
padding: 15px 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
max-width: 700px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.wpa-pro-plugin {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
.wpa-pro-plugin:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.wpa-pro-plugin:hover {
|
||||||
|
border-color: #2271b1;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
.wpa-pro-plugin h3 {
|
||||||
|
margin: 0 0 12px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d2327;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
.wpa-pro-plugin p {
|
||||||
|
margin: 0 0 16px;
|
||||||
|
color: #50575e;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.wpa-pro-plugin .button-group {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: auto;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
.wpa-pro-plugin .button {
|
||||||
|
text-decoration: none;
|
||||||
|
min-width: 120px;
|
||||||
|
text-align: center;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 28px;
|
||||||
|
padding: 0 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: normal;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
.wpa-pro-plugin .button:hover {
|
||||||
|
background: #f0f0f1;
|
||||||
|
border-color: #0071a1;
|
||||||
|
color: #0071a1;
|
||||||
|
}
|
||||||
|
.wpa-pro-plugin .button-primary {
|
||||||
|
background: #0071a1;
|
||||||
|
border-color: #0071a1;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.wpa-pro-plugin .button-primary:hover {
|
||||||
|
background: #006291;
|
||||||
|
border-color: #006291;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
';
|
||||||
|
|
||||||
|
wp_add_inline_style('wp-allstars-admin', $custom_css);
|
||||||
|
}
|
||||||
|
}
|
126
admin/includes/class-readme-manager.php
Normal file
126
admin/includes/class-readme-manager.php
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Read Me Manager Class
|
||||||
|
*
|
||||||
|
* @package WP_ALLSTARS
|
||||||
|
* @since 0.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WP_Allstars_Readme_Manager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the class
|
||||||
|
*/
|
||||||
|
public static function init() {
|
||||||
|
add_action('admin_enqueue_scripts', array(__CLASS__, 'enqueue_styles'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue styles for the readme tab
|
||||||
|
*
|
||||||
|
* @param string $hook Current admin page hook
|
||||||
|
*/
|
||||||
|
public static function enqueue_styles($hook) {
|
||||||
|
if ('settings_page_wp-allstars' !== $hook) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_enqueue_style(
|
||||||
|
'wp-allstars-admin',
|
||||||
|
plugins_url('css/wp-allstars-admin.css', dirname(__FILE__)),
|
||||||
|
array(),
|
||||||
|
WP_ALLSTARS_VERSION
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the readme content
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function get_readme_content() {
|
||||||
|
return wp_allstars_get_readme_content();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the readme tab content
|
||||||
|
*/
|
||||||
|
public static function display_tab_content() {
|
||||||
|
$readme = self::get_readme_content();
|
||||||
|
|
||||||
|
?>
|
||||||
|
<div class="wp-allstars-settings-content tab-content" id="readme">
|
||||||
|
<div class="wpa-pro-plugins">
|
||||||
|
<div class="wpa-pro-plugin">
|
||||||
|
<div class="wp-allstars-markdown-content">
|
||||||
|
<?php echo self::parse_markdown($readme['content']); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse markdown content to HTML
|
||||||
|
*
|
||||||
|
* A simple markdown parser for basic formatting
|
||||||
|
*
|
||||||
|
* @param string $markdown The markdown content
|
||||||
|
* @return string The HTML content
|
||||||
|
*/
|
||||||
|
private static function parse_markdown($markdown) {
|
||||||
|
// Replace version placeholder with actual version
|
||||||
|
$markdown = str_replace('{WP_ALLSTARS_VERSION}', WP_ALLSTARS_VERSION, $markdown);
|
||||||
|
|
||||||
|
// Headers
|
||||||
|
$markdown = preg_replace('/^### (.*?)$/m', '<h3>$1</h3>', $markdown);
|
||||||
|
$markdown = preg_replace('/^## (.*?)$/m', '<h2>$1</h2>', $markdown);
|
||||||
|
$markdown = preg_replace('/^# (.*?)$/m', '<h1>$1</h1>', $markdown);
|
||||||
|
|
||||||
|
// Bold and Italic
|
||||||
|
$markdown = preg_replace('/\*\*(.*?)\*\*/s', '<strong>$1</strong>', $markdown);
|
||||||
|
$markdown = preg_replace('/\*(.*?)\*/s', '<em>$1</em>', $markdown);
|
||||||
|
|
||||||
|
// Process lists first - identify all list items
|
||||||
|
$markdown = preg_replace('/^- (.*?)$/m', '<li class="bullet-item">$1</li>', $markdown);
|
||||||
|
$markdown = preg_replace('/^\* (.*?)$/m', '<li class="bullet-item">$1</li>', $markdown);
|
||||||
|
$markdown = preg_replace('/^\d+\. (.*?)$/m', '<li class="number-item">$1</li>', $markdown);
|
||||||
|
|
||||||
|
// Group consecutive list items into appropriate list types
|
||||||
|
// First group bullet items into unordered lists
|
||||||
|
$markdown = preg_replace('/((?:<li class="bullet-item">.*?<\/li>\n)+)/s', '<ul class="wp-allstars-ul">$1</ul>', $markdown);
|
||||||
|
|
||||||
|
// Then group numbered items into ordered lists with a special class for indentation
|
||||||
|
$markdown = preg_replace('/((?:<li class="number-item">.*?<\/li>\n)+)/s', '<ol class="wp-allstars-ol numbered-list">$1</ol>', $markdown);
|
||||||
|
|
||||||
|
// Clean up the classes from the final output
|
||||||
|
$markdown = str_replace('class="bullet-item"', '', $markdown);
|
||||||
|
$markdown = str_replace('class="number-item"', '', $markdown);
|
||||||
|
$markdown = str_replace('class="wp-allstars-ul"', 'class="wp-allstars-list"', $markdown);
|
||||||
|
$markdown = str_replace('class="wp-allstars-ol numbered-list"', 'class="wp-allstars-list numbered-list"', $markdown);
|
||||||
|
|
||||||
|
// Links
|
||||||
|
$markdown = preg_replace('/\[(.*?)\]\((.*?)\)/s', '<a href="$2" target="_blank">$1</a>', $markdown);
|
||||||
|
|
||||||
|
// Paragraphs
|
||||||
|
$markdown = preg_replace('/^(?!<[a-z]).+$/m', '<p>$0</p>', $markdown);
|
||||||
|
|
||||||
|
// Fix multiple paragraph tags
|
||||||
|
$markdown = str_replace('<p><p>', '<p>', $markdown);
|
||||||
|
$markdown = str_replace('</p></p>', '</p>', $markdown);
|
||||||
|
|
||||||
|
// Fix lists within paragraphs
|
||||||
|
$markdown = str_replace('<p><ul>', '<ul>', $markdown);
|
||||||
|
$markdown = str_replace('</ul></p>', '</ul>', $markdown);
|
||||||
|
|
||||||
|
return $markdown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the class
|
||||||
|
WP_Allstars_Readme_Manager::init();
|
168
admin/includes/class-settings-manager.php
Normal file
168
admin/includes/class-settings-manager.php
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Settings Manager Class
|
||||||
|
*
|
||||||
|
* Handles the display and management of plugin settings tabs (General and Advanced).
|
||||||
|
*/
|
||||||
|
|
||||||
|
// If this file is called directly, abort.
|
||||||
|
if ( ! defined( 'WPINC' ) ) {
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WP_Allstars_Settings_Manager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the class
|
||||||
|
*/
|
||||||
|
public static function init() {
|
||||||
|
// Register settings
|
||||||
|
add_action('admin_init', array(self::class, 'register_settings'));
|
||||||
|
|
||||||
|
// Enqueue scripts and styles if needed
|
||||||
|
add_action('admin_enqueue_scripts', array(self::class, 'enqueue_scripts'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register plugin settings
|
||||||
|
*/
|
||||||
|
public static function register_settings() {
|
||||||
|
// General settings
|
||||||
|
register_setting('wp_allstars_settings', 'wp_allstars_simple_setting');
|
||||||
|
|
||||||
|
// Advanced settings
|
||||||
|
register_setting('wp_allstars_settings', 'wp_allstars_auto_upload_images');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue scripts and styles needed for settings
|
||||||
|
*/
|
||||||
|
public static function enqueue_scripts($hook) {
|
||||||
|
// Only load on the plugin settings page
|
||||||
|
if (strpos($hook, 'wp-allstars') === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add inline JS for toggle functionality
|
||||||
|
$toggle_js = '
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
// Toggle expandable settings panels
|
||||||
|
$(".wp-allstars-toggle-header").on("click", function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var $settings = $this.next(".wp-allstars-toggle-settings");
|
||||||
|
var isExpanded = $this.attr("aria-expanded") === "true";
|
||||||
|
|
||||||
|
// Toggle aria-expanded attribute
|
||||||
|
$this.attr("aria-expanded", !isExpanded);
|
||||||
|
|
||||||
|
// Toggle settings visibility
|
||||||
|
$settings.slideToggle(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
';
|
||||||
|
|
||||||
|
wp_add_inline_script('wp-allstars-admin', $toggle_js);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the general tab content
|
||||||
|
*/
|
||||||
|
public static function display_general_tab() {
|
||||||
|
?>
|
||||||
|
<div class="wp-allstars-settings-section">
|
||||||
|
<div class="wp-allstars-settings-grid">
|
||||||
|
<!-- Example of a simple toggle setting (no panel) -->
|
||||||
|
<div class="wp-setting-row">
|
||||||
|
<div class="wp-setting-header">
|
||||||
|
<div class="wp-setting-main">
|
||||||
|
<div class="wp-setting-left">
|
||||||
|
<div class="wp-toggle-switch">
|
||||||
|
<input type="checkbox"
|
||||||
|
id="wp_allstars_simple_setting"
|
||||||
|
name="wp_allstars_simple_setting"
|
||||||
|
value="1"
|
||||||
|
<?php checked(get_option('wp_allstars_simple_setting', false)); ?>
|
||||||
|
/>
|
||||||
|
<span class="wp-toggle-slider"></span>
|
||||||
|
</div>
|
||||||
|
<label for="wp_allstars_simple_setting" class="wp-setting-label">
|
||||||
|
<?php esc_html_e('Example: Simple Toggle', 'wp-allstars'); ?>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="wp-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'); ?>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the advanced tab content
|
||||||
|
*/
|
||||||
|
public static function display_advanced_tab() {
|
||||||
|
?>
|
||||||
|
<div class="wp-allstars-settings-section">
|
||||||
|
<div class="wp-allstars-settings-grid">
|
||||||
|
<!-- Example of an expandable panel setting -->
|
||||||
|
<div class="wp-allstars-toggle">
|
||||||
|
<div class="wp-allstars-toggle-header" aria-expanded="false">
|
||||||
|
<div class="wp-allstars-toggle-main">
|
||||||
|
<div class="wp-allstars-toggle-left">
|
||||||
|
<div class="wp-toggle-switch">
|
||||||
|
<input type="checkbox"
|
||||||
|
id="wp_allstars_auto_upload_images"
|
||||||
|
name="wp_allstars_auto_upload_images"
|
||||||
|
value="1"
|
||||||
|
<?php checked(get_option('wp_allstars_auto_upload_images', false)); ?>
|
||||||
|
/>
|
||||||
|
<span class="wp-toggle-slider"></span>
|
||||||
|
</div>
|
||||||
|
<label for="wp_allstars_auto_upload_images">
|
||||||
|
<?php esc_html_e('Example: Expandable Panel', 'wp-allstars'); ?>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="wp-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'); ?>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="wp-allstars-toggle-settings">
|
||||||
|
<div class="wp-allstars-setting-row">
|
||||||
|
<label for="example_text"><?php esc_html_e('Example Text Field', 'wp-allstars'); ?></label>
|
||||||
|
<input type="text"
|
||||||
|
id="example_text"
|
||||||
|
name="example_text"
|
||||||
|
value="Example value"
|
||||||
|
/>
|
||||||
|
<p class="description"><?php esc_html_e('This is an example text field for demonstration purposes.', 'wp-allstars'); ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save settings
|
||||||
|
*/
|
||||||
|
public static function save_settings() {
|
||||||
|
// Check for nonce
|
||||||
|
if (!isset($_POST['wp_allstars_settings_nonce']) || !wp_verify_nonce($_POST['wp_allstars_settings_nonce'], 'wp_allstars_save_settings')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save general settings
|
||||||
|
update_option('wp_allstars_simple_setting', isset($_POST['wp_allstars_simple_setting']) ? 1 : 0);
|
||||||
|
|
||||||
|
// Save advanced settings
|
||||||
|
update_option('wp_allstars_auto_upload_images', isset($_POST['wp_allstars_auto_upload_images']) ? 1 : 0);
|
||||||
|
|
||||||
|
// Add settings saved notice
|
||||||
|
add_settings_error('wp_allstars_settings', 'settings_updated', __('Settings saved.', 'wp-allstars'), 'updated');
|
||||||
|
}
|
||||||
|
}
|
329
admin/includes/class-theme-manager.php
Normal file
329
admin/includes/class-theme-manager.php
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* WP ALLSTARS Theme Manager
|
||||||
|
*
|
||||||
|
* Manages the Theme tab functionality including:
|
||||||
|
* - Theme data retrieval and caching
|
||||||
|
* - AJAX handlers for theme browsing
|
||||||
|
* - Theme activation and installation
|
||||||
|
* - Theme UI rendering
|
||||||
|
*
|
||||||
|
* @package WP_ALLSTARS
|
||||||
|
* @since 0.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
// If this file is called directly, abort.
|
||||||
|
if (!defined('WPINC')) {
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WP_Allstars_Theme_Manager class
|
||||||
|
*
|
||||||
|
* Provides theme discovery and management functionality
|
||||||
|
*/
|
||||||
|
class WP_Allstars_Theme_Manager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the class and register all action hooks
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function init() {
|
||||||
|
// Register AJAX handlers for theme operations
|
||||||
|
add_action('wp_ajax_wp_allstars_get_themes', array(self::class, 'ajax_get_themes'));
|
||||||
|
add_action('wp_ajax_wp_allstars_activate_theme', array(self::class, 'activate_theme'));
|
||||||
|
|
||||||
|
// Register hooks for automatic cache clearing when themes change
|
||||||
|
add_action('upgrader_process_complete', array(self::class, 'clear_theme_cache'), 10, 0);
|
||||||
|
add_action('switch_theme', array(self::class, 'clear_theme_cache'));
|
||||||
|
|
||||||
|
// Enqueue theme-specific assets when needed
|
||||||
|
add_action('admin_enqueue_scripts', array(self::class, 'enqueue_scripts'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue scripts and styles for the theme tab
|
||||||
|
*
|
||||||
|
* Loads necessary WordPress core scripts and stylesheets
|
||||||
|
* required for theme browsing and installation.
|
||||||
|
*
|
||||||
|
* @param string $hook The current admin page hook
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function enqueue_scripts($hook) {
|
||||||
|
// Only load on plugin pages
|
||||||
|
if (strpos($hook, 'wp-allstars') === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only load when theme tab is active
|
||||||
|
if (!isset($_GET['tab']) || $_GET['tab'] !== 'theme') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load WordPress core theme functionality
|
||||||
|
require_once ABSPATH . 'wp-admin/includes/theme.php';
|
||||||
|
|
||||||
|
// Enqueue core WordPress scripts for theme operations
|
||||||
|
wp_enqueue_script('theme-install');
|
||||||
|
wp_enqueue_script('updates');
|
||||||
|
add_thickbox();
|
||||||
|
|
||||||
|
// Enqueue theme tab specific styles
|
||||||
|
wp_enqueue_style(
|
||||||
|
'wp-allstars-admin',
|
||||||
|
plugins_url('css/wp-allstars-admin.css', dirname(__FILE__)),
|
||||||
|
array(),
|
||||||
|
WP_ALLSTARS_VERSION
|
||||||
|
);
|
||||||
|
wp_enqueue_style('wp-allstars-plugins', plugins_url('css/wp-allstars-plugins.css', dirname(__FILE__)));
|
||||||
|
|
||||||
|
// Enqueue the main admin script before adding inline script
|
||||||
|
wp_enqueue_script('wp-allstars-admin', plugins_url('js/wp-allstars-admin.js', dirname(__FILE__)), array('jquery'), '1.0.0', true);
|
||||||
|
|
||||||
|
// Localize the script with nonce data
|
||||||
|
wp_localize_script('wp-allstars-admin', 'wpAllstars', array(
|
||||||
|
'nonce' => wp_create_nonce('wp-allstars-nonce'),
|
||||||
|
'ajaxurl' => admin_url('admin-ajax.php')
|
||||||
|
));
|
||||||
|
|
||||||
|
// Add inline script for theme loading and interaction
|
||||||
|
wp_add_inline_script('wp-allstars-admin', self::get_theme_scripts());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get theme scripts for inline inclusion
|
||||||
|
*/
|
||||||
|
private static function get_theme_scripts() {
|
||||||
|
return '
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
if ($("#wpa-theme-list").length) {
|
||||||
|
var $container = $("#wpa-theme-list");
|
||||||
|
var $loadingOverlay = $container.find(".wp-allstars-loading-overlay");
|
||||||
|
|
||||||
|
// AJAX request to get themes
|
||||||
|
$.ajax({
|
||||||
|
url: wpAllstars.ajaxurl,
|
||||||
|
type: "POST",
|
||||||
|
data: {
|
||||||
|
action: "wp_allstars_get_themes",
|
||||||
|
_wpnonce: wpAllstars.nonce
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
$loadingOverlay.remove();
|
||||||
|
if (response.success) {
|
||||||
|
$container.html(response.data);
|
||||||
|
// Initialize theme handlers - use the global function from admin.js
|
||||||
|
if (typeof window.initThemeHandlers === "function") {
|
||||||
|
window.initThemeHandlers();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$container.html("<div class=\"notice notice-error\"><p>" + response.data + "</p></div>");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
$loadingOverlay.remove();
|
||||||
|
$container.html("<div class=\"notice notice-error\"><p>Failed to load themes. Please try again. Error: " + error + "</p></div>");
|
||||||
|
console.error("AJAX Error:", xhr.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the theme tab content
|
||||||
|
*/
|
||||||
|
public static function display_tab_content() {
|
||||||
|
?>
|
||||||
|
<div class="wp-allstars-settings-content tab-content" id="theme">
|
||||||
|
<div id="wpa-theme-list" class="wpa-theme-container">
|
||||||
|
<!-- Theme content will be loaded via AJAX -->
|
||||||
|
<div class="wp-allstars-loading-overlay">
|
||||||
|
<span class="spinner is-active"></span>
|
||||||
|
<p>Loading theme data...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cached theme
|
||||||
|
*/
|
||||||
|
public static function get_cached_theme() {
|
||||||
|
$cache_key = 'wp_allstars_theme_kadence';
|
||||||
|
return get_transient($cache_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set cached theme
|
||||||
|
*/
|
||||||
|
public static function set_cached_theme($data) {
|
||||||
|
$cache_key = 'wp_allstars_theme_kadence';
|
||||||
|
set_transient($cache_key, $data, 12 * HOUR_IN_SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear theme cache
|
||||||
|
*/
|
||||||
|
public static function clear_theme_cache() {
|
||||||
|
delete_transient('wp_allstars_theme_kadence');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AJAX endpoint for getting themes
|
||||||
|
*/
|
||||||
|
public static function ajax_get_themes() {
|
||||||
|
error_log('WP ALLSTARS: Theme AJAX handler started');
|
||||||
|
|
||||||
|
// Check nonce with the correct action name
|
||||||
|
if (!isset($_POST['_wpnonce'])) {
|
||||||
|
error_log('WP ALLSTARS: No nonce provided');
|
||||||
|
wp_send_json_error('No security token provided.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use verify_nonce instead of check_ajax_referer for more reliable verification
|
||||||
|
if (!wp_verify_nonce($_POST['_wpnonce'], 'wp-allstars-nonce')) {
|
||||||
|
error_log('WP ALLSTARS: Invalid nonce: ' . sanitize_text_field($_POST['_wpnonce']));
|
||||||
|
wp_send_json_error('Invalid security token sent.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!current_user_can('install_themes')) {
|
||||||
|
error_log('WP ALLSTARS: User does not have permission to install themes');
|
||||||
|
wp_send_json_error('Permission denied');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log('WP ALLSTARS: Starting theme fetch process');
|
||||||
|
|
||||||
|
try {
|
||||||
|
error_log('WP ALLSTARS: Fetching theme data for kadence');
|
||||||
|
|
||||||
|
// Check if we have cached data first
|
||||||
|
$theme_data = self::get_cached_theme();
|
||||||
|
|
||||||
|
// If no cached data, fetch from API
|
||||||
|
if (empty($theme_data)) {
|
||||||
|
error_log('WP ALLSTARS: No cached theme data, fetching from API');
|
||||||
|
|
||||||
|
// Get theme data with minimal fields
|
||||||
|
$theme_data = themes_api('theme_information', array(
|
||||||
|
'slug' => 'kadence',
|
||||||
|
'fields' => array(
|
||||||
|
'sections' => false,
|
||||||
|
'description' => true,
|
||||||
|
'rating' => true,
|
||||||
|
'ratings' => false,
|
||||||
|
'downloaded' => true,
|
||||||
|
'download_link' => true,
|
||||||
|
'last_updated' => true,
|
||||||
|
'homepage' => true,
|
||||||
|
'tags' => false,
|
||||||
|
'screenshot_url' => true,
|
||||||
|
'version' => true,
|
||||||
|
'requires' => true,
|
||||||
|
'requires_php' => true,
|
||||||
|
'active_installs' => true,
|
||||||
|
'author' => true,
|
||||||
|
'preview_url' => true,
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
// Cache the result if successful
|
||||||
|
if (!is_wp_error($theme_data)) {
|
||||||
|
self::set_cached_theme($theme_data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_log('WP ALLSTARS: Using cached theme data');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_wp_error($theme_data)) {
|
||||||
|
error_log('WP ALLSTARS Theme API Error: ' . $theme_data->get_error_message());
|
||||||
|
wp_send_json_error('Theme API Error: ' . $theme_data->get_error_message());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log('WP ALLSTARS: Successfully fetched theme data');
|
||||||
|
|
||||||
|
// Format author data
|
||||||
|
$author = '';
|
||||||
|
if (is_string($theme_data->author)) {
|
||||||
|
$author = $theme_data->author;
|
||||||
|
} elseif (is_array($theme_data->author)) {
|
||||||
|
$author = isset($theme_data->author['display_name']) ? $theme_data->author['display_name'] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log('WP ALLSTARS: Theme data retrieved, generating HTML');
|
||||||
|
|
||||||
|
// Generate custom HTML for the theme using our template partial
|
||||||
|
ob_start();
|
||||||
|
include(plugin_dir_path(dirname(__FILE__)) . 'partials/theme-panel.php');
|
||||||
|
$html = ob_get_clean();
|
||||||
|
|
||||||
|
if (empty($html)) {
|
||||||
|
error_log('WP ALLSTARS: Empty HTML generated');
|
||||||
|
wp_send_json_error('Failed to generate theme display');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log('WP ALLSTARS: Successfully generated theme display, HTML length: ' . strlen($html));
|
||||||
|
wp_send_json_success($html);
|
||||||
|
exit; // Ensure we exit after sending the JSON response
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('WP ALLSTARS Theme loading exception: ' . $e->getMessage());
|
||||||
|
error_log('WP ALLSTARS Theme loading exception trace: ' . $e->getTraceAsString());
|
||||||
|
wp_send_json_error('Theme loading error: ' . $e->getMessage());
|
||||||
|
} catch (Error $e) {
|
||||||
|
error_log('WP ALLSTARS Theme loading error: ' . $e->getMessage());
|
||||||
|
error_log('WP ALLSTARS Theme loading error trace: ' . $e->getTraceAsString());
|
||||||
|
wp_send_json_error('Theme loading error: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AJAX handler for theme activation
|
||||||
|
*/
|
||||||
|
public static function activate_theme() {
|
||||||
|
// Debug information
|
||||||
|
error_log('Theme activation AJAX request received: ' . print_r($_POST, true));
|
||||||
|
|
||||||
|
// Check nonce with the correct action name
|
||||||
|
if (!check_ajax_referer('wp-allstars-nonce', '_wpnonce', false)) {
|
||||||
|
error_log('Theme activation failed: Invalid nonce');
|
||||||
|
wp_send_json_error('Invalid security token sent.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!current_user_can('switch_themes')) {
|
||||||
|
error_log('Theme activation failed: Permission denied');
|
||||||
|
wp_send_json_error('Permission denied');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$theme = isset($_POST['theme']) ? sanitize_text_field($_POST['theme']) : '';
|
||||||
|
if (empty($theme)) {
|
||||||
|
error_log('Theme activation failed: No theme specified');
|
||||||
|
wp_send_json_error('No theme specified');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the theme object
|
||||||
|
$theme_obj = wp_get_theme($theme);
|
||||||
|
if (!$theme_obj->exists()) {
|
||||||
|
error_log('Theme activation failed: Theme does not exist - ' . $theme);
|
||||||
|
wp_send_json_error('Theme does not exist');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the new theme
|
||||||
|
switch_theme($theme);
|
||||||
|
error_log('Theme activation success - ' . $theme);
|
||||||
|
wp_send_json_success();
|
||||||
|
}
|
||||||
|
}
|
168
admin/includes/class-tools-manager.php
Normal file
168
admin/includes/class-tools-manager.php
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Tools Manager Class
|
||||||
|
*
|
||||||
|
* @package WP_ALLSTARS
|
||||||
|
* @since 0.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WP_Allstars_Tools_Manager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the class
|
||||||
|
*/
|
||||||
|
public static function init() {
|
||||||
|
add_action('admin_enqueue_scripts', array(__CLASS__, 'enqueue_styles'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue styles for the tools tab
|
||||||
|
*
|
||||||
|
* @param string $hook Current admin page hook
|
||||||
|
*/
|
||||||
|
public static function enqueue_styles($hook) {
|
||||||
|
if ('settings_page_wp-allstars' !== $hook) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_enqueue_style(
|
||||||
|
'wp-allstars-admin',
|
||||||
|
plugins_url('css/wp-allstars-admin.css', dirname(__FILE__)),
|
||||||
|
array(),
|
||||||
|
WP_ALLSTARS_VERSION
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add inline CSS for tools to match the single column layout
|
||||||
|
$custom_css = '
|
||||||
|
#tools .wpa-pro-plugins {
|
||||||
|
padding: 15px 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
max-width: 700px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
#tools .wpa-pro-plugin {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
#tools .wpa-pro-plugin:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
#tools .wpa-pro-plugin:hover {
|
||||||
|
border-color: #2271b1;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
#tools .wpa-pro-plugin .button-group {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
';
|
||||||
|
|
||||||
|
wp_add_inline_style('wp-allstars-admin', $custom_css);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all tools
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function get_tools() {
|
||||||
|
return wp_allstars_get_tools();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the tools tab content
|
||||||
|
*/
|
||||||
|
public static function display_tab_content() {
|
||||||
|
$tools = self::get_tools();
|
||||||
|
|
||||||
|
// Sort tools alphabetically by name
|
||||||
|
uasort($tools, function($a, $b) {
|
||||||
|
return strcasecmp($a['name'], $b['name']);
|
||||||
|
});
|
||||||
|
|
||||||
|
?>
|
||||||
|
<div class="wp-allstars-settings-content tab-content" id="tools">
|
||||||
|
<div class="wpa-pro-plugins">
|
||||||
|
<?php
|
||||||
|
foreach ($tools as $tool) {
|
||||||
|
self::display_tool_card(self::sanitize_tool_data($tool));
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a single tool card
|
||||||
|
*
|
||||||
|
* @param array $tool Sanitized tool configuration
|
||||||
|
*/
|
||||||
|
private static function display_tool_card($tool) {
|
||||||
|
// Ensure we have the required fields
|
||||||
|
if (empty($tool['name'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<div class="wpa-pro-plugin">
|
||||||
|
<h3><?php echo esc_html($tool['name']); ?></h3>
|
||||||
|
|
||||||
|
<?php if (!empty($tool['description'])): ?>
|
||||||
|
<p><?php echo esc_html($tool['description']); ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($tool['button_group']) && is_array($tool['button_group'])): ?>
|
||||||
|
<div class="button-group">
|
||||||
|
<?php foreach ($tool['button_group'] as $button): ?>
|
||||||
|
<?php if (!empty($button['url']) && !empty($button['text'])): ?>
|
||||||
|
<?php
|
||||||
|
$button_class = 'button';
|
||||||
|
if (!empty($button['primary'])) {
|
||||||
|
$button_class .= ' button-primary go-pro-button';
|
||||||
|
} else {
|
||||||
|
$button_class .= ' green-button-secondary';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<a
|
||||||
|
href="<?php echo esc_url($button['url']); ?>"
|
||||||
|
target="_blank"
|
||||||
|
class="<?php echo esc_attr($button_class); ?>"
|
||||||
|
>
|
||||||
|
<?php echo esc_html($button['text']); ?>
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitize tool data
|
||||||
|
*
|
||||||
|
* @param array $tool Raw tool data
|
||||||
|
* @return array Sanitized tool data
|
||||||
|
*/
|
||||||
|
private static function sanitize_tool_data($tool) {
|
||||||
|
return array(
|
||||||
|
'name' => isset($tool['name']) ? sanitize_text_field($tool['name']) : '',
|
||||||
|
'description' => isset($tool['description']) ? sanitize_text_field($tool['description']) : '',
|
||||||
|
'button_group' => isset($tool['button_group']) ? $tool['button_group'] : array(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
178
admin/includes/class-workflow-manager.php
Normal file
178
admin/includes/class-workflow-manager.php
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Workflow Manager Class
|
||||||
|
*
|
||||||
|
* @package WP_ALLSTARS
|
||||||
|
* @since 0.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WP_Allstars_Workflow_Manager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the class
|
||||||
|
*/
|
||||||
|
public static function init() {
|
||||||
|
add_action('admin_init', array(__CLASS__, 'register_settings'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register workflow settings
|
||||||
|
*/
|
||||||
|
public static function register_settings() {
|
||||||
|
register_setting('wp_allstars_workflow', 'wp_allstars_workflow_options');
|
||||||
|
register_setting('wp_allstars_workflow', 'wp_allstars_auto_upload_images');
|
||||||
|
register_setting('wp_allstars_workflow', 'wp_allstars_max_width');
|
||||||
|
register_setting('wp_allstars_workflow', 'wp_allstars_max_height');
|
||||||
|
register_setting('wp_allstars_workflow', 'wp_allstars_exclude_urls');
|
||||||
|
register_setting('wp_allstars_workflow', 'wp_allstars_image_name_pattern');
|
||||||
|
register_setting('wp_allstars_workflow', 'wp_allstars_image_alt_pattern');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the workflow tab content
|
||||||
|
*/
|
||||||
|
public static function display_tab_content() {
|
||||||
|
?>
|
||||||
|
<div class="wp-allstars-settings-content tab-content" id="workflow">
|
||||||
|
<div class="wp-allstars-toggle">
|
||||||
|
<div class="wp-allstars-toggle-header" aria-expanded="false">
|
||||||
|
<div class="wp-allstars-toggle-main">
|
||||||
|
<div class="wp-allstars-toggle-left">
|
||||||
|
<div class="wp-toggle-switch">
|
||||||
|
<input type="checkbox"
|
||||||
|
id="wp_allstars_auto_upload_images"
|
||||||
|
name="wp_allstars_auto_upload_images"
|
||||||
|
value="1"
|
||||||
|
<?php checked(get_option('wp_allstars_auto_upload_images', false)); ?>
|
||||||
|
/>
|
||||||
|
<span class="wp-toggle-slider"></span>
|
||||||
|
</div>
|
||||||
|
<label for="wp_allstars_auto_upload_images">
|
||||||
|
<?php esc_html_e('Enable Auto Upload Images', 'wp-allstars'); ?>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="wp-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'); ?>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="wp-allstars-toggle-settings">
|
||||||
|
<div class="wp-allstars-setting-row">
|
||||||
|
<label for="wp_allstars_max_width"><?php esc_html_e('Max Width', 'wp-allstars'); ?></label>
|
||||||
|
<input type="number"
|
||||||
|
id="wp_allstars_max_width"
|
||||||
|
name="wp_allstars_max_width"
|
||||||
|
value="<?php echo esc_attr(get_option('wp_allstars_max_width', 2560)); ?>"
|
||||||
|
/>
|
||||||
|
<p class="description"><?php esc_html_e('Maximum width for uploaded images in pixels.', 'wp-allstars'); ?></p>
|
||||||
|
</div>
|
||||||
|
<div class="wp-allstars-setting-row">
|
||||||
|
<label for="wp_allstars_max_height"><?php esc_html_e('Max Height', 'wp-allstars'); ?></label>
|
||||||
|
<input type="number"
|
||||||
|
id="wp_allstars_max_height"
|
||||||
|
name="wp_allstars_max_height"
|
||||||
|
value="<?php echo esc_attr(get_option('wp_allstars_max_height', 2560)); ?>"
|
||||||
|
/>
|
||||||
|
<p class="description"><?php esc_html_e('Maximum height for uploaded images in pixels.', 'wp-allstars'); ?></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wp-allstars-setting-row">
|
||||||
|
<label for="wp_allstars_exclude_urls"><?php esc_html_e('Exclude URLs', 'wp-allstars'); ?></label>
|
||||||
|
<textarea id="wp_allstars_exclude_urls"
|
||||||
|
name="wp_allstars_exclude_urls"
|
||||||
|
rows="3"
|
||||||
|
placeholder="example.com another-domain.com"
|
||||||
|
><?php echo esc_textarea(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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wp-allstars-setting-row">
|
||||||
|
<label for="wp_allstars_image_name"><?php esc_html_e('Image Name Pattern', 'wp-allstars'); ?></label>
|
||||||
|
<input type="text"
|
||||||
|
id="wp_allstars_image_name"
|
||||||
|
name="wp_allstars_image_name"
|
||||||
|
value="<?php echo esc_attr(get_option('wp_allstars_image_name_pattern', '%filename%')); ?>"
|
||||||
|
/>
|
||||||
|
<p class="description">
|
||||||
|
<?php esc_html_e('Available patterns:', 'wp-allstars'); ?> %filename%, %post_id%, %postname%, %timestamp%, %date%, %year%, %month%, %day%
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wp-allstars-setting-row">
|
||||||
|
<label for="wp_allstars_image_alt"><?php esc_html_e('Image Alt Pattern', 'wp-allstars'); ?></label>
|
||||||
|
<input type="text"
|
||||||
|
id="wp_allstars_image_alt"
|
||||||
|
name="wp_allstars_image_alt"
|
||||||
|
value="<?php echo esc_attr(get_option('wp_allstars_image_alt_pattern', '%filename%')); ?>"
|
||||||
|
/>
|
||||||
|
<p class="description">
|
||||||
|
<?php esc_html_e('Available patterns:', 'wp-allstars'); ?> %filename%, %post_title%, %post_id%, %postname%, %timestamp%
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save workflow settings via AJAX
|
||||||
|
*/
|
||||||
|
public static function save_settings() {
|
||||||
|
// Verify nonce for security
|
||||||
|
check_ajax_referer('wp-allstars-nonce', 'nonce');
|
||||||
|
|
||||||
|
// Check if user has proper permissions
|
||||||
|
if (!current_user_can('manage_options')) {
|
||||||
|
wp_send_json_error('Insufficient permissions');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$options = array();
|
||||||
|
|
||||||
|
// Auto upload images setting
|
||||||
|
$options['auto_upload_images'] = isset($_POST['auto_upload_images']) ?
|
||||||
|
(bool) $_POST['auto_upload_images'] :
|
||||||
|
false;
|
||||||
|
|
||||||
|
// Max dimensions
|
||||||
|
$options['max_width'] = isset($_POST['max_width']) ?
|
||||||
|
absint($_POST['max_width']) :
|
||||||
|
2560;
|
||||||
|
|
||||||
|
$options['max_height'] = isset($_POST['max_height']) ?
|
||||||
|
absint($_POST['max_height']) :
|
||||||
|
2560;
|
||||||
|
|
||||||
|
// Exclude URLs
|
||||||
|
$options['exclude_urls'] = isset($_POST['exclude_urls']) ?
|
||||||
|
sanitize_textarea_field($_POST['exclude_urls']) :
|
||||||
|
'';
|
||||||
|
|
||||||
|
// Name and alt patterns
|
||||||
|
$options['image_name_pattern'] = isset($_POST['image_name_pattern']) ?
|
||||||
|
sanitize_text_field($_POST['image_name_pattern']) :
|
||||||
|
'%filename%';
|
||||||
|
|
||||||
|
$options['image_alt_pattern'] = isset($_POST['image_alt_pattern']) ?
|
||||||
|
sanitize_text_field($_POST['image_alt_pattern']) :
|
||||||
|
'%filename%';
|
||||||
|
|
||||||
|
// Update the options
|
||||||
|
update_option('wp_allstars_workflow_options', $options);
|
||||||
|
|
||||||
|
// Also update individual options for backward compatibility
|
||||||
|
update_option('wp_allstars_auto_upload_images', $options['auto_upload_images']);
|
||||||
|
update_option('wp_allstars_max_width', $options['max_width']);
|
||||||
|
update_option('wp_allstars_max_height', $options['max_height']);
|
||||||
|
update_option('wp_allstars_exclude_urls', $options['exclude_urls']);
|
||||||
|
update_option('wp_allstars_image_name_pattern', $options['image_name_pattern']);
|
||||||
|
update_option('wp_allstars_image_alt_pattern', $options['image_alt_pattern']);
|
||||||
|
|
||||||
|
wp_send_json_success('Workflow settings saved');
|
||||||
|
}
|
||||||
|
}
|
@ -1,403 +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
|
|
||||||
$('.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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
387
admin/js/wp-allstars-admin.js
Normal file
387
admin/js/wp-allstars-admin.js
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
// 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('blur 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.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose initPluginActions to global scope for use in other scripts
|
||||||
|
window.initPluginActions = initPluginActions;
|
||||||
|
|
||||||
|
// 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 wp.updates.installTheme AJAX method
|
||||||
|
$('.theme-actions .install-now').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var $button = $(this);
|
||||||
|
var slug = $button.data('slug');
|
||||||
|
var buttonText = $button.text();
|
||||||
|
|
||||||
|
$button.addClass('updating-message').attr('aria-label', wp.updates.l10n.installing);
|
||||||
|
|
||||||
|
wp.updates.installTheme({
|
||||||
|
slug: slug,
|
||||||
|
success: function(response) {
|
||||||
|
$button.removeClass('updating-message').addClass('updated-message').attr('aria-label', wp.updates.l10n.installed);
|
||||||
|
setTimeout(function() {
|
||||||
|
// Replace the button with an activate button
|
||||||
|
var $parent = $button.parent();
|
||||||
|
$button.remove();
|
||||||
|
|
||||||
|
// Create activate URL with nonce
|
||||||
|
var activateUrl = ajaxurl + '?action=wp_allstars_activate_theme&theme=' + slug + '&_wpnonce=' + wpAllstars.nonce;
|
||||||
|
|
||||||
|
$parent.prepend('<a href="' + activateUrl + '" class="button button-primary activate-now" data-slug="' + slug + '" data-name="Kadence" data-nonce="' + wpAllstars.nonce + '">Activate</a>');
|
||||||
|
|
||||||
|
// Re-initialize the event handlers
|
||||||
|
initThemeHandlers();
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
error: function(response) {
|
||||||
|
$button.removeClass('updating-message').text(buttonText);
|
||||||
|
alert(response.errorMessage || 'Error installing theme');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Activate theme - use AJAX
|
||||||
|
$('.theme-actions .activate-now').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var $button = $(this);
|
||||||
|
var slug = $button.data('slug');
|
||||||
|
var nonce = $button.data('nonce');
|
||||||
|
var buttonText = $button.text();
|
||||||
|
|
||||||
|
$button.addClass('updating-message').attr('aria-label', 'Activating...');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: ajaxurl,
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
action: 'wp_allstars_activate_theme',
|
||||||
|
theme: slug,
|
||||||
|
_wpnonce: wpAllstars.nonce
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
$button.removeClass('updating-message').addClass('updated-message').attr('aria-label', 'Activated');
|
||||||
|
setTimeout(function() {
|
||||||
|
// Replace the button with an active button
|
||||||
|
var $parent = $button.parent();
|
||||||
|
$button.remove();
|
||||||
|
$parent.prepend('<button type="button" class="button button-disabled" disabled="disabled">Active</button>');
|
||||||
|
|
||||||
|
// Optionally reload the page to show the activated theme
|
||||||
|
// window.location.reload();
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
$button.removeClass('updating-message').text(buttonText);
|
||||||
|
alert(response.data || 'Error activating theme');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
$button.removeClass('updating-message').text(buttonText);
|
||||||
|
alert('Failed to activate theme. Please try again or activate from the Themes page. Error: ' + error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose initThemeHandlers to global scope for use in other scripts
|
||||||
|
window.initThemeHandlers = initThemeHandlers;
|
||||||
|
});
|
@ -1,9 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Theme panel template for SEO Pro Stack
|
* Theme panel template for WP Allstars
|
||||||
*
|
*
|
||||||
* @package SEO_Pro_Stack
|
* @package WP_Allstars
|
||||||
* @subpackage SEO_Pro_Stack/Admin/Partials
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Prevent direct access
|
// Prevent direct access
|
||||||
@ -25,7 +24,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-seoprostack-nonce');
|
$nonce = wp_create_nonce('wp-allstars-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">
|
||||||
@ -74,22 +73,22 @@ if (!defined('ABSPATH')) {
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<a class="button button-secondary preview install-theme-preview" href="<?php echo esc_url($theme_data->preview_url); ?>" target="_blank">
|
<a class="button button-secondary green-button-secondary preview install-theme-preview" href="<?php echo esc_url($theme_data->preview_url); ?>" target="_blank">
|
||||||
<?php esc_html_e('Preview'); ?>
|
<?php esc_html_e('Preview'); ?>
|
||||||
</a>
|
</a>
|
||||||
<a class="button button-secondary" href="https://www.kadencewp.com/kadence-theme/starter-templates/" target="_blank">
|
<a class="button button-secondary green-button-secondary" href="https://www.kadencewp.com/kadence-theme/starter-templates/" target="_blank">
|
||||||
<?php esc_html_e('Templates'); ?>
|
<?php esc_html_e('Templates'); ?>
|
||||||
</a>
|
</a>
|
||||||
<a class="button button-secondary" href="https://www.kadencewp.com/wordpress-solutions/kadence-ai/" target="_blank">
|
<a class="button button-secondary green-button-secondary" href="https://www.kadencewp.com/wordpress-solutions/kadence-ai/" target="_blank">
|
||||||
<?php esc_html_e('Starter AI'); ?>
|
<?php esc_html_e('Starter AI'); ?>
|
||||||
</a>
|
</a>
|
||||||
<a class="button button-secondary" href="https://www.kadencewp.com/kadence-theme/marketplace/" target="_blank">
|
<a class="button button-secondary green-button-secondary" href="https://www.kadencewp.com/kadence-theme/marketplace/" target="_blank">
|
||||||
<?php esc_html_e('Marketplace'); ?>
|
<?php esc_html_e('Marketplace'); ?>
|
||||||
</a>
|
</a>
|
||||||
<a class="button button-secondary" href="https://www.kadencewp.com/pricing/" target="_blank">
|
<a class="button button-secondary green-button-secondary" href="https://www.kadencewp.com/pricing/" target="_blank">
|
||||||
<?php esc_html_e('Pricing'); ?>
|
<?php esc_html_e('Pricing'); ?>
|
||||||
</a>
|
</a>
|
||||||
<a class="button button-primary" href="https://www.kadencewp.com/kadence-theme/" target="_blank">
|
<a class="button button-primary go-pro-button" href="https://www.kadencewp.com/kadence-theme/" target="_blank">
|
||||||
<?php esc_html_e('Go Pro'); ?>
|
<?php esc_html_e('Go Pro'); ?>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
2162
admin/settings.php
2162
admin/settings.php
File diff suppressed because it is too large
Load Diff
@ -1,132 +0,0 @@
|
|||||||
<?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
|
|
||||||
)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
<?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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,194 +0,0 @@
|
|||||||
<?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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,119 +0,0 @@
|
|||||||
<?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
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,93 +0,0 @@
|
|||||||
<?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')),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
<?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
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,193 +0,0 @@
|
|||||||
<?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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,159 +0,0 @@
|
|||||||
<?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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
<?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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,692 +0,0 @@
|
|||||||
<?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 '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,176 +0,0 @@
|
|||||||
<?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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,617 +0,0 @@
|
|||||||
<?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
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
<?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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,299 +0,0 @@
|
|||||||
<?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
|
|
||||||
)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,132 +0,0 @@
|
|||||||
<?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
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,24 +2,20 @@
|
|||||||
/**
|
/**
|
||||||
* Auto Upload Images functionality
|
* Auto Upload Images functionality
|
||||||
*
|
*
|
||||||
* @package SEO_Pro_Stack
|
* @package WP_ALLSTARS
|
||||||
* @deprecated 1.0.0 Use the class in includes/features/auto-upload/class-seoprostack-auto-upload.php instead
|
* @since 0.2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// If this file is called directly, abort.
|
|
||||||
if (!defined('ABSPATH')) {
|
if (!defined('ABSPATH')) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
class WP_Allstars_Auto_Upload {
|
||||||
* @deprecated 1.0.0 Use SEOProStack_Auto_Upload instead
|
|
||||||
*/
|
|
||||||
class SEOProStack_Auto_Upload_Legacy {
|
|
||||||
/**
|
/**
|
||||||
* Initialize the class
|
* Initialize the class
|
||||||
*/
|
*/
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
add_filter('content_save_pre', array($this, 'process_content'), 10, 1);
|
add_filter('content_save_pre', array($this, 'process_content'));
|
||||||
add_action('wp_allstars_image_upload_error', array($this, 'log_error'), 10, 2);
|
add_action('wp_allstars_image_upload_error', array($this, 'log_error'), 10, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +62,8 @@ class SEOProStack_Auto_Upload_Legacy {
|
|||||||
return str_replace($url, $local_url, $matches[0]);
|
return str_replace($url, $local_url, $matches[0]);
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
do_action('wp_allstars_image_upload_error', $url, $e->getMessage());
|
// Trigger error action for logging
|
||||||
|
do_action('wp_allstars_image_upload_error', esc_url($url), $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $matches[0];
|
return $matches[0];
|
||||||
@ -89,11 +86,12 @@ class SEOProStack_Auto_Upload_Legacy {
|
|||||||
*
|
*
|
||||||
* @param string $url External image URL
|
* @param string $url External image URL
|
||||||
* @return string|false Local URL on success, false on failure
|
* @return string|false Local URL on success, false on failure
|
||||||
|
* @throws Exception If download or upload fails
|
||||||
*/
|
*/
|
||||||
private function upload_image($url) {
|
private function upload_image($url) {
|
||||||
// Get file info
|
$file_array = array(
|
||||||
$file_array = array();
|
'name' => sanitize_file_name(basename($url))
|
||||||
$file_array['name'] = basename($url);
|
);
|
||||||
|
|
||||||
// Download file to temp location
|
// Download file to temp location
|
||||||
$file_array['tmp_name'] = download_url($url);
|
$file_array['tmp_name'] = download_url($url);
|
||||||
@ -102,17 +100,18 @@ class SEOProStack_Auto_Upload_Legacy {
|
|||||||
throw new Exception('Failed to download image: ' . $file_array['tmp_name']->get_error_message());
|
throw new Exception('Failed to download image: ' . $file_array['tmp_name']->get_error_message());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check file type
|
// Check file type for security
|
||||||
$wp_filetype = wp_check_filetype_and_ext($file_array['tmp_name'], $file_array['name']);
|
$wp_filetype = wp_check_filetype_and_ext($file_array['tmp_name'], $file_array['name']);
|
||||||
if (!$wp_filetype['type']) {
|
if (!$wp_filetype['type']) {
|
||||||
unlink($file_array['tmp_name']);
|
unlink($file_array['tmp_name']);
|
||||||
throw new Exception('Invalid file type');
|
throw new Exception('Invalid file type');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload the file
|
// Upload the file to media library
|
||||||
$attachment_id = media_handle_sideload($file_array, 0);
|
$attachment_id = media_handle_sideload($file_array, 0);
|
||||||
|
|
||||||
if (is_wp_error($attachment_id)) {
|
if (is_wp_error($attachment_id)) {
|
||||||
|
unlink($file_array['tmp_name']);
|
||||||
throw new Exception('Failed to upload image: ' . $attachment_id->get_error_message());
|
throw new Exception('Failed to upload image: ' . $attachment_id->get_error_message());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,10 +125,12 @@ class SEOProStack_Auto_Upload_Legacy {
|
|||||||
* @param string $error Error message
|
* @param string $error Error message
|
||||||
*/
|
*/
|
||||||
public function log_error($url, $error) {
|
public function log_error($url, $error) {
|
||||||
error_log(sprintf(
|
if (WP_DEBUG) {
|
||||||
'[SEO Pro Stack] Auto Upload Images Error - URL: %s, Error: %s',
|
error_log(sprintf(
|
||||||
$url,
|
'[WP ALLSTARS] Auto Upload Images Error - URL: %s, Error: %s',
|
||||||
$error
|
esc_url_raw($url),
|
||||||
));
|
sanitize_text_field($error)
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
60
includes/class-wp-allstars-sync-guard.php
Normal file
60
includes/class-wp-allstars-sync-guard.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* WP ALLSTARS Sync Guard
|
||||||
|
*
|
||||||
|
* Prevents plugin loading during sync operations to avoid fatal errors.
|
||||||
|
*
|
||||||
|
* @package WP_ALLSTARS
|
||||||
|
* @since 0.2.3.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class responsible for detecting sync operations and preventing plugin loading
|
||||||
|
*/
|
||||||
|
class WP_Allstars_Sync_Guard {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag file name for sync operations
|
||||||
|
*/
|
||||||
|
const SYNC_FLAG_FILE = '.syncing';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if sync is in progress
|
||||||
|
*
|
||||||
|
* @return bool Whether sync is in progress
|
||||||
|
*/
|
||||||
|
public static function is_sync_in_progress() {
|
||||||
|
$flag_file = plugin_dir_path(dirname(__FILE__)) . self::SYNC_FLAG_FILE;
|
||||||
|
return file_exists($flag_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle sync mode by showing admin notice and preventing plugin loading
|
||||||
|
*
|
||||||
|
* @return bool True if sync is in progress, false otherwise
|
||||||
|
*/
|
||||||
|
public static function handle_sync_mode() {
|
||||||
|
if (self::is_sync_in_progress()) {
|
||||||
|
// Add admin notice
|
||||||
|
add_action('admin_notices', array(__CLASS__, 'display_sync_notice'));
|
||||||
|
|
||||||
|
// Return true to indicate plugin should not continue loading
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display sync in progress notice
|
||||||
|
*/
|
||||||
|
public static function display_sync_notice() {
|
||||||
|
echo '<div class="notice notice-warning is-dismissible">';
|
||||||
|
echo '<p><strong>WP Allstars:</strong> Plugin files are currently syncing. The plugin functionality is temporarily disabled to prevent errors. Please try again in a moment.</p>';
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
}
|
@ -1,69 +0,0 @@
|
|||||||
<?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();
|
|
@ -1,102 +0,0 @@
|
|||||||
<?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']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
<?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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,136 +0,0 @@
|
|||||||
<?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
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
126
wp-allstars-plugin.php
Normal file
126
wp-allstars-plugin.php
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* WP ALLSTARS Plugin
|
||||||
|
*
|
||||||
|
* A comprehensive WordPress optimization and management tool designed to enhance
|
||||||
|
* site performance, improve workflow, and provide recommendations for plugins and hosting.
|
||||||
|
*
|
||||||
|
* @package WP_ALLSTARS
|
||||||
|
* @version v0.2.3.1
|
||||||
|
*
|
||||||
|
* Plugin Name: WP Allstars
|
||||||
|
* Plugin URI: https://wpallstars.com
|
||||||
|
* Description: A superstar stack of premium WordPress functionality, designed for SEO pros.
|
||||||
|
* Author: Marcus Quinn
|
||||||
|
* Author URI: https://wpallstars.com
|
||||||
|
* Text Domain: wp-allstars
|
||||||
|
* Domain Path: /languages
|
||||||
|
* @version v0.2.3.1
|
||||||
|
*
|
||||||
|
* WP Allstars is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* any later version.
|
||||||
|
* Version: v0.2.3.1 (Beta)
|
||||||
|
*
|
||||||
|
* WP Allstars is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with WP Allstars. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('WPINC')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
define('WP_ALLSTARS_VERSION', 'v0.2.3.1');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load files safely by checking if they exist first
|
||||||
|
*/
|
||||||
|
function wp_allstars_require_if_exists($file) {
|
||||||
|
if (file_exists($file)) {
|
||||||
|
require_once $file;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for sync operations before loading the plugin
|
||||||
|
*/
|
||||||
|
// Simple sync detection - check for .syncing file
|
||||||
|
if (file_exists(__DIR__ . '/.syncing')) {
|
||||||
|
// Only load the minimal code needed for admin notice
|
||||||
|
if (is_admin()) {
|
||||||
|
add_action('admin_notices', function() {
|
||||||
|
echo '<div class="notice notice-warning is-dismissible">';
|
||||||
|
echo '<p><strong>WP Allstars:</strong> Plugin files are currently syncing. The plugin functionality is temporarily disabled to prevent errors. Please try again in a moment.</p>';
|
||||||
|
echo '</div>';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Exit early to prevent loading other files
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the sync guard for future use and more advanced sync detection
|
||||||
|
wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . 'includes/class-wp-allstars-sync-guard.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plugin activation hook
|
||||||
|
*/
|
||||||
|
function wp_allstars_activate() {
|
||||||
|
// Setup initial config
|
||||||
|
}
|
||||||
|
register_activation_hook(__FILE__, 'wp_allstars_activate');
|
||||||
|
|
||||||
|
// Core includes
|
||||||
|
wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . 'includes/class-wp-allstars-auto-upload.php');
|
||||||
|
|
||||||
|
// Admin includes
|
||||||
|
if (is_admin()) {
|
||||||
|
$admin_includes = array(
|
||||||
|
'admin/includes/class-admin-manager.php',
|
||||||
|
'admin/includes/class-settings-manager.php',
|
||||||
|
'admin/includes/class-theme-manager.php',
|
||||||
|
'admin/includes/class-workflow-manager.php',
|
||||||
|
'admin/includes/class-tools-manager.php',
|
||||||
|
'admin/includes/class-hosting-manager.php',
|
||||||
|
'admin/includes/class-pro-plugins-manager.php',
|
||||||
|
'admin/includes/class-plugin-manager.php',
|
||||||
|
'admin/includes/class-free-plugins-manager.php',
|
||||||
|
'admin/includes/class-readme-manager.php'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($admin_includes as $file) {
|
||||||
|
wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Settings and data
|
||||||
|
wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . 'admin/data/pro-plugins.php');
|
||||||
|
wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . 'admin/data/readme.php');
|
||||||
|
|
||||||
|
// Admin settings
|
||||||
|
wp_allstars_require_if_exists(plugin_dir_path(__FILE__) . 'admin/settings.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto Upload feature initialization
|
||||||
|
*
|
||||||
|
* Initialize the Auto Upload feature when a user is logged in
|
||||||
|
*/
|
||||||
|
function wp_allstars_init_auto_upload() {
|
||||||
|
// Only initialize for logged-in users
|
||||||
|
if (is_user_logged_in()) {
|
||||||
|
new WP_Allstars_Auto_Upload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action('init', 'wp_allstars_init_auto_upload');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize core plugin classes
|
||||||
|
*/
|
||||||
|
$wp_allstars_auto_upload = new WP_Allstars_Auto_Upload();
|
@ -1,93 +0,0 @@
|
|||||||
<?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();
|
|
Reference in New Issue
Block a user