Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
362
native/wordpress/maplepress-plugin/includes/admin-dashboard.php
Normal file
362
native/wordpress/maplepress-plugin/includes/admin-dashboard.php
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin dashboard page template.
|
||||
*
|
||||
* @package MaplePress
|
||||
* @subpackage MaplePress/includes
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$options = get_option( 'maplepress_settings' );
|
||||
$has_api_key = ! empty( $options['api_key'] );
|
||||
$is_verified = isset( $options['is_verified'] ) && $options['is_verified'];
|
||||
|
||||
// Refresh quota data if verified and API credentials are available
|
||||
if ( $is_verified && ! empty( $options['api_url'] ) && ! empty( $options['api_key'] ) ) {
|
||||
require_once MAPLEPRESS_PLUGIN_DIR . 'includes/class-maplepress-api-client.php';
|
||||
$api_client = new MaplePress_API_Client( $options['api_url'], $options['api_key'] );
|
||||
$fresh_status = $api_client->verify_connection();
|
||||
|
||||
// Update options with fresh quota data if API call succeeded
|
||||
if ( ! is_wp_error( $fresh_status ) ) {
|
||||
if ( isset( $fresh_status['search_requests_count'] ) ) {
|
||||
$options['search_requests_count'] = absint( $fresh_status['search_requests_count'] );
|
||||
}
|
||||
if ( isset( $fresh_status['storage_used_bytes'] ) ) {
|
||||
$options['storage_used_bytes'] = absint( $fresh_status['storage_used_bytes'] );
|
||||
}
|
||||
if ( isset( $fresh_status['monthly_pages_indexed'] ) ) {
|
||||
$options['monthly_pages_indexed'] = absint( $fresh_status['monthly_pages_indexed'] );
|
||||
}
|
||||
if ( isset( $fresh_status['total_pages_indexed'] ) ) {
|
||||
$options['total_pages_indexed'] = absint( $fresh_status['total_pages_indexed'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e( 'MaplePress Dashboard', 'maplepress' ); ?></h1>
|
||||
|
||||
<?php
|
||||
// Display sync status messages
|
||||
if ( isset( $_GET['sync_status'] ) ) {
|
||||
if ( $_GET['sync_status'] === 'success' && isset( $_GET['synced_count'] ) ) {
|
||||
?>
|
||||
<div class="notice notice-success is-dismissible">
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %d: number of pages synced */
|
||||
esc_html__( '✓ Successfully synced %d pages to MaplePress!', 'maplepress' ),
|
||||
absint( $_GET['synced_count'] )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
} elseif ( $_GET['sync_status'] === 'error' && isset( $_GET['sync_message'] ) ) {
|
||||
?>
|
||||
<div class="notice notice-error is-dismissible">
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: error message */
|
||||
esc_html__( '✗ Sync failed: %s', 'maplepress' ),
|
||||
esc_html( urldecode( $_GET['sync_message'] ) )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
} elseif ( $_GET['sync_status'] === 'no_posts' ) {
|
||||
?>
|
||||
<div class="notice notice-warning is-dismissible">
|
||||
<p><?php esc_html_e( 'No published posts or pages found to sync.', 'maplepress' ); ?></p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php if ( ! $has_api_key ) : ?>
|
||||
<!-- No API key - prompt setup -->
|
||||
<div class="notice notice-warning" style="padding: 20px; margin: 20px 0;">
|
||||
<h2 style="margin-top: 0;"><?php esc_html_e( 'Welcome to MaplePress!', 'maplepress' ); ?></h2>
|
||||
<p><?php esc_html_e( 'You need to connect your site to MaplePress to use the cloud services.', 'maplepress' ); ?></p>
|
||||
<p>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=maplepress-settings' ) ); ?>" class="button button-primary button-large">
|
||||
<?php esc_html_e( 'Connect to MaplePress', 'maplepress' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<?php elseif ( ! $is_verified ) : ?>
|
||||
<!-- API key connected but NOT verified - show verification required notice -->
|
||||
<div class="notice notice-error" style="padding: 20px; margin: 20px 0; border-left: 4px solid #dc3232;">
|
||||
<h2 style="margin-top: 0; color: #dc3232;">
|
||||
⚠️ <?php esc_html_e( 'Domain Verification Required', 'maplepress' ); ?>
|
||||
</h2>
|
||||
<p>
|
||||
<?php esc_html_e( 'Your API key is connected, but your domain needs to be verified before you can use MaplePress features.', 'maplepress' ); ?>
|
||||
</p>
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'What you need to do:', 'maplepress' ); ?></strong>
|
||||
</p>
|
||||
<ol style="margin-left: 20px;">
|
||||
<li><?php esc_html_e( 'Go to Settings → MaplePress', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'Follow the DNS verification instructions', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'Add the DNS TXT record to your domain', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'Click "Verify Domain Now"', 'maplepress' ); ?></li>
|
||||
</ol>
|
||||
<p>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=maplepress-settings' ) ); ?>" class="button button-primary button-large">
|
||||
<?php esc_html_e( 'Complete Verification', 'maplepress' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<hr style="margin: 20px 0;">
|
||||
|
||||
<p style="margin: 0;">
|
||||
<strong><?php esc_html_e( 'Features disabled until verification:', 'maplepress' ); ?></strong><br>
|
||||
<span style="color: #666;">
|
||||
<?php esc_html_e( 'Page syncing, search indexing, and all MaplePress cloud services are currently unavailable.', 'maplepress' ); ?>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php return; // Stop rendering dashboard content if not verified ?>
|
||||
|
||||
<?php else : ?>
|
||||
<!-- Connected - show dashboard -->
|
||||
|
||||
<!-- Connection Status -->
|
||||
<div class="notice notice-success" style="padding: 15px; margin: 20px 0; border-left-width: 4px;">
|
||||
<h2 style="margin: 0; color: #46b450;">
|
||||
✓ <?php esc_html_e( 'Connected to MaplePress', 'maplepress' ); ?>
|
||||
</h2>
|
||||
<p style="margin: 10px 0 0 0;">
|
||||
<strong><?php esc_html_e( 'Domain:', 'maplepress' ); ?></strong> <?php echo esc_html( $options['domain'] ?? 'N/A' ); ?>
|
||||
|
|
||||
<strong><?php esc_html_e( 'Billing:', 'maplepress' ); ?></strong> <?php esc_html_e( 'Usage-Based', 'maplepress' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Usage-Based Billing Notice -->
|
||||
<div class="notice notice-info" style="padding: 15px; margin: 20px 0;">
|
||||
<h3 style="margin: 0 0 10px 0;">ℹ️ <?php esc_html_e( 'Usage-Based Billing', 'maplepress' ); ?></h3>
|
||||
<p><?php esc_html_e( 'MaplePress now uses usage-based billing with no limits or quotas. You pay only for what you use:', 'maplepress' ); ?></p>
|
||||
<ul style="margin: 10px 0 10px 20px;">
|
||||
<li><?php esc_html_e( '✓ No search request limits', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( '✓ No page indexing limits', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( '✓ No storage limits', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( '✓ Generous rate limits for anti-abuse (10,000 requests/hour)', 'maplepress' ); ?></li>
|
||||
</ul>
|
||||
<p>
|
||||
<a href="https://getmaplepress.com/pricing" target="_blank" class="button">
|
||||
<?php esc_html_e( 'View Pricing Details', 'maplepress' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Quick Stats -->
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin: 30px 0;">
|
||||
<!-- Monthly Searches -->
|
||||
<div class="postbox" style="padding: 20px;">
|
||||
<h3 style="margin: 0 0 10px 0;"><?php esc_html_e( 'Monthly Searches', 'maplepress' ); ?></h3>
|
||||
<p style="font-size: 32px; font-weight: bold; margin: 0; color: #2271b1;">
|
||||
<?php echo esc_html( number_format( $options['search_requests_count'] ?? 0 ) ); ?>
|
||||
</p>
|
||||
<p style="margin: 5px 0 0 0; color: #666;">
|
||||
<?php esc_html_e( 'this billing cycle', 'maplepress' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Monthly Pages Indexed -->
|
||||
<div class="postbox" style="padding: 20px;">
|
||||
<h3 style="margin: 0 0 10px 0;"><?php esc_html_e( 'Monthly Indexing', 'maplepress' ); ?></h3>
|
||||
<p style="font-size: 32px; font-weight: bold; margin: 0; color: #2271b1;">
|
||||
<?php echo esc_html( number_format( $options['monthly_pages_indexed'] ?? 0 ) ); ?>
|
||||
</p>
|
||||
<p style="margin: 5px 0 0 0; color: #666;">
|
||||
<?php esc_html_e( 'pages this cycle', 'maplepress' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Total Pages Indexed -->
|
||||
<div class="postbox" style="padding: 20px;">
|
||||
<h3 style="margin: 0 0 10px 0;"><?php esc_html_e( 'Total Pages', 'maplepress' ); ?></h3>
|
||||
<p style="font-size: 32px; font-weight: bold; margin: 0; color: #2271b1;">
|
||||
<?php echo esc_html( number_format( $options['total_pages_indexed'] ?? 0 ) ); ?>
|
||||
</p>
|
||||
<p style="margin: 5px 0 0 0; color: #666;">
|
||||
<?php esc_html_e( 'all-time indexed', 'maplepress' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Storage Used -->
|
||||
<div class="postbox" style="padding: 20px;">
|
||||
<h3 style="margin: 0 0 10px 0;"><?php esc_html_e( 'Storage Used', 'maplepress' ); ?></h3>
|
||||
<p style="font-size: 32px; font-weight: bold; margin: 0; color: #2271b1;">
|
||||
<?php
|
||||
$storage_mb = round( ( $options['storage_used_bytes'] ?? 0 ) / 1024 / 1024, 1 );
|
||||
echo esc_html( $storage_mb );
|
||||
?>
|
||||
<span style="font-size: 16px;">MB</span>
|
||||
</p>
|
||||
<p style="margin: 5px 0 0 0; color: #666;">
|
||||
<?php esc_html_e( 'cumulative usage', 'maplepress' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Detailed Usage -->
|
||||
<h2><?php esc_html_e( 'Usage Details', 'maplepress' ); ?></h2>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 40%;"><?php esc_html_e( 'Resource', 'maplepress' ); ?></th>
|
||||
<th style="width: 30%;"><?php esc_html_e( 'Usage', 'maplepress' ); ?></th>
|
||||
<th style="width: 30%;"><?php esc_html_e( 'Period', 'maplepress' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong><?php esc_html_e( 'Monthly Searches', 'maplepress' ); ?></strong></td>
|
||||
<td><?php echo esc_html( number_format( $options['search_requests_count'] ?? 0 ) ); ?> requests</td>
|
||||
<td><?php esc_html_e( 'Current billing cycle', 'maplepress' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong><?php esc_html_e( 'Monthly Indexing', 'maplepress' ); ?></strong></td>
|
||||
<td><?php echo esc_html( number_format( $options['monthly_pages_indexed'] ?? 0 ) ); ?> pages</td>
|
||||
<td><?php esc_html_e( 'Current billing cycle', 'maplepress' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong><?php esc_html_e( 'Total Pages Indexed', 'maplepress' ); ?></strong></td>
|
||||
<td><?php echo esc_html( number_format( $options['total_pages_indexed'] ?? 0 ) ); ?> pages</td>
|
||||
<td><?php esc_html_e( 'All-time cumulative', 'maplepress' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong><?php esc_html_e( 'Storage Used', 'maplepress' ); ?></strong></td>
|
||||
<td>
|
||||
<?php
|
||||
$used_mb = round( ( $options['storage_used_bytes'] ?? 0 ) / 1024 / 1024, 2 );
|
||||
echo esc_html( $used_mb ) . ' MB';
|
||||
?>
|
||||
</td>
|
||||
<td><?php esc_html_e( 'All-time cumulative', 'maplepress' ); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<h2 style="margin-top: 40px;"><?php esc_html_e( 'Quick Actions', 'maplepress' ); ?></h2>
|
||||
|
||||
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=maplepress-initial-sync' ) ); ?>" class="button button-primary button-large">
|
||||
<?php esc_html_e( 'Sync All Pages Now', 'maplepress' ); ?>
|
||||
</a>
|
||||
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=maplepress-settings' ) ); ?>" class="button button-large">
|
||||
<?php esc_html_e( 'Settings', 'maplepress' ); ?>
|
||||
</a>
|
||||
|
||||
<a href="https://getmaplepress.com/dashboard" target="_blank" class="button button-large">
|
||||
<?php esc_html_e( '→ Open Cloud Dashboard', 'maplepress' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Advanced Tools -->
|
||||
<h2 style="margin-top: 40px;"><?php esc_html_e( 'Advanced', 'maplepress' ); ?></h2>
|
||||
<div class="postbox" style="padding: 20px; margin-bottom: 20px;">
|
||||
<h3 style="margin-top: 0;"><?php esc_html_e( 'Diagnostic Tools', 'maplepress' ); ?></h3>
|
||||
<p>
|
||||
<?php esc_html_e( 'Access advanced diagnostic and testing tools for your MaplePress integration.', 'maplepress' ); ?>
|
||||
</p>
|
||||
<div style="display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 30px;">
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=maplepress-speedtest' ) ); ?>" class="button button-large">
|
||||
<span class="dashicons dashicons-performance" style="vertical-align: middle;"></span>
|
||||
<?php esc_html_e( 'Search Speed Test', 'maplepress' ); ?>
|
||||
</a>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=maplepress-system-info' ) ); ?>" class="button button-large">
|
||||
<span class="dashicons dashicons-info" style="vertical-align: middle;"></span>
|
||||
<?php esc_html_e( 'System Info', 'maplepress' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<hr style="margin: 20px 0;">
|
||||
|
||||
<h3 style="margin-top: 20px; color: #d63638;"><?php esc_html_e( 'Danger Zone', 'maplepress' ); ?></h3>
|
||||
<p>
|
||||
<?php esc_html_e( 'Permanently remove MaplePress plugin and all local data.', 'maplepress' ); ?>
|
||||
</p>
|
||||
<form method="post" action="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>" style="margin-top: 15px;">
|
||||
<input type="hidden" name="action" value="maplepress_reset_and_delete">
|
||||
<?php wp_nonce_field( 'maplepress_reset_and_delete' ); ?>
|
||||
<button type="submit"
|
||||
class="button button-large"
|
||||
style="color: #ffffff; background-color: #d63638; border-color: #d63638;"
|
||||
onmouseover="this.style.backgroundColor='#b32d2e';"
|
||||
onmouseout="this.style.backgroundColor='#d63638';"
|
||||
onclick="return confirm('<?php echo esc_js( __( '⚠️ WARNING: This action is PERMANENT and cannot be undone!\n\nThis will:\n✗ Delete all MaplePress settings from WordPress\n✗ Remove API keys and configuration\n✗ Clear verification status\n✗ Deactivate and DELETE the plugin\n\n⚠️ Your data in the MaplePress cloud will remain safe and can be accessed again if you reinstall.\n\nAre you absolutely sure you want to continue?', 'maplepress' ) ); ?>">
|
||||
<span class="dashicons dashicons-trash" style="vertical-align: middle;"></span>
|
||||
<?php esc_html_e( 'Reset & Delete Plugin', 'maplepress' ); ?>
|
||||
</button>
|
||||
</form>
|
||||
<p class="description" style="color: #d63638; margin-top: 10px;">
|
||||
<strong><?php esc_html_e( 'Warning:', 'maplepress' ); ?></strong>
|
||||
<?php esc_html_e( 'This will permanently delete the plugin and all local settings. Your cloud data remains safe.', 'maplepress' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Site Information -->
|
||||
<h2><?php esc_html_e( 'Site Information', 'maplepress' ); ?></h2>
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Domain', 'maplepress' ); ?></th>
|
||||
<td><?php echo esc_html( $options['domain'] ?? 'N/A' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Billing Model', 'maplepress' ); ?></th>
|
||||
<td><strong><?php esc_html_e( 'Usage-Based', 'maplepress' ); ?></strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Status', 'maplepress' ); ?></th>
|
||||
<td>
|
||||
<?php if ( $options['enabled'] ) : ?>
|
||||
<span style="color: #46b450; font-weight: bold;">● <?php esc_html_e( 'Active', 'maplepress' ); ?></span>
|
||||
<?php else : ?>
|
||||
<span style="color: #dc3232; font-weight: bold;">● <?php esc_html_e( 'Inactive', 'maplepress' ); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Footer -->
|
||||
<div style="margin-top: 40px; padding-top: 20px; border-top: 1px solid #dcdcde; text-align: center; color: #646970; font-size: 13px;">
|
||||
<p style="margin: 0;">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: link to source code */
|
||||
esc_html__( 'MaplePress is open-source software. %s', 'maplepress' ),
|
||||
'<a href="https://codeberg.org/mapleopentech/monorepo/src/branch/main/native/wordpress/maplepress-plugin" target="_blank" rel="noopener noreferrer" style="color: #2271b1; text-decoration: none;">' .
|
||||
esc_html__( 'View source code', 'maplepress' ) .
|
||||
' <span class="dashicons dashicons-external" style="font-size: 12px; vertical-align: text-top;"></span></a>'
|
||||
);
|
||||
?>
|
||||
|
|
||||
<a href="https://getmaplepress.com" target="_blank" rel="noopener noreferrer" style="color: #2271b1; text-decoration: none;">
|
||||
<?php esc_html_e( 'Documentation', 'maplepress' ); ?>
|
||||
</a>
|
||||
|
|
||||
<a href="https://codeberg.org/mapleopentech/monorepo/issues" target="_blank" rel="noopener noreferrer" style="color: #2271b1; text-decoration: none;">
|
||||
<?php esc_html_e( 'Report an issue', 'maplepress' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin sync page template.
|
||||
* This page is shown when syncing all pages to MaplePress (initial or manual sync).
|
||||
*
|
||||
* @package MaplePress
|
||||
* @subpackage MaplePress/includes
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$options = get_option( 'maplepress_settings', array() );
|
||||
?>
|
||||
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e( 'Syncing Pages', 'maplepress' ); ?></h1>
|
||||
|
||||
<div style="max-width: 800px; margin: 40px auto; text-align: center;">
|
||||
<div style="background: #fff; border: 1px solid #dcdcde; padding: 40px; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
|
||||
<!-- Loading animation -->
|
||||
<div style="margin-bottom: 30px;">
|
||||
<span class="spinner is-active" style="float: none; width: 40px; height: 40px; margin: 0 auto; background-size: 40px 40px;"></span>
|
||||
</div>
|
||||
|
||||
<!-- Status heading -->
|
||||
<h2 id="maplepress-sync-status" style="margin: 20px 0; color: #2271b1; font-size: 24px;">
|
||||
<?php esc_html_e( 'Preparing to sync your content...', 'maplepress' ); ?>
|
||||
</h2>
|
||||
|
||||
<!-- Details text -->
|
||||
<p id="maplepress-sync-details" style="color: #666; font-size: 16px; margin: 15px 0;">
|
||||
<?php esc_html_e( 'This will only take a moment.', 'maplepress' ); ?>
|
||||
</p>
|
||||
|
||||
<!-- Progress bar -->
|
||||
<div id="maplepress-sync-progressbar" style="margin: 30px 0;">
|
||||
<div style="background: #f0f0f1; border-radius: 4px; height: 30px; position: relative; overflow: hidden;">
|
||||
<div id="maplepress-sync-progressbar-fill" style="background: linear-gradient(90deg, #2271b1 0%, #135e96 100%); height: 100%; width: 0%; transition: width 0.5s ease;">
|
||||
<span id="maplepress-sync-progressbar-text" style="color: #fff; font-size: 14px; font-weight: 600; line-height: 30px; display: block; text-align: center;"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Batch information -->
|
||||
<div id="maplepress-sync-batch-info" style="background: #f9f9f9; border: 1px solid #e0e0e0; border-radius: 4px; padding: 20px; margin: 20px 0; display: none;">
|
||||
<div style="display: flex; justify-content: space-around; text-align: center;">
|
||||
<div>
|
||||
<div style="font-size: 28px; font-weight: 600; color: #2271b1;" id="maplepress-sync-pages-synced">0</div>
|
||||
<div style="color: #666; font-size: 14px;"><?php esc_html_e( 'Pages Synced', 'maplepress' ); ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size: 28px; font-weight: 600; color: #2271b1;" id="maplepress-sync-current-batch">0</div>
|
||||
<div style="color: #666; font-size: 14px;"><?php esc_html_e( 'Current Batch', 'maplepress' ); ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size: 28px; font-weight: 600; color: #2271b1;" id="maplepress-sync-total-batches">0</div>
|
||||
<div style="color: #666; font-size: 14px;"><?php esc_html_e( 'Total Batches', 'maplepress' ); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Important note -->
|
||||
<div style="background: #fff3cd; border: 1px solid #ffc107; border-radius: 4px; padding: 15px; margin-top: 30px; text-align: left;">
|
||||
<p style="margin: 0; color: #856404;">
|
||||
<strong><?php esc_html_e( 'Please do not close this page.', 'maplepress' ); ?></strong><br>
|
||||
<?php esc_html_e( 'We are syncing all your published content to MaplePress.', 'maplepress' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
var statusText = $('#maplepress-sync-status');
|
||||
var detailsText = $('#maplepress-sync-details');
|
||||
var progressBar = $('#maplepress-sync-progressbar-fill');
|
||||
var progressText = $('#maplepress-sync-progressbar-text');
|
||||
var batchInfo = $('#maplepress-sync-batch-info');
|
||||
var pagesSynced = $('#maplepress-sync-pages-synced');
|
||||
var currentBatch = $('#maplepress-sync-current-batch');
|
||||
var totalBatches = $('#maplepress-sync-total-batches');
|
||||
|
||||
// Start the sync
|
||||
function startSync() {
|
||||
statusText.text('<?php esc_html_e( 'Counting pages to sync...', 'maplepress' ); ?>');
|
||||
detailsText.text('<?php esc_html_e( 'Analyzing your content...', 'maplepress' ); ?>');
|
||||
progressBar.css('width', '5%');
|
||||
progressText.text('5%');
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'maplepress_initial_sync',
|
||||
nonce: '<?php echo wp_create_nonce( 'maplepress_initial_sync' ); ?>'
|
||||
},
|
||||
timeout: 600000, // 10 minute timeout
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
// Show completion
|
||||
progressBar.css('width', '100%');
|
||||
progressText.text('100%');
|
||||
statusText.html('<span style="color: #008a00;">✓ ' + response.data.message + '</span>');
|
||||
detailsText.html(response.data.details || '');
|
||||
|
||||
// Redirect to dashboard after 2 seconds
|
||||
setTimeout(function() {
|
||||
window.location.href = '<?php echo admin_url( 'admin.php?page=maplepress&sync_status=success&synced_count=' ); ?>' + (response.data.synced_count || 0);
|
||||
}, 2000);
|
||||
} else {
|
||||
// Show error
|
||||
statusText.html('<span style="color: #d63638;">✗ Sync failed</span>');
|
||||
detailsText.html('<strong><?php esc_html_e( 'Error:', 'maplepress' ); ?></strong> ' + (response.data || '<?php esc_html_e( 'Unknown error', 'maplepress' ); ?>'));
|
||||
|
||||
// Show retry button
|
||||
$('<div style="margin-top: 20px;"><a href="<?php echo admin_url( 'admin.php?page=maplepress-settings' ); ?>" class="button button-primary"><?php esc_html_e( 'Return to Settings', 'maplepress' ); ?></a></div>').insertAfter('#maplepress-sync-progressbar');
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
statusText.html('<span style="color: #d63638;">✗ Network error</span>');
|
||||
detailsText.html('<strong><?php esc_html_e( 'Error:', 'maplepress' ); ?></strong> ' + error);
|
||||
|
||||
// Show retry button
|
||||
$('<div style="margin-top: 20px;"><a href="<?php echo admin_url( 'admin.php?page=maplepress-settings' ); ?>" class="button button-primary"><?php esc_html_e( 'Return to Settings', 'maplepress' ); ?></a></div>').insertAfter('#maplepress-sync-progressbar');
|
||||
},
|
||||
xhr: function() {
|
||||
var xhr = new window.XMLHttpRequest();
|
||||
var progressSimulator;
|
||||
var startTime = Date.now();
|
||||
|
||||
// Start progress simulation
|
||||
progressSimulator = setInterval(function() {
|
||||
var elapsed = (Date.now() - startTime) / 1000;
|
||||
|
||||
if (elapsed < 5) {
|
||||
// 5-15% - Analyzing content
|
||||
var progress = 5 + (elapsed / 5) * 10;
|
||||
progressBar.css('width', progress + '%');
|
||||
progressText.text(Math.round(progress) + '%');
|
||||
statusText.text('<?php esc_html_e( 'Analyzing your content...', 'maplepress' ); ?>');
|
||||
} else if (elapsed < 10) {
|
||||
// 15-30% - Preparing batches
|
||||
var progress = 15 + ((elapsed - 5) / 5) * 15;
|
||||
progressBar.css('width', progress + '%');
|
||||
progressText.text(Math.round(progress) + '%');
|
||||
statusText.text('<?php esc_html_e( 'Preparing batches for sync...', 'maplepress' ); ?>');
|
||||
batchInfo.show();
|
||||
} else if (elapsed < 60) {
|
||||
// 30-80% - Syncing batches
|
||||
var progress = 30 + ((elapsed - 10) / 50) * 50;
|
||||
progressBar.css('width', Math.min(progress, 80) + '%');
|
||||
progressText.text(Math.round(Math.min(progress, 80)) + '%');
|
||||
statusText.text('<?php esc_html_e( 'Syncing pages to MaplePress...', 'maplepress' ); ?>');
|
||||
detailsText.html('<?php esc_html_e( 'Processing batches...', 'maplepress' ); ?><br><small><?php esc_html_e( 'This may take a moment for large sites.', 'maplepress' ); ?></small>');
|
||||
|
||||
// Simulate batch progress
|
||||
var estimatedBatches = Math.ceil(elapsed / 3);
|
||||
currentBatch.text(estimatedBatches);
|
||||
totalBatches.text(estimatedBatches + Math.ceil((60 - elapsed) / 3));
|
||||
pagesSynced.text(estimatedBatches * 950);
|
||||
} else {
|
||||
// 80-95% - Finalizing
|
||||
var progress = 80 + ((elapsed - 60) / 60) * 15;
|
||||
progressBar.css('width', Math.min(progress, 95) + '%');
|
||||
progressText.text(Math.round(Math.min(progress, 95)) + '%');
|
||||
statusText.text('<?php esc_html_e( 'Finalizing sync...', 'maplepress' ); ?>');
|
||||
detailsText.html('<?php esc_html_e( 'Almost done!', 'maplepress' ); ?>');
|
||||
}
|
||||
}, 500);
|
||||
|
||||
xhr.addEventListener('loadend', function() {
|
||||
clearInterval(progressSimulator);
|
||||
});
|
||||
|
||||
return xhr;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Auto-start sync when page loads
|
||||
setTimeout(startSync, 500);
|
||||
});
|
||||
</script>
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin ready-to-sync page template.
|
||||
* This page is shown after first-time connection to prompt user to manually start sync.
|
||||
*
|
||||
* @package MaplePress
|
||||
* @subpackage MaplePress/includes
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$options = get_option( 'maplepress_settings', array() );
|
||||
?>
|
||||
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e( 'MaplePress - Ready to Sync', 'maplepress' ); ?></h1>
|
||||
|
||||
<div style="max-width: 800px; margin: 40px auto;">
|
||||
<div style="background: #fff; border: 1px solid #dcdcde; padding: 40px; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
|
||||
|
||||
<!-- Success icon -->
|
||||
<div style="text-align: center; margin-bottom: 30px;">
|
||||
<span style="display: inline-block; width: 80px; height: 80px; line-height: 80px; border-radius: 50%; background: #00a32a; color: #fff; font-size: 48px;">✓</span>
|
||||
</div>
|
||||
|
||||
<!-- Main message -->
|
||||
<h2 style="text-align: center; margin: 20px 0; color: #1d2327; font-size: 28px;">
|
||||
<?php esc_html_e( 'Connection Successful!', 'maplepress' ); ?>
|
||||
</h2>
|
||||
|
||||
<p style="text-align: center; color: #666; font-size: 18px; margin: 20px 0;">
|
||||
<?php esc_html_e( 'Your site is now connected to MaplePress.', 'maplepress' ); ?>
|
||||
</p>
|
||||
|
||||
<!-- Important notice -->
|
||||
<div style="background: #fff3cd; border: 1px solid #ffc107; border-radius: 4px; padding: 20px; margin: 30px 0; text-align: center;">
|
||||
<p style="margin: 0; color: #856404; font-size: 16px; font-weight: 600;">
|
||||
<?php esc_html_e( 'You must sync all your pages to continue.', 'maplepress' ); ?>
|
||||
</p>
|
||||
<p style="margin: 10px 0 0 0; color: #856404; font-size: 14px;">
|
||||
<?php esc_html_e( 'This is a one-time process that will make all your published content searchable via MaplePress.', 'maplepress' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Action buttons -->
|
||||
<div style="text-align: center; margin: 40px 0 20px 0;">
|
||||
<a href="<?php echo admin_url( 'admin.php?page=maplepress-initial-sync' ); ?>" class="button button-primary button-hero" style="font-size: 18px; padding: 12px 36px; height: auto;">
|
||||
<?php esc_html_e( 'Start Sync Now', 'maplepress' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Divider -->
|
||||
<hr style="margin: 40px 0; border: none; border-top: 1px solid #dcdcde;">
|
||||
|
||||
<!-- Secondary actions -->
|
||||
<div style="text-align: center;">
|
||||
<p style="color: #666; font-size: 14px; margin-bottom: 15px;">
|
||||
<?php esc_html_e( 'Need to start over?', 'maplepress' ); ?>
|
||||
</p>
|
||||
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" onsubmit="return confirm('<?php echo esc_js( __( 'Are you sure you want to reset all MaplePress settings? This will disconnect your site from MaplePress.', 'maplepress' ) ); ?>');">
|
||||
<?php wp_nonce_field( 'maplepress_reset_settings' ); ?>
|
||||
<input type="hidden" name="action" value="maplepress_reset_settings">
|
||||
<button type="submit" class="button button-link-delete" style="color: #d63638; text-decoration: none;">
|
||||
<?php esc_html_e( 'Reset All Settings', 'maplepress' ); ?>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,332 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin settings page template.
|
||||
*
|
||||
* @package MaplePress
|
||||
* @subpackage MaplePress/includes
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if (!defined("ABSPATH")) {
|
||||
exit();
|
||||
} ?>
|
||||
|
||||
<div class="wrap">
|
||||
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
|
||||
|
||||
<?php
|
||||
$options = get_option("maplepress_settings");
|
||||
$has_api_key = !empty($options["api_key"]);
|
||||
$is_verified = isset($options["is_verified"]) && $options["is_verified"];
|
||||
|
||||
// Refresh quota data if verified and API credentials are available
|
||||
// Fetch fresh data on every page load without persisting to avoid triggering hooks
|
||||
if (
|
||||
$is_verified &&
|
||||
!empty($options["api_url"]) &&
|
||||
!empty($options["api_key"])
|
||||
) {
|
||||
require_once MAPLEPRESS_PLUGIN_DIR .
|
||||
"includes/class-maplepress-api-client.php";
|
||||
$api_client = new MaplePress_API_Client(
|
||||
$options["api_url"],
|
||||
$options["api_key"],
|
||||
);
|
||||
$fresh_status = $api_client->verify_connection();
|
||||
|
||||
// Update options with fresh quota data if API call succeeded
|
||||
// Note: We only update the in-memory $options array, not the database
|
||||
// This ensures fresh display without triggering validation hooks
|
||||
if (!is_wp_error($fresh_status)) {
|
||||
// Update quota fields in options for display only
|
||||
if (isset($fresh_status["search_requests_count"])) {
|
||||
$options["search_requests_count"] = absint(
|
||||
$fresh_status["search_requests_count"],
|
||||
);
|
||||
}
|
||||
if (isset($fresh_status["storage_used_bytes"])) {
|
||||
$options["storage_used_bytes"] = absint(
|
||||
$fresh_status["storage_used_bytes"],
|
||||
);
|
||||
}
|
||||
if (isset($fresh_status["monthly_pages_indexed"])) {
|
||||
$options["monthly_pages_indexed"] = absint(
|
||||
$fresh_status["monthly_pages_indexed"],
|
||||
);
|
||||
}
|
||||
if (isset($fresh_status["total_pages_indexed"])) {
|
||||
$options["total_pages_indexed"] = absint(
|
||||
$fresh_status["total_pages_indexed"],
|
||||
);
|
||||
}
|
||||
// Do NOT call update_option() here - it could trigger validation/sync hooks
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php if (!$has_api_key): ?>
|
||||
<!-- First-time setup instructions -->
|
||||
<div class="notice notice-info" style="padding: 15px; margin: 20px 0;">
|
||||
<h2 style="margin-top: 0;"><?php esc_html_e(
|
||||
"🚀 Welcome to MaplePress!",
|
||||
"maplepress",
|
||||
); ?></h2>
|
||||
<p><?php esc_html_e(
|
||||
"MaplePress provides cloud services for your WordPress site - starting with advanced search, with more features coming soon (uploads, metrics, analytics, etc.).",
|
||||
"maplepress",
|
||||
); ?></p>
|
||||
<p><strong><?php esc_html_e(
|
||||
'✨ When you save settings with "Enable MaplePress search" checked, all your existing pages will automatically sync!',
|
||||
"maplepress",
|
||||
); ?></strong></p>
|
||||
<p><?php esc_html_e("To get started, follow these steps:", "maplepress"); ?></p>
|
||||
<ol style="margin-left: 20px;">
|
||||
<li>
|
||||
<strong><?php esc_html_e(
|
||||
"Create a MaplePress account:",
|
||||
"maplepress",
|
||||
); ?></strong><br>
|
||||
<a href="https://getmaplepress.com/register" target="_blank" class="button button-primary" style="margin-top: 5px;">
|
||||
<?php esc_html_e("Sign Up at MaplePress.io", "maplepress"); ?>
|
||||
</a>
|
||||
<?php esc_html_e("or", "maplepress"); ?>
|
||||
<a href="https://getmaplepress.com/login" target="_blank" class="button" style="margin-top: 5px;">
|
||||
<?php esc_html_e("Login to Existing Account", "maplepress"); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li style="margin-top: 10px;">
|
||||
<strong><?php esc_html_e(
|
||||
"Create a site in your dashboard",
|
||||
"maplepress",
|
||||
); ?></strong><br>
|
||||
<span style="color: #666;"><?php esc_html_e(
|
||||
"After logging in, create a new site for this WordPress installation.",
|
||||
"maplepress",
|
||||
); ?></span>
|
||||
</li>
|
||||
<li style="margin-top: 10px;">
|
||||
<strong><?php esc_html_e(
|
||||
"Copy your API URL and API key",
|
||||
"maplepress",
|
||||
); ?></strong><br>
|
||||
<span style="color: #666;">
|
||||
<?php esc_html_e(
|
||||
"Your API URL is https://getmaplepress.ca (or your custom backend URL). Your API key will be displayed once - make sure to copy both!",
|
||||
"maplepress",
|
||||
); ?>
|
||||
</span>
|
||||
</li>
|
||||
<li style="margin-top: 10px;">
|
||||
<strong><?php esc_html_e(
|
||||
"Paste your API URL and API key below and save",
|
||||
"maplepress",
|
||||
); ?></strong>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php settings_errors("maplepress_settings"); ?>
|
||||
|
||||
<?php // Display sync status messages
|
||||
if (isset($_GET["sync_status"])) {
|
||||
if (
|
||||
$_GET["sync_status"] === "success" &&
|
||||
isset($_GET["synced_count"])
|
||||
) { ?>
|
||||
<div class="notice notice-success is-dismissible">
|
||||
<p>
|
||||
<?php printf(
|
||||
/* translators: %d: number of pages synced */
|
||||
esc_html__(
|
||||
"✓ Successfully synced %d pages to MaplePress!",
|
||||
"maplepress",
|
||||
),
|
||||
absint($_GET["synced_count"]),
|
||||
); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php } elseif (
|
||||
$_GET["sync_status"] === "error" &&
|
||||
isset($_GET["sync_message"])
|
||||
) { ?>
|
||||
<div class="notice notice-error is-dismissible">
|
||||
<p>
|
||||
<?php printf(
|
||||
/* translators: %s: error message */
|
||||
esc_html__("✗ Sync failed: %s", "maplepress"),
|
||||
esc_html(urldecode($_GET["sync_message"])),
|
||||
); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php } elseif ($_GET["sync_status"] === "no_posts") { ?>
|
||||
<div class="notice notice-warning is-dismissible">
|
||||
<p><?php esc_html_e(
|
||||
"No published posts or pages found to sync.",
|
||||
"maplepress",
|
||||
); ?></p>
|
||||
</div>
|
||||
<?php }
|
||||
} ?>
|
||||
|
||||
<form method="post" action="options.php">
|
||||
<?php
|
||||
settings_fields("maplepress_settings_group");
|
||||
do_settings_sections("maplepress");
|
||||
submit_button(__("Save Settings & Verify Connection", "maplepress"));
|
||||
?>
|
||||
</form>
|
||||
|
||||
<?php if ($is_verified): ?>
|
||||
<!-- Connection status - show site details -->
|
||||
<hr>
|
||||
<h2><?php esc_html_e("✓ Connected to MaplePress", "maplepress"); ?></h2>
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e("Domain", "maplepress"); ?></th>
|
||||
<td><?php echo esc_html($options["domain"] ?? "N/A"); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e("Plan", "maplepress"); ?></th>
|
||||
<td><strong><?php echo esc_html(
|
||||
ucfirst($options["plan_tier"] ?? "free"),
|
||||
); ?></strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e("Status", "maplepress"); ?></th>
|
||||
<td>
|
||||
<?php if ($options["enabled"]): ?>
|
||||
<span style="color: #46b450; font-weight: bold;">● <?php esc_html_e(
|
||||
"Active",
|
||||
"maplepress",
|
||||
); ?></span>
|
||||
<?php else: ?>
|
||||
<span style="color: #dc3232; font-weight: bold;">● <?php esc_html_e(
|
||||
"Inactive (Enable above to activate)",
|
||||
"maplepress",
|
||||
); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<?php if (
|
||||
isset($options["storage_quota_bytes"]) ||
|
||||
isset($options["search_quota_monthly"]) ||
|
||||
isset($options["indexing_quota_pages"])
|
||||
): ?>
|
||||
<h3><?php esc_html_e("Usage & Quotas", "maplepress"); ?></h3>
|
||||
<table class="form-table">
|
||||
<?php if (isset($options["storage_quota_bytes"])): ?>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e("Storage", "maplepress"); ?></th>
|
||||
<td>
|
||||
<?php
|
||||
$used = isset($options["storage_used_bytes"])
|
||||
? $options["storage_used_bytes"]
|
||||
: 0;
|
||||
$quota = $options["storage_quota_bytes"];
|
||||
$used_mb = round($used / 1024 / 1024, 2);
|
||||
$quota_mb = round($quota / 1024 / 1024, 2);
|
||||
$percent = $quota > 0 ? round(($used / $quota) * 100, 1) : 0;
|
||||
?>
|
||||
<strong><?php echo esc_html($used_mb); ?> MB</strong> / <?php echo esc_html(
|
||||
$quota_mb,
|
||||
); ?> MB
|
||||
<span style="color: <?php echo $percent > 80
|
||||
? "#dc3232"
|
||||
: "#46b450"; ?>;">(<?php echo esc_html($percent); ?>% used)</span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($options["search_quota_monthly"])): ?>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e("Monthly Searches", "maplepress"); ?></th>
|
||||
<td>
|
||||
<?php
|
||||
$used = isset($options["search_requests_count"])
|
||||
? $options["search_requests_count"]
|
||||
: 0;
|
||||
$quota = $options["search_quota_monthly"];
|
||||
$percent = $quota > 0 ? round(($used / $quota) * 100, 1) : 0;
|
||||
?>
|
||||
<strong><?php echo esc_html(
|
||||
number_format($used),
|
||||
); ?></strong> / <?php echo esc_html(number_format($quota)); ?>
|
||||
<span style="color: <?php echo $percent > 80
|
||||
? "#dc3232"
|
||||
: "#46b450"; ?>;">(<?php echo esc_html($percent); ?>% used)</span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($options["indexing_quota_pages"])): ?>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e("Monthly Indexing", "maplepress"); ?></th>
|
||||
<td>
|
||||
<?php
|
||||
$used = isset($options["monthly_pages_indexed"])
|
||||
? $options["monthly_pages_indexed"]
|
||||
: 0;
|
||||
$quota = $options["indexing_quota_pages"];
|
||||
$percent = $quota > 0 ? round(($used / $quota) * 100, 1) : 0;
|
||||
?>
|
||||
<strong><?php echo esc_html(
|
||||
number_format($used),
|
||||
); ?></strong> / <?php echo esc_html(number_format($quota)); ?> pages
|
||||
<span style="color: <?php echo $percent > 80
|
||||
? "#dc3232"
|
||||
: "#46b450"; ?>;">(<?php echo esc_html(
|
||||
$percent,
|
||||
); ?>% used this month)</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e("Total Pages Indexed", "maplepress"); ?></th>
|
||||
<td>
|
||||
<?php $total = isset($options["total_pages_indexed"])
|
||||
? $options["total_pages_indexed"]
|
||||
: 0; ?>
|
||||
<strong><?php echo esc_html(number_format($total)); ?></strong> pages (all-time)
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
<hr>
|
||||
<h2><?php esc_html_e("Sync Pages", "maplepress"); ?></h2>
|
||||
<p><?php esc_html_e(
|
||||
"Sync all your published posts and pages to MaplePress. New posts and pages are automatically synced when published.",
|
||||
"maplepress",
|
||||
); ?></p>
|
||||
<form method="post" action="<?php echo esc_url(admin_url("admin.php")); ?>">
|
||||
<input type="hidden" name="action" value="maplepress_bulk_sync">
|
||||
<?php wp_nonce_field("maplepress_bulk_sync"); ?>
|
||||
<p>
|
||||
<button type="submit" class="button button-primary">
|
||||
<?php esc_html_e("Sync All Pages Now", "maplepress"); ?>
|
||||
</button>
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<p>
|
||||
<a href="https://getmaplepress.com/dashboard" target="_blank" class="button">
|
||||
<?php esc_html_e("→ Open MaplePress Dashboard", "maplepress"); ?>
|
||||
</a>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2><?php esc_html_e("About MaplePress", "maplepress"); ?></h2>
|
||||
<p>
|
||||
<?php printf(
|
||||
/* translators: %s: MaplePress website URL */
|
||||
esc_html__(
|
||||
"MaplePress is a cloud services platform for WordPress that offloads computationally intensive tasks to dedicated infrastructure. Currently featuring advanced search capabilities, with more services coming soon including uploads, metrics, and analytics. Visit %s to learn more.",
|
||||
"maplepress",
|
||||
),
|
||||
'<a href="https://mapleopentech.io" target="_blank">https://mapleopentech.io</a>',
|
||||
); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,536 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin settings page template.
|
||||
*
|
||||
* @package MaplePress
|
||||
* @subpackage MaplePress/includes
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$options = get_option( 'maplepress_settings', array() );
|
||||
$has_api_key = ! empty( $options['api_key'] );
|
||||
$is_verified = isset( $options['is_verified'] ) && $options['is_verified'];
|
||||
|
||||
// Debug: Log current options
|
||||
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
||||
error_log( 'MaplePress Settings Page - api_url: ' . ( $options['api_url'] ?? 'NOT SET' ) );
|
||||
error_log( 'MaplePress Settings Page - api_key: ' . ( isset( $options['api_key'] ) ? 'SET (' . strlen( $options['api_key'] ) . ' chars)' : 'NOT SET' ) );
|
||||
error_log( 'MaplePress Settings Page - has_api_key: ' . ( $has_api_key ? 'true' : 'false' ) );
|
||||
error_log( 'MaplePress Settings Page - is_verified: ' . ( $is_verified ? 'true' : 'false' ) );
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e( 'MaplePress Settings', 'maplepress' ); ?></h1>
|
||||
|
||||
<?php
|
||||
// WordPress automatically displays settings errors, no need to call settings_errors() manually
|
||||
?>
|
||||
|
||||
<?php if ( ! $has_api_key ) : ?>
|
||||
<!-- First-time setup instructions -->
|
||||
<div class="notice notice-info" style="padding: 15px; margin: 20px 0;">
|
||||
<h2 style="margin-top: 0;"><?php esc_html_e( '🚀 Getting Started', 'maplepress' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Connect your WordPress site to MaplePress cloud services to enable advanced search and more.', 'maplepress' ); ?></p>
|
||||
<ol style="margin-left: 20px;">
|
||||
<li>
|
||||
<strong><?php esc_html_e( 'Create a MaplePress account:', 'maplepress' ); ?></strong><br>
|
||||
<a href="https://getmaplepress.com/register" target="_blank" class="button button-primary" style="margin-top: 5px;">
|
||||
<?php esc_html_e( 'Sign Up', 'maplepress' ); ?>
|
||||
</a>
|
||||
<?php esc_html_e( 'or', 'maplepress' ); ?>
|
||||
<a href="https://getmaplepress.com/login" target="_blank" class="button" style="margin-top: 5px;">
|
||||
<?php esc_html_e( 'Login', 'maplepress' ); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li style="margin-top: 10px;">
|
||||
<strong><?php esc_html_e( 'Create a site in your dashboard', 'maplepress' ); ?></strong>
|
||||
</li>
|
||||
<li style="margin-top: 10px;">
|
||||
<strong><?php esc_html_e( 'Copy your API credentials and paste them below', 'maplepress' ); ?></strong>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post" action="options.php">
|
||||
<?php settings_fields( 'maplepress_settings_group' ); ?>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="api_url"><?php esc_html_e( 'API URL', 'maplepress' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<?php if ( $is_verified ) : ?>
|
||||
<!-- Show URL as read-only when verified -->
|
||||
<input type="text"
|
||||
id="api_url"
|
||||
value="<?php echo esc_attr( $options['api_url'] ?? '' ); ?>"
|
||||
class="regular-text"
|
||||
disabled>
|
||||
<input type="hidden"
|
||||
name="maplepress_settings[api_url]"
|
||||
value="<?php echo esc_attr( $options['api_url'] ?? '' ); ?>">
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Connected. To change, disconnect first.', 'maplepress' ); ?>
|
||||
</p>
|
||||
<?php else : ?>
|
||||
<!-- Allow editing when not verified -->
|
||||
<input type="text"
|
||||
id="api_url"
|
||||
name="maplepress_settings[api_url]"
|
||||
value="<?php echo esc_attr( ! empty( $options['api_url'] ) ? $options['api_url'] : 'https://getmaplepress.ca' ); ?>"
|
||||
class="regular-text"
|
||||
placeholder="https://getmaplepress.ca">
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Your MaplePress API endpoint URL', 'maplepress' ); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="api_key"><?php esc_html_e( 'API Key', 'maplepress' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<?php if ( $is_verified ) : ?>
|
||||
<!-- Show masked key when verified -->
|
||||
<div style="margin-bottom: 10px;">
|
||||
<code style="background: #f0f0f1; padding: 8px 12px; border-radius: 3px; font-size: 13px;">
|
||||
<?php
|
||||
$prefix = $options['api_key_prefix'] ?? 'mpsk';
|
||||
$last_four = $options['api_key_last_four'] ?? '****';
|
||||
echo esc_html( $prefix . '_' . str_repeat( '*', 28 ) . $last_four );
|
||||
?>
|
||||
</code>
|
||||
</div>
|
||||
<input type="hidden"
|
||||
name="maplepress_settings[api_key]"
|
||||
value="<?php echo esc_attr( $options['api_key'] ?? '' ); ?>">
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Your API key is securely stored. To change it, disconnect first.', 'maplepress' ); ?>
|
||||
</p>
|
||||
<?php else : ?>
|
||||
<!-- Allow editing when not verified -->
|
||||
<input type="password"
|
||||
id="api_key"
|
||||
name="maplepress_settings[api_key]"
|
||||
value="<?php echo esc_attr( $options['api_key'] ?? '' ); ?>"
|
||||
class="regular-text"
|
||||
placeholder="live_sk_... or test_sk_...">
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Your MaplePress API key. Use "live_" prefix for production (https://getmaplepress.ca) or "test_" prefix for development/custom URLs.', 'maplepress' ); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<?php if ( $has_api_key && ! $is_verified ) : ?>
|
||||
<!-- DNS Verification Required Section -->
|
||||
<tr>
|
||||
<th scope="row" colspan="2">
|
||||
<h3 style="margin: 30px 0 10px 0; color: #d63638;">
|
||||
⚠️ <?php esc_html_e( 'Domain Verification Required', 'maplepress' ); ?>
|
||||
</h3>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="notice notice-warning inline" style="margin: 0; padding: 20px; background: #fff3cd; border-left: 4px solid #ffc107;">
|
||||
<h4 style="margin-top: 0;">
|
||||
<?php esc_html_e( '🔐 Your API key is connected, but your domain needs verification to enable syncing.', 'maplepress' ); ?>
|
||||
</h4>
|
||||
|
||||
<p><?php esc_html_e( 'To verify ownership of your domain, please add the following DNS TXT record:', 'maplepress' ); ?></p>
|
||||
|
||||
<table class="widefat" style="background: #f9f9f9; margin: 15px 0; max-width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 150px; font-weight: bold; padding: 12px;">
|
||||
<?php esc_html_e( 'Host/Name:', 'maplepress' ); ?>
|
||||
</td>
|
||||
<td style="padding: 12px;">
|
||||
<code style="background: #fff; padding: 5px 10px; font-size: 13px;">
|
||||
<?php echo esc_html( $options['domain'] ?? 'your-domain.com' ); ?>
|
||||
</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold; padding: 12px;">
|
||||
<?php esc_html_e( 'Type:', 'maplepress' ); ?>
|
||||
</td>
|
||||
<td style="padding: 12px;">
|
||||
<code style="background: #fff; padding: 5px 10px; font-size: 13px;">TXT</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold; padding: 12px;">
|
||||
<?php esc_html_e( 'Value:', 'maplepress' ); ?>
|
||||
</td>
|
||||
<td style="padding: 12px;">
|
||||
<code style="background: #fff; padding: 5px 10px; font-size: 13px; word-break: break-all;">
|
||||
maplepress-verify=<?php echo esc_html( $options['verification_token'] ?? 'xxx' ); ?>
|
||||
</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div style="background: #e7f3ff; border-left: 3px solid #2271b1; padding: 15px; margin: 20px 0;">
|
||||
<h4 style="margin-top: 0;">
|
||||
<?php esc_html_e( '📋 Step-by-Step Instructions:', 'maplepress' ); ?>
|
||||
</h4>
|
||||
<ol style="margin: 10px 0 10px 20px; line-height: 1.8;">
|
||||
<li><?php esc_html_e( 'Log in to your domain registrar (GoDaddy, Namecheap, Cloudflare, etc.)', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'Navigate to DNS settings for your domain', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'Add a new TXT record with the values shown above', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'Wait 5-10 minutes for DNS propagation (can take up to 48 hours)', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'Click the "Verify Domain Now" button below', 'maplepress' ); ?></li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<!-- Progress indicator (hidden by default) -->
|
||||
<div id="maplepress-verification-progress" style="display: none; background: #fff; border: 1px solid #dcdcde; padding: 20px; margin: 20px 0; border-radius: 4px;">
|
||||
<div style="display: flex; align-items: center; margin-bottom: 15px;">
|
||||
<span class="spinner is-active" style="float: none; margin: 0 10px 0 0;"></span>
|
||||
<strong id="maplepress-verification-status" style="font-size: 14px;">Verifying domain...</strong>
|
||||
</div>
|
||||
|
||||
<div id="maplepress-verification-details" style="color: #666; font-size: 13px; margin-top: 10px;">
|
||||
<!-- Progress details will appear here -->
|
||||
</div>
|
||||
|
||||
<!-- Progress bar -->
|
||||
<div id="maplepress-verification-progressbar" style="display: none; margin-top: 15px;">
|
||||
<div style="background: #f0f0f1; border-radius: 4px; height: 24px; position: relative; overflow: hidden;">
|
||||
<div id="maplepress-verification-progressbar-fill" style="background: linear-gradient(90deg, #2271b1 0%, #135e96 100%); height: 100%; width: 0%; transition: width 0.3s ease; display: flex; align-items: center; justify-content: center;">
|
||||
<span id="maplepress-verification-progressbar-text" style="color: #fff; font-size: 12px; font-weight: 600; position: absolute; width: 100%; text-align: center; z-index: 2;"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="maplepress-verify-form" method="post" action="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>" style="margin-top: 20px;">
|
||||
<input type="hidden" name="action" value="maplepress_verify_domain">
|
||||
<?php wp_nonce_field( 'maplepress_verify_domain' ); ?>
|
||||
<p>
|
||||
<button type="submit" id="maplepress-verify-button" class="button button-primary button-large">
|
||||
🔍 <?php esc_html_e( 'Verify Domain Now', 'maplepress' ); ?>
|
||||
</button>
|
||||
<span style="margin-left: 15px; color: #666;">
|
||||
<?php esc_html_e( 'Make sure you\'ve added the DNS record and waited a few minutes before clicking.', 'maplepress' ); ?>
|
||||
</span>
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
$('#maplepress-verify-form').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var button = $('#maplepress-verify-button');
|
||||
var progressBox = $('#maplepress-verification-progress');
|
||||
var statusText = $('#maplepress-verification-status');
|
||||
var detailsBox = $('#maplepress-verification-details');
|
||||
var progressBar = $('#maplepress-verification-progressbar');
|
||||
var progressBarFill = $('#maplepress-verification-progressbar-fill');
|
||||
var progressBarText = $('#maplepress-verification-progressbar-text');
|
||||
|
||||
// Disable button and show progress
|
||||
button.prop('disabled', true);
|
||||
button.text('⏳ Verifying...');
|
||||
progressBox.show();
|
||||
statusText.text('Step 1 of 2: Verifying domain ownership...');
|
||||
detailsBox.html('Checking DNS TXT record...');
|
||||
|
||||
var startTime = Date.now();
|
||||
|
||||
// Make AJAX request
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'maplepress_verify_and_sync_ajax',
|
||||
nonce: '<?php echo wp_create_nonce( 'maplepress_verify_and_sync_ajax' ); ?>'
|
||||
},
|
||||
timeout: 300000, // 5 minute timeout for large sites
|
||||
xhr: function() {
|
||||
var xhr = new window.XMLHttpRequest();
|
||||
|
||||
// Simulate progress during long operations
|
||||
var progressSimulator = setInterval(function() {
|
||||
var elapsed = (Date.now() - startTime) / 1000;
|
||||
|
||||
if (elapsed < 5) {
|
||||
detailsBox.html('Checking DNS TXT record...');
|
||||
} else if (elapsed < 10) {
|
||||
statusText.text('Step 2 of 2: Syncing pages to MaplePress...');
|
||||
detailsBox.html('Preparing pages for sync...');
|
||||
progressBar.show();
|
||||
progressBarFill.css('width', '10%');
|
||||
progressBarText.text('10%');
|
||||
} else if (elapsed < 30) {
|
||||
var progress = Math.min(10 + ((elapsed - 10) / 20) * 60, 70);
|
||||
detailsBox.html('Syncing pages to MaplePress cloud...<br><small>This may take a moment for large sites...</small>');
|
||||
progressBarFill.css('width', progress + '%');
|
||||
progressBarText.text(Math.round(progress) + '%');
|
||||
} else {
|
||||
var progress = Math.min(70 + ((elapsed - 30) / 30) * 25, 95);
|
||||
detailsBox.html('Almost done, finalizing sync...<br><small>Processing batches...</small>');
|
||||
progressBarFill.css('width', progress + '%');
|
||||
progressBarText.text(Math.round(progress) + '%');
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
xhr.addEventListener('loadend', function() {
|
||||
clearInterval(progressSimulator);
|
||||
});
|
||||
|
||||
return xhr;
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
// Show 100% complete
|
||||
progressBar.show();
|
||||
progressBarFill.css('width', '100%');
|
||||
progressBarText.text('100%');
|
||||
|
||||
statusText.html('<span style="color: #008a00;">✓ ' + response.data.message + '</span>');
|
||||
detailsBox.html(response.data.details || '');
|
||||
|
||||
// Reload page after 2 seconds
|
||||
setTimeout(function() {
|
||||
window.location.href = '<?php echo admin_url( 'admin.php?page=maplepress-settings&verification_status=success' ); ?>';
|
||||
}, 2000);
|
||||
} else {
|
||||
progressBar.hide();
|
||||
statusText.html('<span style="color: #d63638;">✗ Verification failed</span>');
|
||||
detailsBox.html('<strong>Error:</strong> ' + (response.data || 'Unknown error'));
|
||||
button.prop('disabled', false);
|
||||
button.text('🔍 <?php esc_html_e( 'Verify Domain Now', 'maplepress' ); ?>');
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
progressBar.hide();
|
||||
statusText.html('<span style="color: #d63638;">✗ Network error</span>');
|
||||
detailsBox.html('<strong>Error:</strong> ' + error);
|
||||
button.prop('disabled', false);
|
||||
button.text('🔍 <?php esc_html_e( 'Verify Domain Now', 'maplepress' ); ?>');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php if ( isset( $_GET['verification_status'] ) && $_GET['verification_status'] === 'failed' ) : ?>
|
||||
<div class="notice notice-error inline" style="margin-top: 20px; padding: 15px; background: #fee; border-left: 4px solid #dc3232;">
|
||||
<h4 style="margin: 0 0 10px 0; color: #dc3232;">
|
||||
❌ <?php esc_html_e( 'Verification Failed', 'maplepress' ); ?>
|
||||
</h4>
|
||||
<p style="margin: 0 0 15px 0; font-size: 14px;">
|
||||
<strong><?php esc_html_e( 'Error:', 'maplepress' ); ?></strong><br>
|
||||
<?php
|
||||
if ( isset( $_GET['verification_message'] ) ) {
|
||||
echo esc_html( urldecode( $_GET['verification_message'] ) );
|
||||
} else {
|
||||
esc_html_e( 'Unknown verification error. Please check your settings and try again.', 'maplepress' );
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
|
||||
<?php
|
||||
$error_message = isset( $_GET['verification_message'] ) ? urldecode( $_GET['verification_message'] ) : '';
|
||||
|
||||
// Show different troubleshooting tips based on error type
|
||||
if ( strpos( $error_message, 'API URL' ) !== false || strpos( $error_message, 'API Key' ) !== false ) :
|
||||
?>
|
||||
<div style="background: #fff; padding: 15px; border-radius: 4px; margin-top: 15px;">
|
||||
<h4 style="margin: 0 0 10px 0;"><?php esc_html_e( 'Configuration Issue:', 'maplepress' ); ?></h4>
|
||||
<p style="margin: 0;"><?php esc_html_e( 'Please go back and save your API URL and API Key before attempting verification.', 'maplepress' ); ?></p>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div style="background: #fff; padding: 15px; border-radius: 4px; margin-top: 15px;">
|
||||
<h4 style="margin: 0 0 10px 0;"><?php esc_html_e( 'Common Issues:', 'maplepress' ); ?></h4>
|
||||
<ul style="margin: 0; padding-left: 20px; line-height: 1.8;">
|
||||
<li><?php esc_html_e( 'DNS record hasn\'t propagated yet (usually takes 5-10 minutes, can take up to 48 hours)', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'TXT record value doesn\'t match exactly (check for typos or extra spaces)', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'TXT record added to wrong domain or subdomain', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'Backend API connectivity issue (check if https://getmaplepress.ca is accessible)', 'maplepress' ); ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style="background: #e7f3ff; border-left: 3px solid #2271b1; padding: 15px; margin-top: 15px;">
|
||||
<p style="margin: 0; font-size: 14px;">
|
||||
<strong>💡 <?php esc_html_e( 'Tip:', 'maplepress' ); ?></strong>
|
||||
<?php esc_html_e( 'You can check if your DNS record is visible using online tools like "whatsmydns.net" or "dnschecker.org". Search for TXT records for your domain.', 'maplepress' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( isset( $_GET['verification_status'] ) && $_GET['verification_status'] === 'success' ) : ?>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="notice notice-success inline" style="margin: 20px 0; padding: 15px;">
|
||||
<p style="margin: 0;">
|
||||
<strong>✓ <?php esc_html_e( 'Domain Verified Successfully!', 'maplepress' ); ?></strong><br>
|
||||
<?php
|
||||
if ( isset( $_GET['sync_status'] ) && $_GET['sync_status'] === 'success' && isset( $_GET['synced_count'] ) ) {
|
||||
printf(
|
||||
esc_html__( 'Your domain has been verified and %d pages have been synced to MaplePress!', 'maplepress' ),
|
||||
absint( $_GET['synced_count'] )
|
||||
);
|
||||
} else {
|
||||
esc_html_e( 'Your site is now fully connected to MaplePress. You can now sync pages and use all features.', 'maplepress' );
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $is_verified ) : ?>
|
||||
<!-- Connection Status -->
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Connection Status', 'maplepress' ); ?></th>
|
||||
<td>
|
||||
<span style="color: #46b450; font-weight: bold;">
|
||||
✓ <?php esc_html_e( 'Connected', 'maplepress' ); ?>
|
||||
</span>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Your site is successfully connected to MaplePress.', 'maplepress' ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Billing Information -->
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Billing Model', 'maplepress' ); ?></th>
|
||||
<td>
|
||||
<strong><?php esc_html_e( 'Usage-Based', 'maplepress' ); ?></strong>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Pay only for what you use with no limits or quotas.', 'maplepress' ); ?>
|
||||
<a href="https://getmaplepress.com/pricing" target="_blank">
|
||||
<?php esc_html_e( 'View pricing details', 'maplepress' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Enable MaplePress -->
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Enable Services', 'maplepress' ); ?></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
name="maplepress_settings[enabled]"
|
||||
value="1"
|
||||
<?php checked( 1, $options['enabled'] ?? false ); ?>>
|
||||
<strong><?php esc_html_e( 'Enable MaplePress', 'maplepress' ); ?></strong>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Turn on MaplePress cloud services for this site.', 'maplepress' ); ?>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Search Settings -->
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Search Settings', 'maplepress' ); ?></th>
|
||||
<td>
|
||||
<fieldset>
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
name="maplepress_settings[enable_frontend_search]"
|
||||
value="1"
|
||||
<?php checked( 1, $options['enable_frontend_search'] ?? true ); ?>>
|
||||
<?php esc_html_e( 'Enable frontend search', 'maplepress' ); ?>
|
||||
</label>
|
||||
<br>
|
||||
<label style="margin-top: 8px; display: inline-block;">
|
||||
<input type="checkbox"
|
||||
name="maplepress_settings[enable_admin_search]"
|
||||
value="1"
|
||||
<?php checked( 1, $options['enable_admin_search'] ?? false ); ?>>
|
||||
<?php esc_html_e( 'Enable admin search', 'maplepress' ); ?>
|
||||
</label>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'Choose where MaplePress search should be used.', 'maplepress' ); ?>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<?php if ( $is_verified ) : ?>
|
||||
<!-- Show both Save and Disconnect buttons when connected -->
|
||||
<p class="submit">
|
||||
<?php submit_button( __( 'Save Settings', 'maplepress' ), 'primary', 'submit', false ); ?>
|
||||
|
||||
<a href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=maplepress-settings&action=disconnect' ), 'maplepress_disconnect' ) ); ?>"
|
||||
class="button button-secondary"
|
||||
onclick="return confirm('<?php esc_attr_e( 'Are you sure you want to disconnect from MaplePress? Your data will remain in the cloud.', 'maplepress' ); ?>');">
|
||||
<?php esc_html_e( 'Disconnect', 'maplepress' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
<?php else : ?>
|
||||
<!-- Show only Connect button when not connected -->
|
||||
<?php submit_button( __( 'Connect to MaplePress', 'maplepress' ), 'primary', 'submit', true ); ?>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
|
||||
<!-- Reset Settings -->
|
||||
<hr style="margin: 40px 0 20px 0;">
|
||||
<h3><?php esc_html_e( 'Reset Settings', 'maplepress' ); ?></h3>
|
||||
<p><?php esc_html_e( 'If you need to start over, you can reset all MaplePress settings.', 'maplepress' ); ?></p>
|
||||
<form method="post" action="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>" style="margin-top: 20px;">
|
||||
<input type="hidden" name="action" value="maplepress_reset_settings">
|
||||
<?php wp_nonce_field( 'maplepress_reset_settings' ); ?>
|
||||
<button type="submit"
|
||||
class="button button-secondary"
|
||||
style="color: #d63638; border-color: #d63638;"
|
||||
onclick="return confirm('<?php esc_attr_e( 'Are you sure you want to reset all MaplePress settings?\n\nThis will:\n- Delete API URL and API Key\n- Clear verification status\n- Remove all configuration\n\nYour data in the MaplePress cloud will NOT be affected.\n\nYou will need to reconnect after reset.', 'maplepress' ); ?>');">
|
||||
🔄 <?php esc_html_e( 'Reset All Settings', 'maplepress' ); ?>
|
||||
</button>
|
||||
<p class="description">
|
||||
<?php esc_html_e( 'This will delete all plugin settings from WordPress. Your data in the MaplePress cloud will remain safe.', 'maplepress' ); ?>
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<?php if ( $is_verified ) : ?>
|
||||
<!-- Show connection info when connected -->
|
||||
<hr style="margin: 40px 0;">
|
||||
<h2><?php esc_html_e( 'Connection Details', 'maplepress' ); ?></h2>
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Domain', 'maplepress' ); ?></th>
|
||||
<td><?php echo esc_html( $options['domain'] ?? 'N/A' ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php esc_html_e( 'Connected Since', 'maplepress' ); ?></th>
|
||||
<td>
|
||||
<?php
|
||||
// Assuming connection doesn't change often, we can use current time as reference
|
||||
// In a real scenario, you'd store a 'connected_at' timestamp
|
||||
esc_html_e( 'Active connection', 'maplepress' );
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
<?php
|
||||
/**
|
||||
* Simple Admin Speed Test Page
|
||||
*
|
||||
* @package MaplePress_SearchSpeedTest
|
||||
*/
|
||||
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_die( esc_html__( 'You do not have permission to access this page.', 'maplepress-searchspeedtest' ) );
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="wrap mpss-wrap">
|
||||
<!-- Header -->
|
||||
<div style="margin: 30px 0 40px 0;">
|
||||
<h1 style="font-size: 32px; font-weight: 300; margin: 0 0 10px 0; color: #1e1e1e;">
|
||||
<span style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; font-weight: 600;">
|
||||
<?php esc_html_e( 'How Fast is Your Search?', 'maplepress-searchspeedtest' ); ?>
|
||||
</span>
|
||||
</h1>
|
||||
<p style="font-size: 16px; color: #666; margin: 0;">
|
||||
<?php esc_html_e( 'Find out how quickly visitors can search your website', 'maplepress-searchspeedtest' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Test Configuration -->
|
||||
<div class="mpss-test-config">
|
||||
<div class="mpss-card" style="max-width: 900px; background: linear-gradient(to bottom, #ffffff 0%, #f8f9fa 100%); border: none; box-shadow: 0 2px 20px rgba(0, 0, 0, 0.08); border-radius: 16px; padding: 40px;">
|
||||
|
||||
<!-- Number of Queries Section -->
|
||||
<div style="margin-bottom: 35px;">
|
||||
<label for="mpss-query-count" style="display: block; font-size: 15px; font-weight: 600; margin-bottom: 8px; color: #1e1e1e;">
|
||||
<span style="display: inline-block; width: 32px; height: 32px; line-height: 32px; text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 50%; margin-right: 10px; font-size: 14px;">1</span>
|
||||
<?php esc_html_e( 'How thorough should the test be?', 'maplepress-searchspeedtest' ); ?>
|
||||
</label>
|
||||
<p style="font-size: 13px; color: #666; margin: 0 0 15px 42px; line-height: 1.5;">
|
||||
<?php esc_html_e( 'More searches = more accurate results, but takes longer to complete', 'maplepress-searchspeedtest' ); ?>
|
||||
</p>
|
||||
<div style="background: white; padding: 20px; border-radius: 12px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);">
|
||||
<select id="mpss-query-count" name="query_count" style="width: 100%; padding: 12px 16px; font-size: 15px; border: 2px solid #e0e0e0; border-radius: 8px; background: white; cursor: pointer; transition: all 0.2s;">
|
||||
<option value="10" selected>10 searches - Super quick (recommended to start) ⭐</option>
|
||||
<option value="50">50 searches - Quick and accurate</option>
|
||||
<option value="100">100 searches - Balanced (good choice)</option>
|
||||
<option value="250">250 searches - Very thorough</option>
|
||||
<option value="500">500 searches - Heavy load test</option>
|
||||
<option value="1000">1,000 searches - Serious stress test</option>
|
||||
<option value="2500">2,500 searches - Extreme testing</option>
|
||||
<option value="5000">5,000 searches - Maximum stress 🔥</option>
|
||||
<option value="10000">10,000 searches - Ultimate challenge 💪</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Execution Mode Section -->
|
||||
<div style="margin-bottom: 35px;">
|
||||
<label style="display: block; font-size: 15px; font-weight: 600; margin-bottom: 8px; color: #1e1e1e;">
|
||||
<span style="display: inline-block; width: 32px; height: 32px; line-height: 32px; text-align: center; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; border-radius: 50%; margin-right: 10px; font-size: 14px;">2</span>
|
||||
<?php esc_html_e( 'How should we test?', 'maplepress-searchspeedtest' ); ?>
|
||||
</label>
|
||||
<p style="font-size: 13px; color: #666; margin: 0 0 15px 42px; line-height: 1.5;">
|
||||
<?php esc_html_e( 'Choose how the test simulates visitors searching your site', 'maplepress-searchspeedtest' ); ?>
|
||||
</p>
|
||||
|
||||
<!-- Normal Mode Card -->
|
||||
<label class="mpss-mode-card" for="mpss-mode-serial" style="display: block; margin-bottom: 15px; cursor: pointer;">
|
||||
<input type="radio" name="execution_mode" id="mpss-mode-serial" value="serial" checked style="display: none;">
|
||||
<div class="mpss-mode-card-inner" style="background: white; padding: 20px; border-radius: 12px; border: 2px solid #e0e0e0; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); transition: all 0.3s;">
|
||||
<div style="display: flex; align-items: center; margin-bottom: 8px;">
|
||||
<span style="font-size: 24px; margin-right: 12px;">👤</span>
|
||||
<div>
|
||||
<div style="font-size: 16px; font-weight: 600; color: #1e1e1e;">
|
||||
<?php esc_html_e( 'Normal - One Person at a Time', 'maplepress-searchspeedtest' ); ?>
|
||||
<span class="mpss-mode-badge" style="display: inline-block; margin-left: 8px; padding: 2px 8px; background: #e8f5e9; color: #2e7d32; font-size: 11px; font-weight: 600; border-radius: 4px; text-transform: uppercase;">Start Here</span>
|
||||
</div>
|
||||
<div style="font-size: 13px; color: #666; margin-top: 4px;">
|
||||
<?php esc_html_e( 'Simulates one visitor searching at a time', 'maplepress-searchspeedtest' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mpss-serial-explanation" style="margin-top: 12px; padding: 12px; background: linear-gradient(to right, rgba(102, 126, 234, 0.05), rgba(118, 75, 162, 0.05)); border-left: 3px solid #667eea; border-radius: 6px; font-size: 13px; color: #666; line-height: 1.6;">
|
||||
💡 <?php esc_html_e( 'Best for everyday testing. Shows how fast searches are under normal conditions.', 'maplepress-searchspeedtest' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<!-- Stress Test Mode Card -->
|
||||
<label class="mpss-mode-card" for="mpss-mode-parallel" style="display: block; cursor: pointer;">
|
||||
<input type="radio" name="execution_mode" id="mpss-mode-parallel" value="parallel" style="display: none;">
|
||||
<div class="mpss-mode-card-inner" style="background: white; padding: 20px; border-radius: 12px; border: 2px solid #e0e0e0; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); transition: all 0.3s;">
|
||||
<div style="display: flex; align-items: center; margin-bottom: 8px;">
|
||||
<span style="font-size: 24px; margin-right: 12px;">👥</span>
|
||||
<div>
|
||||
<div style="font-size: 16px; font-weight: 600; color: #1e1e1e;">
|
||||
<?php esc_html_e( 'Stress Test - Many People at Once', 'maplepress-searchspeedtest' ); ?>
|
||||
<span class="mpss-mode-badge" style="display: inline-block; margin-left: 8px; padding: 2px 8px; background: #fff3e0; color: #e65100; font-size: 11px; font-weight: 600; border-radius: 4px; text-transform: uppercase;">Advanced</span>
|
||||
</div>
|
||||
<div style="font-size: 13px; color: #666; margin-top: 4px;">
|
||||
<?php esc_html_e( 'Simulates many visitors searching at the same time', 'maplepress-searchspeedtest' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mpss-parallel-explanation" style="margin-top: 12px; padding: 12px; background: linear-gradient(to right, rgba(255, 152, 0, 0.05), rgba(255, 87, 34, 0.05)); border-left: 3px solid #ff9800; border-radius: 6px; font-size: 13px; color: #e65100; line-height: 1.6;">
|
||||
⚠️ <?php esc_html_e( 'Tests your site under heavy load. May temporarily slow down your website.', 'maplepress-searchspeedtest' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Run Button -->
|
||||
<div style="text-align: center; margin-top: 40px;">
|
||||
<button id="mpss-run-test" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; padding: 18px 56px; font-size: 17px; font-weight: 600; border-radius: 50px; cursor: pointer; box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4); transition: all 0.3s; display: inline-flex; align-items: center; gap: 10px;">
|
||||
<span style="font-size: 22px;">🚀</span>
|
||||
<?php esc_html_e( 'Start Test Now', 'maplepress-searchspeedtest' ); ?>
|
||||
</button>
|
||||
<p style="font-size: 12px; color: #999; margin-top: 15px;">
|
||||
<?php esc_html_e( 'This won\'t affect your live website or visitors', 'maplepress-searchspeedtest' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Progress -->
|
||||
<div id="mpss-progress" class="mpss-progress" style="display: none;">
|
||||
<div class="mpss-card" style="max-width: 900px; background: linear-gradient(to bottom, #ffffff 0%, #f8f9fa 100%); border: none; box-shadow: 0 2px 20px rgba(0, 0, 0, 0.08); border-radius: 16px; padding: 40px;">
|
||||
<div style="text-align: center;">
|
||||
<div style="font-size: 48px; margin-bottom: 20px;">⏳</div>
|
||||
<h2 style="font-size: 24px; font-weight: 600; margin: 0 0 15px 0;">
|
||||
<?php esc_html_e( 'Testing Your Search Speed...', 'maplepress-searchspeedtest' ); ?>
|
||||
</h2>
|
||||
<p id="mpss-progress-text" style="font-size: 15px; color: #666; margin-bottom: 10px;">
|
||||
<?php esc_html_e( 'Please wait, this will only take a moment...', 'maplepress-searchspeedtest' ); ?>
|
||||
</p>
|
||||
<div id="mpss-progress-counter" style="font-size: 32px; font-weight: bold; color: #667eea; margin: 15px 0;">
|
||||
<span id="mpss-completed-count">0</span> / <span id="mpss-total-count">0</span>
|
||||
</div>
|
||||
<p style="font-size: 13px; color: #999; margin-bottom: 5px;">searches completed</p>
|
||||
<p id="mpss-time-estimate" style="font-size: 13px; color: #667eea; font-weight: 600; margin-bottom: 25px;">
|
||||
<?php esc_html_e( 'Estimated time: calculating...', 'maplepress-searchspeedtest' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
<div class="mpss-progress-bar">
|
||||
<div id="mpss-progress-fill" class="mpss-progress-fill" style="width: 0%;"></div>
|
||||
</div>
|
||||
<div style="text-align: center; margin-top: 20px;">
|
||||
<button id="mpss-cancel-test" style="background: transparent; color: #dc3232; border: 2px solid #dc3232; padding: 10px 24px; font-size: 14px; font-weight: 600; border-radius: 50px; cursor: pointer; transition: all 0.3s;">
|
||||
<span style="font-size: 16px;">✕</span> <?php esc_html_e( 'Cancel Test', 'maplepress-searchspeedtest' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Results -->
|
||||
<div id="mpss-results" class="mpss-results" style="display: none;">
|
||||
<div class="mpss-card" style="max-width: 900px; background: linear-gradient(to bottom, #ffffff 0%, #f8f9fa 100%); border: none; box-shadow: 0 2px 20px rgba(0, 0, 0, 0.08); border-radius: 16px; padding: 40px;">
|
||||
<div style="text-align: center; margin-bottom: 30px;">
|
||||
<div style="font-size: 64px; margin-bottom: 15px;">✅</div>
|
||||
<h2 style="font-size: 28px; font-weight: 600; margin: 0 0 10px 0;">
|
||||
<?php esc_html_e( 'Your Results Are Ready!', 'maplepress-searchspeedtest' ); ?>
|
||||
</h2>
|
||||
<p style="font-size: 15px; color: #666; margin: 0;">
|
||||
<?php esc_html_e( 'Here\'s how your search performed', 'maplepress-searchspeedtest' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Summary Stats -->
|
||||
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 30px; margin: 30px auto; max-width: 800px;">
|
||||
<div style="text-align: center; padding: 30px 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 12px; box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);">
|
||||
<div style="font-size: 48px; font-weight: bold; color: #fff; margin-bottom: 10px;" id="mpss-total-queries">-</div>
|
||||
<div style="font-size: 14px; color: rgba(255, 255, 255, 0.9); text-transform: uppercase; letter-spacing: 1px; font-weight: 600;"><?php esc_html_e( 'Searches Tested', 'maplepress-searchspeedtest' ); ?></div>
|
||||
</div>
|
||||
<div style="text-align: center; padding: 30px 20px; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); border-radius: 12px; box-shadow: 0 4px 15px rgba(245, 87, 108, 0.4);">
|
||||
<div style="font-size: 48px; font-weight: bold; color: #fff; margin-bottom: 10px;" id="mpss-total-time">-</div>
|
||||
<div style="font-size: 14px; color: rgba(255, 255, 255, 0.9); text-transform: uppercase; letter-spacing: 1px; font-weight: 600;"><?php esc_html_e( 'Time Taken', 'maplepress-searchspeedtest' ); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Recommendations -->
|
||||
<div id="mpss-recommendations" style="margin: 30px 0;"></div>
|
||||
|
||||
<!-- Chart -->
|
||||
<div style="margin: 40px 0;">
|
||||
<h3 style="font-size: 18px; font-weight: 600; margin: 0 0 20px 0; color: #1e1e1e;">
|
||||
📊 <?php esc_html_e( 'Individual Search Times', 'maplepress-searchspeedtest' ); ?>
|
||||
</h3>
|
||||
<canvas id="mpss-chart"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div style="display: flex; gap: 15px; justify-content: center; margin-top: 40px; padding-top: 30px; border-top: 1px solid #e0e0e0;">
|
||||
<button id="mpss-run-again" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; padding: 12px 32px; font-size: 15px; font-weight: 600; border-radius: 50px; cursor: pointer; box-shadow: 0 2px 10px rgba(102, 126, 234, 0.3); transition: all 0.3s; display: inline-flex; align-items: center; gap: 8px;">
|
||||
<span style="font-size: 16px;">🔄</span>
|
||||
<?php esc_html_e( 'Test Again', 'maplepress-searchspeedtest' ); ?>
|
||||
</button>
|
||||
<button id="mpss-share-results" style="background: #3b5998; color: white; border: none; padding: 12px 32px; font-size: 15px; font-weight: 600; border-radius: 50px; cursor: pointer; box-shadow: 0 2px 10px rgba(59, 89, 152, 0.3); transition: all 0.3s; display: inline-flex; align-items: center; gap: 8px;">
|
||||
<span style="font-size: 16px;">📤</span>
|
||||
<?php esc_html_e( 'Share Results', 'maplepress-searchspeedtest' ); ?>
|
||||
</button>
|
||||
<button id="mpss-export-results" style="background: white; color: #667eea; border: 2px solid #667eea; padding: 12px 32px; font-size: 15px; font-weight: 600; border-radius: 50px; cursor: pointer; transition: all 0.3s; display: inline-flex; align-items: center; gap: 8px;">
|
||||
<span style="font-size: 16px;">📥</span>
|
||||
<?php esc_html_e( 'Download Results', 'maplepress-searchspeedtest' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Share Modal -->
|
||||
<div id="mpss-share-modal" style="display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.7); z-index: 9999; align-items: center; justify-content: center;">
|
||||
<div style="background: white; padding: 40px; border-radius: 20px; max-width: 600px; width: 90%; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3); position: relative;">
|
||||
<button id="mpss-close-share-modal" style="position: absolute; top: 15px; right: 15px; background: none; border: none; font-size: 24px; cursor: pointer; color: #999; transition: color 0.2s;" onmouseover="this.style.color='#333'" onmouseout="this.style.color='#999'">✖</button>
|
||||
|
||||
<h2 style="margin: 0 0 25px 0; font-size: 24px; text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;">
|
||||
📤 Share Your Results
|
||||
</h2>
|
||||
|
||||
<div id="mpss-share-content" style="margin-bottom: 30px; text-align: center;">
|
||||
<div id="mpss-share-graphic" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 40px; border-radius: 16px; color: white; margin-bottom: 20px;">
|
||||
<!-- Share graphic will be generated here -->
|
||||
</div>
|
||||
<p style="color: #666; font-size: 13px;">Click a button below to share your results</p>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px;">
|
||||
<button class="mpss-share-twitter" style="background: #1DA1F2; color: white; border: none; padding: 15px; font-size: 15px; font-weight: 600; border-radius: 12px; cursor: pointer; transition: all 0.3s; display: flex; align-items: center; justify-content: center; gap: 8px;" onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 4px 15px rgba(29, 161, 242, 0.4)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='none'">
|
||||
<span style="font-size: 18px;">🐦</span>
|
||||
Twitter / X
|
||||
</button>
|
||||
<button class="mpss-share-facebook" style="background: #1877F2; color: white; border: none; padding: 15px; font-size: 15px; font-weight: 600; border-radius: 12px; cursor: pointer; transition: all 0.3s; display: flex; align-items: center; justify-content: center; gap: 8px;" onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 4px 15px rgba(24, 119, 242, 0.4)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='none'">
|
||||
<span style="font-size: 18px;">👥</span>
|
||||
Facebook
|
||||
</button>
|
||||
<button class="mpss-share-linkedin" style="background: #0A66C2; color: white; border: none; padding: 15px; font-size: 15px; font-weight: 600; border-radius: 12px; cursor: pointer; transition: all 0.3s; display: flex; align-items: center; justify-content: center; gap: 8px;" onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 4px 15px rgba(10, 102, 194, 0.4)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='none'">
|
||||
<span style="font-size: 18px;">💼</span>
|
||||
LinkedIn
|
||||
</button>
|
||||
<button class="mpss-share-copy" style="background: #10b981; color: white; border: none; padding: 15px; font-size: 15px; font-weight: 600; border-radius: 12px; cursor: pointer; transition: all 0.3s; display: flex; align-items: center; justify-content: center; gap: 8px;" onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 4px 15px rgba(16, 185, 129, 0.4)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='none'">
|
||||
<span style="font-size: 18px;">📋</span>
|
||||
Copy Link
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin System Information Page
|
||||
*
|
||||
* @package MaplePress
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Load system info class
|
||||
require_once MAPLEPRESS_PLUGIN_DIR . 'includes/class-maplepress-system-info.php';
|
||||
|
||||
// Get system information
|
||||
$system_info = MaplePress_System_Info::get_all_info();
|
||||
?>
|
||||
|
||||
<div class="wrap">
|
||||
<h1><?php esc_html_e( 'System Information', 'maplepress' ); ?></h1>
|
||||
|
||||
<div class="notice notice-info" style="padding: 15px; margin: 20px 0;">
|
||||
<h2 style="margin-top: 0;">
|
||||
📊 <?php esc_html_e( 'System Diagnostics', 'maplepress' ); ?>
|
||||
</h2>
|
||||
<p>
|
||||
<?php esc_html_e( 'This page shows detailed information about your server configuration, PHP-FPM workers, and system resources. Use this data to diagnose performance bottlenecks.', 'maplepress' ); ?>
|
||||
</p>
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'Key Metrics to Check:', 'maplepress' ); ?></strong>
|
||||
</p>
|
||||
<ul style="margin-left: 20px;">
|
||||
<li><?php esc_html_e( 'PHP-FPM Max Children: Should be ≥50 for 4GB servers to handle concurrent requests', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'OpCache Status: Should be enabled for better PHP performance', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'Memory Limits: PHP memory_limit should be 256M+', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'Load Average: Should be below CPU count for healthy performance', 'maplepress' ); ?></li>
|
||||
<li><?php esc_html_e( 'Database Connections: max_connections should be 200+ for high traffic', 'maplepress' ); ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Check for critical issues
|
||||
$warnings = array();
|
||||
|
||||
// Check PHP-FPM max_children
|
||||
if ( isset( $system_info['php_fpm']['max_children'] ) && is_numeric( $system_info['php_fpm']['max_children'] ) ) {
|
||||
if ( $system_info['php_fpm']['max_children'] < 25 ) {
|
||||
$warnings[] = sprintf(
|
||||
__( '⚠️ PHP-FPM max_children is %d. Recommended: 50+ for 4GB servers. This is the #1 WordPress performance bottleneck.', 'maplepress' ),
|
||||
$system_info['php_fpm']['max_children']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check OpCache
|
||||
if ( ! $system_info['php']['opcache_enabled'] ) {
|
||||
$warnings[] = __( '⚠️ OpCache is not enabled. Enable it for 30-50% faster PHP execution.', 'maplepress' );
|
||||
}
|
||||
|
||||
// Check memory limit
|
||||
$memory_limit = ini_get( 'memory_limit' );
|
||||
if ( preg_match( '/^(\d+)/', $memory_limit, $matches ) ) {
|
||||
if ( (int) $matches[1] < 128 ) {
|
||||
$warnings[] = sprintf(
|
||||
__( '⚠️ PHP memory_limit is %s. Recommended: 256M or higher.', 'maplepress' ),
|
||||
$memory_limit
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Display warnings
|
||||
if ( ! empty( $warnings ) ) :
|
||||
?>
|
||||
<div class="notice notice-warning" style="padding: 15px; margin: 20px 0; border-left-color: #ffc107;">
|
||||
<h3 style="margin-top: 0; color: #856404;">
|
||||
⚠️ <?php esc_html_e( 'Performance Warnings', 'maplepress' ); ?>
|
||||
</h3>
|
||||
<ul style="margin-left: 20px; color: #856404;">
|
||||
<?php foreach ( $warnings as $warning ) : ?>
|
||||
<li><?php echo esc_html( $warning ); ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<p style="margin-bottom: 0;">
|
||||
<a href="<?php echo esc_url( MAPLEPRESS_PLUGIN_URL . 'docs/PERFORMANCE_OPTIMIZATION.md' ); ?>"
|
||||
class="button button-primary"
|
||||
target="_blank"
|
||||
style="background: #856404; border-color: #856404;">
|
||||
📖 <?php esc_html_e( 'Read Performance Optimization Guide', 'maplepress' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="notice notice-success" style="padding: 15px; margin: 20px 0;">
|
||||
<p style="margin: 0;">
|
||||
<strong>✓ <?php esc_html_e( 'System configuration looks good!', 'maplepress' ); ?></strong>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- System Information Tables -->
|
||||
<?php echo MaplePress_System_Info::format_as_html( $system_info ); ?>
|
||||
|
||||
<!-- Export Button -->
|
||||
<div style="margin-top: 30px;">
|
||||
<button id="copy-system-info" class="button button-primary">
|
||||
📋 <?php esc_html_e( 'Copy All Info to Clipboard', 'maplepress' ); ?>
|
||||
</button>
|
||||
<button id="download-system-info" class="button">
|
||||
💾 <?php esc_html_e( 'Download as JSON', 'maplepress' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
// Copy to clipboard
|
||||
$('#copy-system-info').on('click', function() {
|
||||
var systemInfo = <?php echo wp_json_encode( $system_info ); ?>;
|
||||
var text = JSON.stringify(systemInfo, null, 2);
|
||||
|
||||
navigator.clipboard.writeText(text).then(function() {
|
||||
alert('<?php esc_html_e( 'System information copied to clipboard!', 'maplepress' ); ?>');
|
||||
}).catch(function() {
|
||||
// Fallback for older browsers
|
||||
var textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(textarea);
|
||||
alert('<?php esc_html_e( 'System information copied to clipboard!', 'maplepress' ); ?>');
|
||||
});
|
||||
});
|
||||
|
||||
// Download as JSON
|
||||
$('#download-system-info').on('click', function() {
|
||||
var systemInfo = <?php echo wp_json_encode( $system_info ); ?>;
|
||||
var dataStr = JSON.stringify(systemInfo, null, 2);
|
||||
var dataBlob = new Blob([dataStr], {type: 'application/json'});
|
||||
var url = URL.createObjectURL(dataBlob);
|
||||
|
||||
var link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = 'maplepress-system-info-' + Date.now() + '.json';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
/**
|
||||
* Fired during plugin activation.
|
||||
*
|
||||
* @package MaplePress
|
||||
* @subpackage MaplePress/includes
|
||||
*/
|
||||
|
||||
class MaplePress_Activator {
|
||||
|
||||
/**
|
||||
* Activation tasks.
|
||||
*
|
||||
* Creates default options and flushes rewrite rules.
|
||||
*/
|
||||
public static function activate() {
|
||||
// Set default options.
|
||||
// Allow developers to override API URL via wp-config.php constant
|
||||
$default_api_url = defined( 'MAPLEPRESS_API_URL' ) ? MAPLEPRESS_API_URL : '';
|
||||
|
||||
$default_options = array(
|
||||
'api_url' => $default_api_url, // Empty by default - user must configure
|
||||
'api_key' => '',
|
||||
'site_id' => '',
|
||||
'tenant_id' => '',
|
||||
'domain' => '',
|
||||
'plan_tier' => '',
|
||||
'is_verified' => false,
|
||||
'enabled' => false,
|
||||
'needs_setup' => true, // Flag to show setup notice
|
||||
);
|
||||
|
||||
add_option( 'maplepress_settings', $default_options );
|
||||
|
||||
// Set activation redirect flag
|
||||
set_transient( 'maplepress_activation_redirect', true, 30 );
|
||||
|
||||
// Flush rewrite rules.
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,226 @@
|
|||
<?php
|
||||
/**
|
||||
* MaplePress API Client - handles communication with MaplePress backend.
|
||||
*
|
||||
* @package MaplePress
|
||||
* @subpackage MaplePress/includes
|
||||
*/
|
||||
|
||||
class MaplePress_API_Client {
|
||||
|
||||
/**
|
||||
* API base URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $api_url;
|
||||
|
||||
/**
|
||||
* API key.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $api_key;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $api_url API base URL.
|
||||
* @param string $api_key API key.
|
||||
*/
|
||||
public function __construct( $api_url, $api_key ) {
|
||||
$this->api_url = trailingslashit( $api_url );
|
||||
$this->api_key = $api_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify API connection and API key.
|
||||
*
|
||||
* @return array|WP_Error Response data or WP_Error on failure.
|
||||
*/
|
||||
public function verify_connection() {
|
||||
return $this->request( 'GET', 'api/v1/plugin/status' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger domain verification via DNS TXT record check.
|
||||
*
|
||||
* @return array|WP_Error Response data or WP_Error on failure.
|
||||
*/
|
||||
public function verify_domain() {
|
||||
error_log( 'MaplePress API: verify_domain() called' );
|
||||
$result = $this->request( 'POST', 'api/v1/plugin/verify' );
|
||||
error_log( 'MaplePress API: verify_domain() result = ' . print_r( $result, true ) );
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a request to the MaplePress API.
|
||||
*
|
||||
* @param string $method HTTP method (GET, POST, PUT, DELETE).
|
||||
* @param string $endpoint API endpoint (relative to base URL).
|
||||
* @param array $body Optional. Request body data.
|
||||
* @return array|WP_Error Response data or WP_Error on failure.
|
||||
*/
|
||||
private function request( $method, $endpoint, $body = array() ) {
|
||||
$url = $this->api_url . ltrim( $endpoint, '/' );
|
||||
|
||||
// Debug logging (only enable when WP_DEBUG is true)
|
||||
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
||||
error_log( "MaplePress API: Making $method request to: $url" );
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'method' => $method,
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $this->api_key,
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
'timeout' => 15,
|
||||
);
|
||||
|
||||
if ( ! empty( $body ) && in_array( $method, array( 'POST', 'PUT', 'PATCH' ), true ) ) {
|
||||
$args['body'] = wp_json_encode( $body );
|
||||
}
|
||||
|
||||
$response = wp_remote_request( $url, $args );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$status_code = wp_remote_retrieve_response_code( $response );
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$data = json_decode( $body, true );
|
||||
|
||||
if ( $status_code >= 400 ) {
|
||||
$error_message = isset( $data['message'] ) ? $data['message'] : __( 'Unknown API error', 'maplepress' );
|
||||
|
||||
// Log full response for debugging
|
||||
error_log( 'MaplePress API Error Response:' );
|
||||
error_log( 'Status Code: ' . $status_code );
|
||||
error_log( 'Raw Body: ' . $body );
|
||||
error_log( 'Parsed Data: ' . print_r( $data, true ) );
|
||||
|
||||
// Determine error code based on status
|
||||
$error_code = 'maplepress_api_error';
|
||||
if ( $status_code === 429 ) {
|
||||
$error_code = 'maplepress_rate_limited';
|
||||
} elseif ( $status_code === 403 ) {
|
||||
$error_code = 'maplepress_forbidden';
|
||||
} elseif ( $status_code === 404 ) {
|
||||
$error_code = 'maplepress_not_found';
|
||||
}
|
||||
|
||||
return new WP_Error(
|
||||
$error_code,
|
||||
sprintf(
|
||||
/* translators: 1: HTTP status code, 2: error message */
|
||||
__( 'API Error (%1$d): %2$s', 'maplepress' ),
|
||||
$status_code,
|
||||
$error_message
|
||||
),
|
||||
array( 'status' => $status_code )
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync pages to MaplePress backend.
|
||||
*
|
||||
* @param array $pages Array of page data to sync.
|
||||
* @return array|WP_Error Response data or WP_Error on failure.
|
||||
*/
|
||||
public function sync_pages( $pages ) {
|
||||
$data = array(
|
||||
'pages' => $pages,
|
||||
);
|
||||
|
||||
return $this->request( 'POST', 'api/v1/plugin/pages/sync', $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Index a post in MaplePress (single page).
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @return array|WP_Error Response data or WP_Error on failure.
|
||||
*/
|
||||
public function index_post( $post_id ) {
|
||||
$post = get_post( $post_id );
|
||||
|
||||
if ( ! $post ) {
|
||||
return new WP_Error( 'invalid_post', __( 'Post not found', 'maplepress' ) );
|
||||
}
|
||||
|
||||
// Format page data for API
|
||||
$page_data = $this->format_page_data( $post );
|
||||
|
||||
// Sync single page
|
||||
return $this->sync_pages( array( $page_data ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format post/page data for API sync.
|
||||
*
|
||||
* @param WP_Post $post Post object.
|
||||
* @return array Formatted page data.
|
||||
*/
|
||||
private function format_page_data( $post ) {
|
||||
// Format timestamps in RFC3339 format (ISO 8601)
|
||||
// Use actual GMT time if available, otherwise use server time converted to GMT
|
||||
$published_at = '';
|
||||
if ( $post->post_date_gmt && $post->post_date_gmt !== '0000-00-00 00:00:00' ) {
|
||||
$published_at = gmdate( 'Y-m-d\TH:i:s\Z', strtotime( $post->post_date_gmt . ' UTC' ) );
|
||||
}
|
||||
|
||||
$modified_at = '';
|
||||
if ( $post->post_modified_gmt && $post->post_modified_gmt !== '0000-00-00 00:00:00' ) {
|
||||
$modified_at = gmdate( 'Y-m-d\TH:i:s\Z', strtotime( $post->post_modified_gmt . ' UTC' ) );
|
||||
}
|
||||
|
||||
return array(
|
||||
'page_id' => (string) $post->ID,
|
||||
'title' => $post->post_title,
|
||||
'content' => wp_strip_all_tags( $post->post_content ),
|
||||
'excerpt' => ! empty( $post->post_excerpt ) ? $post->post_excerpt : wp_trim_words( $post->post_content, 55, '...' ),
|
||||
'url' => get_permalink( $post->ID ),
|
||||
'status' => $post->post_status,
|
||||
'post_type' => $post->post_type,
|
||||
'author' => get_the_author_meta( 'display_name', $post->post_author ),
|
||||
'published_at' => $published_at,
|
||||
'modified_at' => $modified_at,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a post from MaplePress index.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @return array|WP_Error Response data or WP_Error on failure.
|
||||
*/
|
||||
public function delete_post( $post_id ) {
|
||||
return $this->request( 'DELETE', 'api/v1/plugin/index/' . $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Search using MaplePress API.
|
||||
*
|
||||
* @param string $query Search query.
|
||||
* @param array $args Optional. Additional search parameters.
|
||||
* @return array|WP_Error Search results or WP_Error on failure.
|
||||
*/
|
||||
public function search( $query, $args = array() ) {
|
||||
$params = array_merge(
|
||||
array(
|
||||
'query' => $query,
|
||||
'limit' => 10,
|
||||
'offset' => 0,
|
||||
),
|
||||
$args
|
||||
);
|
||||
|
||||
return $this->request( 'POST', 'api/v1/plugin/pages/search', $params );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
/**
|
||||
* Fired during plugin deactivation.
|
||||
*
|
||||
* @package MaplePress
|
||||
* @subpackage MaplePress/includes
|
||||
*/
|
||||
|
||||
class MaplePress_Deactivator {
|
||||
|
||||
/**
|
||||
* Deactivation tasks.
|
||||
*
|
||||
* Flushes rewrite rules.
|
||||
*/
|
||||
public static function deactivate() {
|
||||
// Flush rewrite rules.
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
/**
|
||||
* Register all actions and filters for the plugin.
|
||||
*
|
||||
* @package MaplePress
|
||||
* @subpackage MaplePress/includes
|
||||
*/
|
||||
|
||||
class MaplePress_Loader {
|
||||
|
||||
/**
|
||||
* The array of actions registered with WordPress.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $actions;
|
||||
|
||||
/**
|
||||
* The array of filters registered with WordPress.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
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 to be registered with WordPress.
|
||||
*
|
||||
* @param string $hook The name of the WordPress action.
|
||||
* @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 to be registered with WordPress.
|
||||
*
|
||||
* @param string $hook The name of the WordPress filter.
|
||||
* @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 into a single collection.
|
||||
*
|
||||
* @param array $hooks The collection of hooks that is being registered.
|
||||
* @param string $hook The name of the WordPress filter/action.
|
||||
* @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
|
||||
*/
|
||||
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'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
<?php
|
||||
/**
|
||||
* The public-facing functionality of the plugin.
|
||||
*
|
||||
* @package MaplePress
|
||||
* @subpackage MaplePress/includes
|
||||
*/
|
||||
|
||||
class MaplePress_Public {
|
||||
|
||||
/**
|
||||
* The ID of this plugin.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $plugin_name;
|
||||
|
||||
/**
|
||||
* The version of this plugin.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* Initialize the class and set its properties.
|
||||
*
|
||||
* @param string $plugin_name The name of the plugin.
|
||||
* @param string $version The version of this plugin.
|
||||
*/
|
||||
public function __construct( $plugin_name, $version ) {
|
||||
$this->plugin_name = $plugin_name;
|
||||
$this->version = $version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the stylesheets for the public-facing side of the site.
|
||||
*/
|
||||
public function enqueue_styles() {
|
||||
wp_enqueue_style(
|
||||
$this->plugin_name,
|
||||
MAPLEPRESS_PLUGIN_URL . 'assets/css/maplepress-public.css',
|
||||
array(),
|
||||
$this->version,
|
||||
'all'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the JavaScript for the public-facing side of the site.
|
||||
*/
|
||||
public function enqueue_scripts() {
|
||||
wp_enqueue_script(
|
||||
$this->plugin_name,
|
||||
MAPLEPRESS_PLUGIN_URL . 'assets/js/maplepress-public.js',
|
||||
array( 'jquery' ),
|
||||
$this->version,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept WordPress search and use MaplePress search instead.
|
||||
*
|
||||
* @param WP_Query $query The WordPress query object.
|
||||
*/
|
||||
public function intercept_search( $query ) {
|
||||
// Debug logging - detect if this is from CLI test
|
||||
$is_cli_test = isset( $_SERVER['HTTP_X_MAPLEPRESS_TEST'] );
|
||||
|
||||
// Log every invocation when WP_DEBUG is on or when it's a CLI test
|
||||
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || $is_cli_test ) {
|
||||
error_log( '=== MaplePress intercept_search called ===' );
|
||||
error_log( 'is_main_query: ' . ( $query->is_main_query() ? 'true' : 'false' ) );
|
||||
error_log( 'is_search: ' . ( $query->is_search() ? 'true' : 'false' ) );
|
||||
error_log( 's param: ' . var_export( $query->get( 's' ), true ) );
|
||||
error_log( 'CLI test header: ' . ( $is_cli_test ? 'true' : 'false' ) );
|
||||
}
|
||||
|
||||
// Only intercept main search queries
|
||||
// Check both is_search() and presence of 's' parameter to catch all search scenarios
|
||||
$is_search_query = $query->is_search() || ! empty( $query->get( 's' ) );
|
||||
|
||||
if ( ! $query->is_main_query() || ! $is_search_query ) {
|
||||
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || $is_cli_test ) {
|
||||
error_log( 'MaplePress: Early return - not main query or not search' );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if MaplePress is enabled
|
||||
$options = get_option( 'maplepress_settings' );
|
||||
if ( empty( $options['enabled'] ) || empty( $options['api_url'] ) || empty( $options['api_key'] ) ) {
|
||||
// MaplePress not enabled or configured, use default WordPress search
|
||||
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || $is_cli_test ) {
|
||||
error_log( 'MaplePress: Early return - not enabled or not configured' );
|
||||
error_log( 'enabled: ' . var_export( $options['enabled'] ?? null, true ) );
|
||||
error_log( 'api_url: ' . var_export( $options['api_url'] ?? null, true ) );
|
||||
error_log( 'api_key present: ' . ( ! empty( $options['api_key'] ) ? 'yes' : 'no' ) );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if connection is verified
|
||||
if ( empty( $options['is_verified'] ) ) {
|
||||
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || $is_cli_test ) {
|
||||
error_log( 'MaplePress: Early return - connection not verified' );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if search is enabled for the current context
|
||||
// Speed test queries always proceed regardless of admin/frontend settings
|
||||
if ( ! $is_speed_test ) {
|
||||
$is_admin_area = is_admin();
|
||||
$frontend_search_enabled = isset( $options['enable_frontend_search'] ) ? $options['enable_frontend_search'] : true;
|
||||
$admin_search_enabled = isset( $options['enable_admin_search'] ) ? $options['enable_admin_search'] : false;
|
||||
|
||||
// Skip if admin search is not enabled and we're in admin
|
||||
if ( $is_admin_area && ! $admin_search_enabled ) {
|
||||
// In admin but admin search not enabled
|
||||
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || $is_cli_test ) {
|
||||
error_log( 'MaplePress: Early return - admin search not enabled' );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if frontend search is not enabled and we're on frontend
|
||||
if ( ! $is_admin_area && ! $frontend_search_enabled ) {
|
||||
// On frontend but frontend search not enabled
|
||||
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || $is_cli_test ) {
|
||||
error_log( 'MaplePress: Early return - frontend search not enabled' );
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || $is_cli_test ) {
|
||||
error_log( 'MaplePress: Speed test query - bypassing admin/frontend check' );
|
||||
}
|
||||
}
|
||||
|
||||
// Get the search query
|
||||
// Try get_search_query() first, then fall back to direct query parameter
|
||||
$search_query = get_search_query();
|
||||
if ( empty( $search_query ) ) {
|
||||
$search_query = $query->get( 's' );
|
||||
}
|
||||
if ( empty( $search_query ) ) {
|
||||
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || $is_cli_test ) {
|
||||
error_log( 'MaplePress: Early return - empty search query' );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || $is_cli_test ) {
|
||||
error_log( 'MaplePress: Proceeding with search for: ' . $search_query );
|
||||
}
|
||||
|
||||
// Call MaplePress search API
|
||||
require_once MAPLEPRESS_PLUGIN_DIR . 'includes/class-maplepress-api-client.php';
|
||||
$api_client = new MaplePress_API_Client( $options['api_url'], $options['api_key'] );
|
||||
|
||||
$search_args = array(
|
||||
'limit' => (int) $query->get( 'posts_per_page', 10 ),
|
||||
'offset' => (int) ( ( $query->get( 'paged', 1 ) - 1 ) * $query->get( 'posts_per_page', 10 ) ),
|
||||
);
|
||||
|
||||
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || $is_cli_test ) {
|
||||
error_log( 'MaplePress: Calling API with query: ' . $search_query );
|
||||
error_log( 'MaplePress: API URL: ' . $options['api_url'] );
|
||||
error_log( 'MaplePress: Search args: ' . json_encode( $search_args ) );
|
||||
}
|
||||
|
||||
$result = $api_client->search( $search_query, $search_args );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
// API error - fall back to default WordPress search
|
||||
// Log the error for debugging
|
||||
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
||||
error_log( 'MaplePress search error: ' . $result->get_error_message() );
|
||||
}
|
||||
if ( $is_cli_test ) {
|
||||
error_log( 'MaplePress search error (CLI test): ' . $result->get_error_message() );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || $is_cli_test ) {
|
||||
error_log( 'MaplePress: API call successful, results: ' . json_encode( $result ) );
|
||||
}
|
||||
|
||||
// Extract page IDs from MaplePress results
|
||||
$page_ids = array();
|
||||
if ( ! empty( $result['hits'] ) ) {
|
||||
foreach ( $result['hits'] as $result_item ) {
|
||||
// Meilisearch returns 'id' field, not 'page_id'
|
||||
if ( ! empty( $result_item['id'] ) ) {
|
||||
$page_ids[] = (int) $result_item['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no results, show empty results
|
||||
if ( empty( $page_ids ) ) {
|
||||
$query->set( 'post__in', array( 0 ) ); // Force no results
|
||||
} else {
|
||||
// Set query to only return posts matching MaplePress results in the correct order
|
||||
$query->set( 'post__in', $page_ids );
|
||||
$query->set( 'orderby', 'post__in' ); // Maintain MaplePress result order
|
||||
|
||||
// In admin context, respect the existing post_type filter (e.g., 'page' when in Pages list)
|
||||
// On frontend, allow any post type
|
||||
if ( ! is_admin() ) {
|
||||
$query->set( 'post_type', 'any' ); // Allow any post type on frontend
|
||||
}
|
||||
// Note: In admin, we preserve whatever post_type was already set by WordPress
|
||||
|
||||
$query->set( 'post_status', 'publish' );
|
||||
|
||||
// Disable the default search query
|
||||
$query->set( 's', '' );
|
||||
}
|
||||
|
||||
// Store the original search query for display
|
||||
$query->set( 'maplepress_search_query', $search_query );
|
||||
|
||||
// Store total results for pagination
|
||||
if ( ! empty( $result['total_hits'] ) ) {
|
||||
add_filter( 'found_posts', function( $found_posts, $query ) use ( $result ) {
|
||||
if ( $query->get( 'maplepress_search_query' ) ) {
|
||||
return (int) $result['total_hits'];
|
||||
}
|
||||
return $found_posts;
|
||||
}, 10, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the search query for display purposes.
|
||||
*
|
||||
* @param string $search_query The search query.
|
||||
* @return string
|
||||
*/
|
||||
public function restore_search_query( $search_query ) {
|
||||
global $wp_query;
|
||||
$maplepress_query = $wp_query->get( 'maplepress_search_query' );
|
||||
if ( ! empty( $maplepress_query ) ) {
|
||||
return $maplepress_query;
|
||||
}
|
||||
return $search_query;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,454 @@
|
|||
<?php
|
||||
/**
|
||||
* System Information Collector
|
||||
*
|
||||
* Collects detailed system information for diagnosing performance bottlenecks.
|
||||
*
|
||||
* @package MaplePress
|
||||
*/
|
||||
|
||||
class MaplePress_System_Info {
|
||||
|
||||
/**
|
||||
* Get all system information.
|
||||
*
|
||||
* @return array System information array.
|
||||
*/
|
||||
public static function get_all_info() {
|
||||
return array(
|
||||
'php' => self::get_php_info(),
|
||||
'php_fpm' => self::get_php_fpm_info(),
|
||||
'server' => self::get_server_info(),
|
||||
'wordpress' => self::get_wordpress_info(),
|
||||
'database' => self::get_database_info(),
|
||||
'performance' => self::get_performance_info(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PHP configuration information.
|
||||
*
|
||||
* @return array PHP configuration.
|
||||
*/
|
||||
private static function get_php_info() {
|
||||
return array(
|
||||
'version' => PHP_VERSION,
|
||||
'sapi' => php_sapi_name(),
|
||||
'memory_limit' => ini_get( 'memory_limit' ),
|
||||
'max_execution_time' => ini_get( 'max_execution_time' ),
|
||||
'max_input_time' => ini_get( 'max_input_time' ),
|
||||
'post_max_size' => ini_get( 'post_max_size' ),
|
||||
'upload_max_filesize' => ini_get( 'upload_max_filesize' ),
|
||||
'max_input_vars' => ini_get( 'max_input_vars' ),
|
||||
'display_errors' => ini_get( 'display_errors' ),
|
||||
'error_reporting' => ini_get( 'error_reporting' ),
|
||||
'opcache_enabled' => function_exists( 'opcache_get_status' ) && opcache_get_status() !== false,
|
||||
'opcache_status' => function_exists( 'opcache_get_status' ) ? opcache_get_status() : null,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PHP-FPM configuration information.
|
||||
*
|
||||
* @return array PHP-FPM configuration.
|
||||
*/
|
||||
private static function get_php_fpm_info() {
|
||||
$info = array(
|
||||
'is_fpm' => false,
|
||||
'pool_name' => 'N/A',
|
||||
'pm_type' => 'N/A',
|
||||
'max_children' => 'N/A',
|
||||
'start_servers' => 'N/A',
|
||||
'min_spare_servers' => 'N/A',
|
||||
'max_spare_servers' => 'N/A',
|
||||
'max_requests' => 'N/A',
|
||||
'status_url' => 'N/A',
|
||||
'active_processes' => 'N/A',
|
||||
'total_processes' => 'N/A',
|
||||
'idle_processes' => 'N/A',
|
||||
'listen_queue' => 'N/A',
|
||||
'listen_queue_len' => 'N/A',
|
||||
'config_file' => 'N/A',
|
||||
);
|
||||
|
||||
// Check if running under PHP-FPM
|
||||
if ( php_sapi_name() === 'fpm-fcgi' || php_sapi_name() === 'cgi-fcgi' ) {
|
||||
$info['is_fpm'] = true;
|
||||
|
||||
// Try to find PHP-FPM config file
|
||||
$possible_config_paths = array(
|
||||
'/etc/php/' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '/fpm/pool.d/www.conf',
|
||||
'/usr/local/etc/php-fpm.d/www.conf',
|
||||
'/etc/php-fpm.d/www.conf',
|
||||
'/etc/php/fpm/pool.d/www.conf',
|
||||
);
|
||||
|
||||
foreach ( $possible_config_paths as $path ) {
|
||||
if ( file_exists( $path ) && is_readable( $path ) ) {
|
||||
$info['config_file'] = $path;
|
||||
$config = self::parse_php_fpm_config( $path );
|
||||
if ( $config ) {
|
||||
$info = array_merge( $info, $config );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to get PHP-FPM status via FastCGI
|
||||
$status = self::get_php_fpm_status();
|
||||
if ( $status ) {
|
||||
$info = array_merge( $info, $status );
|
||||
}
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse PHP-FPM configuration file.
|
||||
*
|
||||
* @param string $config_file Path to config file.
|
||||
* @return array|null Parsed configuration or null.
|
||||
*/
|
||||
private static function parse_php_fpm_config( $config_file ) {
|
||||
$config = array();
|
||||
|
||||
$content = file_get_contents( $config_file );
|
||||
if ( ! $content ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Parse key configuration values (ignore comments after values)
|
||||
$patterns = array(
|
||||
'pool_name' => '/^\[([^\]]+)\]/m',
|
||||
'pm_type' => '/^pm\s*=\s*(\w+)/m',
|
||||
'max_children' => '/^pm\.max_children\s*=\s*(\d+)/m',
|
||||
'start_servers' => '/^pm\.start_servers\s*=\s*(\d+)/m',
|
||||
'min_spare_servers' => '/^pm\.min_spare_servers\s*=\s*(\d+)/m',
|
||||
'max_spare_servers' => '/^pm\.max_spare_servers\s*=\s*(\d+)/m',
|
||||
'max_requests' => '/^pm\.max_requests\s*=\s*(\d+)/m',
|
||||
);
|
||||
|
||||
foreach ( $patterns as $key => $pattern ) {
|
||||
if ( preg_match( $pattern, $content, $matches ) ) {
|
||||
$config[ $key ] = trim( $matches[1] );
|
||||
}
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PHP-FPM status from status endpoint.
|
||||
*
|
||||
* @return array|null Status information or null.
|
||||
*/
|
||||
private static function get_php_fpm_status() {
|
||||
// Try common PHP-FPM status URLs
|
||||
$status_urls = array(
|
||||
'http://localhost/fpm-status',
|
||||
'http://127.0.0.1/fpm-status',
|
||||
'http://localhost/status',
|
||||
);
|
||||
|
||||
foreach ( $status_urls as $url ) {
|
||||
$response = wp_remote_get( $url . '?json' );
|
||||
if ( ! is_wp_error( $response ) && wp_remote_retrieve_response_code( $response ) === 200 ) {
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$data = json_decode( $body, true );
|
||||
if ( $data ) {
|
||||
return array(
|
||||
'pool_name' => $data['pool'] ?? 'N/A',
|
||||
'total_processes' => $data['total processes'] ?? 'N/A',
|
||||
'active_processes' => $data['active processes'] ?? 'N/A',
|
||||
'idle_processes' => $data['idle processes'] ?? 'N/A',
|
||||
'listen_queue' => $data['listen queue'] ?? 'N/A',
|
||||
'listen_queue_len' => $data['listen queue len'] ?? 'N/A',
|
||||
'max_children' => $data['max children reached'] ?? 'N/A',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get server information.
|
||||
*
|
||||
* @return array Server information.
|
||||
*/
|
||||
private static function get_server_info() {
|
||||
return array(
|
||||
'software' => isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : 'Unknown',
|
||||
'os' => PHP_OS,
|
||||
'hostname' => gethostname(),
|
||||
'server_addr' => isset( $_SERVER['SERVER_ADDR'] ) ? $_SERVER['SERVER_ADDR'] : 'Unknown',
|
||||
'document_root' => isset( $_SERVER['DOCUMENT_ROOT'] ) ? $_SERVER['DOCUMENT_ROOT'] : 'Unknown',
|
||||
'cpu_count' => self::get_cpu_count(),
|
||||
'memory_total' => self::get_memory_total(),
|
||||
'memory_available' => self::get_memory_available(),
|
||||
'load_average' => self::get_load_average(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CPU core count.
|
||||
*
|
||||
* @return int|string CPU count or 'Unknown'.
|
||||
*/
|
||||
private static function get_cpu_count() {
|
||||
if ( function_exists( 'shell_exec' ) ) {
|
||||
// Linux
|
||||
$output = shell_exec( 'nproc 2>/dev/null' );
|
||||
if ( $output ) {
|
||||
return (int) trim( $output );
|
||||
}
|
||||
|
||||
// macOS
|
||||
$output = shell_exec( 'sysctl -n hw.ncpu 2>/dev/null' );
|
||||
if ( $output ) {
|
||||
return (int) trim( $output );
|
||||
}
|
||||
}
|
||||
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total system memory in MB.
|
||||
*
|
||||
* @return string Memory in MB or 'Unknown'.
|
||||
*/
|
||||
private static function get_memory_total() {
|
||||
if ( function_exists( 'shell_exec' ) ) {
|
||||
// Linux
|
||||
$output = shell_exec( "free -m | grep Mem | awk '{print $2}'" );
|
||||
if ( $output ) {
|
||||
return trim( $output ) . ' MB';
|
||||
}
|
||||
|
||||
// macOS
|
||||
$output = shell_exec( 'sysctl -n hw.memsize 2>/dev/null' );
|
||||
if ( $output ) {
|
||||
return round( (int) trim( $output ) / 1024 / 1024 ) . ' MB';
|
||||
}
|
||||
}
|
||||
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available system memory in MB.
|
||||
*
|
||||
* @return string Available memory or 'Unknown'.
|
||||
*/
|
||||
private static function get_memory_available() {
|
||||
if ( function_exists( 'shell_exec' ) ) {
|
||||
// Linux
|
||||
$output = shell_exec( "free -m | grep Mem | awk '{print $7}'" );
|
||||
if ( $output ) {
|
||||
return trim( $output ) . ' MB';
|
||||
}
|
||||
}
|
||||
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get system load average.
|
||||
*
|
||||
* @return string Load average or 'Unknown'.
|
||||
*/
|
||||
private static function get_load_average() {
|
||||
if ( function_exists( 'sys_getloadavg' ) ) {
|
||||
$load = sys_getloadavg();
|
||||
return sprintf( '%.2f, %.2f, %.2f', $load[0], $load[1], $load[2] );
|
||||
}
|
||||
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get WordPress information.
|
||||
*
|
||||
* @return array WordPress information.
|
||||
*/
|
||||
private static function get_wordpress_info() {
|
||||
global $wp_version;
|
||||
|
||||
return array(
|
||||
'version' => $wp_version,
|
||||
'multisite' => is_multisite(),
|
||||
'site_url' => get_site_url(),
|
||||
'home_url' => get_home_url(),
|
||||
'debug_mode' => defined( 'WP_DEBUG' ) && WP_DEBUG,
|
||||
'memory_limit' => WP_MEMORY_LIMIT,
|
||||
'max_memory_limit' => WP_MAX_MEMORY_LIMIT,
|
||||
'theme' => wp_get_theme()->get( 'Name' ),
|
||||
'active_plugins' => count( get_option( 'active_plugins', array() ) ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get database information.
|
||||
*
|
||||
* @return array Database information.
|
||||
*/
|
||||
private static function get_database_info() {
|
||||
global $wpdb;
|
||||
|
||||
$info = array(
|
||||
'extension' => $wpdb->db_version(),
|
||||
'server' => $wpdb->get_var( 'SELECT VERSION()' ),
|
||||
'client_version' => $wpdb->db_version(),
|
||||
'database_name' => DB_NAME,
|
||||
'database_host' => DB_HOST,
|
||||
'database_charset' => DB_CHARSET,
|
||||
'table_prefix' => $wpdb->prefix,
|
||||
);
|
||||
|
||||
// Get MySQL configuration
|
||||
$variables = array(
|
||||
'max_connections',
|
||||
'max_allowed_packet',
|
||||
'query_cache_size',
|
||||
'innodb_buffer_pool_size',
|
||||
'tmp_table_size',
|
||||
'max_heap_table_size',
|
||||
);
|
||||
|
||||
foreach ( $variables as $var ) {
|
||||
$value = $wpdb->get_var( "SHOW VARIABLES LIKE '$var'" );
|
||||
if ( $value ) {
|
||||
$info[ $var ] = $wpdb->get_var( "SHOW VARIABLES LIKE '$var'", 1 );
|
||||
}
|
||||
}
|
||||
|
||||
// Get current connections
|
||||
$info['current_connections'] = $wpdb->get_var( "SHOW STATUS LIKE 'Threads_connected'" )
|
||||
? $wpdb->get_var( "SHOW STATUS LIKE 'Threads_connected'", 1 )
|
||||
: 'Unknown';
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get performance-related information.
|
||||
*
|
||||
* @return array Performance information.
|
||||
*/
|
||||
private static function get_performance_info() {
|
||||
return array(
|
||||
'object_cache' => wp_using_ext_object_cache() ? 'External' : 'Built-in',
|
||||
'curl_available' => function_exists( 'curl_version' ),
|
||||
'curl_version' => function_exists( 'curl_version' ) ? curl_version()['version'] : 'N/A',
|
||||
'allow_url_fopen' => ini_get( 'allow_url_fopen' ) ? 'Yes' : 'No',
|
||||
'compression' => extension_loaded( 'zlib' ) ? 'Available' : 'Not available',
|
||||
'https_support' => is_ssl() ? 'Yes' : 'No',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format system info as HTML.
|
||||
*
|
||||
* @param array $info System information array.
|
||||
* @return string HTML output.
|
||||
*/
|
||||
public static function format_as_html( $info ) {
|
||||
ob_start();
|
||||
?>
|
||||
<div class="maplepress-system-info">
|
||||
<?php foreach ( $info as $section => $data ) : ?>
|
||||
<div class="system-info-section">
|
||||
<h3 style="margin-top: 0; padding: 10px; background: #f0f0f1; border-left: 4px solid #2271b1;">
|
||||
<?php echo esc_html( ucwords( str_replace( '_', ' ', $section ) ) ); ?>
|
||||
</h3>
|
||||
<table class="widefat" style="margin-top: 0;">
|
||||
<tbody>
|
||||
<?php foreach ( $data as $key => $value ) : ?>
|
||||
<?php
|
||||
// Check if this is the opcache_status field (which contains a large array)
|
||||
$is_opcache_status = ( $key === 'opcache_status' && is_array( $value ) );
|
||||
$field_id = 'maplepress-field-' . sanitize_title( $section . '-' . $key );
|
||||
?>
|
||||
<tr>
|
||||
<td style="width: 250px; font-weight: bold; vertical-align: top;">
|
||||
<?php echo esc_html( ucwords( str_replace( '_', ' ', $key ) ) ); ?>
|
||||
<?php if ( $is_opcache_status ) : ?>
|
||||
<br>
|
||||
<button type="button"
|
||||
class="button button-secondary button-small maplepress-toggle-field"
|
||||
data-target="<?php echo esc_attr( $field_id ); ?>"
|
||||
style="margin-top: 5px;">
|
||||
<span class="dashicons dashicons-visibility" style="vertical-align: middle; font-size: 14px;"></span>
|
||||
<span class="toggle-text">Show</span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ( $is_opcache_status ) : ?>
|
||||
<div id="<?php echo esc_attr( $field_id ); ?>" style="display: none;">
|
||||
<pre><?php echo esc_html( print_r( $value, true ) ); ?></pre>
|
||||
</div>
|
||||
<span class="opcache-hidden-notice" style="color: #666; font-style: italic;">
|
||||
Click "Show" to view opcache details
|
||||
</span>
|
||||
<?php elseif ( is_array( $value ) ) : ?>
|
||||
<pre><?php echo esc_html( print_r( $value, true ) ); ?></pre>
|
||||
<?php elseif ( is_bool( $value ) ) : ?>
|
||||
<?php echo $value ? '<span style="color: green;">✓ Yes</span>' : '<span style="color: red;">✗ No</span>'; ?>
|
||||
<?php else : ?>
|
||||
<?php echo esc_html( $value ); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.maplepress-system-info .system-info-section {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.maplepress-system-info pre {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
background: #f9f9f9;
|
||||
border-left: 3px solid #ccc;
|
||||
overflow-x: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
// Toggle field visibility for opcache_status
|
||||
$('.maplepress-toggle-field').on('click', function() {
|
||||
var button = $(this);
|
||||
var targetId = button.data('target');
|
||||
var content = $('#' + targetId);
|
||||
var notice = button.closest('tr').find('.opcache-hidden-notice');
|
||||
var icon = button.find('.dashicons');
|
||||
var text = button.find('.toggle-text');
|
||||
|
||||
if (content.is(':visible')) {
|
||||
content.slideUp(300);
|
||||
notice.show();
|
||||
icon.removeClass('dashicons-hidden').addClass('dashicons-visibility');
|
||||
text.text('Show');
|
||||
} else {
|
||||
content.slideDown(300);
|
||||
notice.hide();
|
||||
icon.removeClass('dashicons-visibility').addClass('dashicons-hidden');
|
||||
text.text('Hide');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
115
native/wordpress/maplepress-plugin/includes/class-maplepress.php
Normal file
115
native/wordpress/maplepress-plugin/includes/class-maplepress.php
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
/**
|
||||
* The core plugin class.
|
||||
*
|
||||
* @package MaplePress
|
||||
* @subpackage MaplePress/includes
|
||||
*/
|
||||
|
||||
class MaplePress {
|
||||
|
||||
/**
|
||||
* The loader that's responsible for maintaining and registering all hooks.
|
||||
*
|
||||
* @var MaplePress_Loader
|
||||
*/
|
||||
protected $loader;
|
||||
|
||||
/**
|
||||
* The unique identifier of this plugin.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $plugin_name;
|
||||
|
||||
/**
|
||||
* The current version of the plugin.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $version;
|
||||
|
||||
/**
|
||||
* Initialize the class and set its properties.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->version = MAPLEPRESS_VERSION;
|
||||
$this->plugin_name = 'maplepress';
|
||||
|
||||
$this->load_dependencies();
|
||||
$this->define_admin_hooks();
|
||||
$this->define_public_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the required dependencies for this plugin.
|
||||
*/
|
||||
private function load_dependencies() {
|
||||
require_once MAPLEPRESS_PLUGIN_DIR . 'includes/class-maplepress-loader.php';
|
||||
require_once MAPLEPRESS_PLUGIN_DIR . 'includes/class-maplepress-admin.php';
|
||||
require_once MAPLEPRESS_PLUGIN_DIR . 'includes/class-maplepress-public.php';
|
||||
require_once MAPLEPRESS_PLUGIN_DIR . 'includes/class-maplepress-api-client.php';
|
||||
|
||||
$this->loader = new MaplePress_Loader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all hooks related to the admin area functionality.
|
||||
*/
|
||||
private function define_admin_hooks() {
|
||||
$plugin_admin = new MaplePress_Admin( $this->get_plugin_name(), $this->get_version() );
|
||||
|
||||
$this->loader->add_action( 'admin_menu', $plugin_admin, 'add_plugin_admin_menu' );
|
||||
$this->loader->add_action( 'admin_init', $plugin_admin, 'register_settings' );
|
||||
$this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
|
||||
$this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all hooks related to the public-facing functionality.
|
||||
*/
|
||||
private function define_public_hooks() {
|
||||
$plugin_public = new MaplePress_Public( $this->get_plugin_name(), $this->get_version() );
|
||||
|
||||
$this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_styles' );
|
||||
$this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
|
||||
|
||||
// Search integration
|
||||
$this->loader->add_action( 'pre_get_posts', $plugin_public, 'intercept_search' );
|
||||
$this->loader->add_filter( 'get_search_query', $plugin_public, 'restore_search_query' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the loader to execute all hooks.
|
||||
*/
|
||||
public function run() {
|
||||
$this->loader->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the plugin.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_plugin_name() {
|
||||
return $this->plugin_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The reference to the class that orchestrates the hooks.
|
||||
*
|
||||
* @return MaplePress_Loader
|
||||
*/
|
||||
public function get_loader() {
|
||||
return $this->loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the version number of the plugin.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_version() {
|
||||
return $this->version;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
/**
|
||||
* Parallel Executor Class
|
||||
*
|
||||
* Executes search queries in parallel (concurrent requests) to simulate
|
||||
* multiple simultaneous users searching the site.
|
||||
*
|
||||
* @package MaplePress_SearchSpeedTest
|
||||
*/
|
||||
|
||||
class MPSS_Parallel_Executor {
|
||||
|
||||
/**
|
||||
* Execute queries in parallel batches.
|
||||
*
|
||||
* @param array $queries Array of search query strings.
|
||||
* @param int $concurrency Number of concurrent requests per batch.
|
||||
* @return array Results array with timing and metadata.
|
||||
*/
|
||||
public function execute( $queries, $concurrency = 5 ) {
|
||||
$results = array();
|
||||
|
||||
// Split queries into batches based on concurrency
|
||||
$batches = array_chunk( $queries, $concurrency );
|
||||
|
||||
foreach ( $batches as $batch ) {
|
||||
$batch_results = $this->execute_batch( $batch );
|
||||
$results = array_merge( $results, $batch_results );
|
||||
|
||||
// Small delay between batches to prevent server overload
|
||||
usleep( 50000 ); // 50ms
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a batch of queries concurrently using cURL multi-handle.
|
||||
*
|
||||
* @param array $queries Array of query strings for this batch.
|
||||
* @return array Results for this batch.
|
||||
*/
|
||||
private function execute_batch( $queries ) {
|
||||
$results = array();
|
||||
|
||||
// Prepare requests
|
||||
$requests = array();
|
||||
foreach ( $queries as $query ) {
|
||||
$search_url = add_query_arg( 's', urlencode( $query ), home_url( '/' ) );
|
||||
|
||||
$requests[] = array(
|
||||
'url' => $search_url,
|
||||
'query' => $query,
|
||||
);
|
||||
}
|
||||
|
||||
// Execute in parallel
|
||||
$parallel_results = $this->execute_parallel_requests( $requests );
|
||||
|
||||
return $parallel_results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute multiple HTTP requests in parallel using cURL multi-handle.
|
||||
*
|
||||
* @param array $requests Array of request data (url, query).
|
||||
* @return array Results array.
|
||||
*/
|
||||
private function execute_parallel_requests( $requests ) {
|
||||
$results = array();
|
||||
$mh = curl_multi_init();
|
||||
$curl_handles = array();
|
||||
|
||||
// Add all requests to multi-handle
|
||||
foreach ( $requests as $index => $request ) {
|
||||
$ch = curl_init();
|
||||
curl_setopt( $ch, CURLOPT_URL, $request['url'] );
|
||||
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
|
||||
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
|
||||
curl_setopt( $ch, CURLOPT_TIMEOUT, 30 );
|
||||
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false ); // For local testing
|
||||
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false ); // For local testing
|
||||
|
||||
// Add custom headers to identify test traffic (optional)
|
||||
curl_setopt(
|
||||
$ch,
|
||||
CURLOPT_HTTPHEADER,
|
||||
array(
|
||||
'X-Speed-Test: MaplePress',
|
||||
)
|
||||
);
|
||||
|
||||
curl_multi_add_handle( $mh, $ch );
|
||||
|
||||
$curl_handles[ (int) $ch ] = array(
|
||||
'handle' => $ch,
|
||||
'query' => $request['query'],
|
||||
'start' => microtime( true ),
|
||||
);
|
||||
}
|
||||
|
||||
// Execute all requests
|
||||
$running = null;
|
||||
do {
|
||||
curl_multi_exec( $mh, $running );
|
||||
curl_multi_select( $mh );
|
||||
} while ( $running > 0 );
|
||||
|
||||
// Collect results
|
||||
foreach ( $curl_handles as $data ) {
|
||||
$info = curl_getinfo( $data['handle'] );
|
||||
|
||||
// Use cURL's total_time which accurately measures the individual request time
|
||||
// NOT the time from batch start to collection (which would be incorrect)
|
||||
$duration_ms = round( $info['total_time'] * 1000, 2 );
|
||||
|
||||
$results[] = array(
|
||||
'query' => $data['query'],
|
||||
'duration_ms' => $duration_ms,
|
||||
'http_code' => $info['http_code'],
|
||||
'timestamp' => $data['start'],
|
||||
'success' => $info['http_code'] === 200,
|
||||
);
|
||||
|
||||
curl_multi_remove_handle( $mh, $data['handle'] );
|
||||
curl_close( $data['handle'] );
|
||||
}
|
||||
|
||||
curl_multi_close( $mh );
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
<?php
|
||||
/**
|
||||
* Query Generator Class
|
||||
*
|
||||
* Generates realistic search queries based on user behavior patterns.
|
||||
*
|
||||
* @package MaplePress_SearchSpeedTest
|
||||
*/
|
||||
|
||||
class MPSS_Query_Generator {
|
||||
|
||||
/**
|
||||
* Pre-defined realistic search query templates by category.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $query_templates = array(
|
||||
// Navigation queries (30%)
|
||||
'navigation' => array(
|
||||
'contact',
|
||||
'about',
|
||||
'home',
|
||||
'services',
|
||||
'pricing',
|
||||
'support',
|
||||
'login',
|
||||
'register',
|
||||
'cart',
|
||||
'checkout',
|
||||
'account',
|
||||
'profile',
|
||||
'settings',
|
||||
'help',
|
||||
'faq',
|
||||
'terms',
|
||||
'privacy',
|
||||
'policy',
|
||||
'sitemap',
|
||||
'search',
|
||||
),
|
||||
|
||||
// Informational queries (25%)
|
||||
'informational' => array(
|
||||
'how to',
|
||||
'what is',
|
||||
'why does',
|
||||
'when should',
|
||||
'where can',
|
||||
'getting started',
|
||||
'tutorial',
|
||||
'guide',
|
||||
'documentation',
|
||||
'manual',
|
||||
'learn',
|
||||
'course',
|
||||
'training',
|
||||
'video',
|
||||
'webinar',
|
||||
'ebook',
|
||||
'whitepaper',
|
||||
'case study',
|
||||
'best practices',
|
||||
'tips',
|
||||
),
|
||||
|
||||
// Product/Service queries (20%)
|
||||
'product' => array(
|
||||
'wordpress plugin',
|
||||
'theme',
|
||||
'template',
|
||||
'widget',
|
||||
'extension',
|
||||
'free shipping',
|
||||
'discount',
|
||||
'coupon',
|
||||
'promo',
|
||||
'deal',
|
||||
'best seller',
|
||||
'popular',
|
||||
'recommended',
|
||||
'featured',
|
||||
'top rated',
|
||||
'new arrival',
|
||||
'latest',
|
||||
'coming soon',
|
||||
'pre order',
|
||||
'limited',
|
||||
'on sale',
|
||||
'clearance',
|
||||
'bundle',
|
||||
'package',
|
||||
'subscription',
|
||||
),
|
||||
|
||||
// Content discovery queries (15%)
|
||||
'content' => array(
|
||||
'blog',
|
||||
'post',
|
||||
'article',
|
||||
'news',
|
||||
'announcement',
|
||||
'latest',
|
||||
'recent',
|
||||
'new',
|
||||
'updated',
|
||||
'archive',
|
||||
'category',
|
||||
'tag',
|
||||
'topic',
|
||||
'subject',
|
||||
'theme',
|
||||
'author',
|
||||
'contributor',
|
||||
'guest',
|
||||
'interview',
|
||||
'podcast',
|
||||
),
|
||||
|
||||
// Troubleshooting queries (10%)
|
||||
'troubleshooting' => array(
|
||||
'error',
|
||||
'not working',
|
||||
'fix',
|
||||
'repair',
|
||||
'restore',
|
||||
'problem',
|
||||
'issue',
|
||||
'bug',
|
||||
'glitch',
|
||||
'crash',
|
||||
'troubleshoot',
|
||||
'diagnose',
|
||||
'solve',
|
||||
'resolve',
|
||||
'debug',
|
||||
'broken',
|
||||
'missing',
|
||||
'invalid',
|
||||
'failed',
|
||||
'rejected',
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Category weights for distribution.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $category_weights = array(
|
||||
'navigation' => 0.30,
|
||||
'informational' => 0.25,
|
||||
'product' => 0.20,
|
||||
'content' => 0.15,
|
||||
'troubleshooting' => 0.10,
|
||||
);
|
||||
|
||||
/**
|
||||
* Generate query set based on site size profile.
|
||||
*
|
||||
* @param string $profile_key Profile key (tiny, small, medium, big, gigantic).
|
||||
* @param int $count Number of queries to generate.
|
||||
* @return array Array of search query strings.
|
||||
*/
|
||||
public function generate_queries( $profile_key, $count ) {
|
||||
$queries = array();
|
||||
|
||||
// Generate queries from each category based on weight
|
||||
foreach ( $this->category_weights as $category => $weight ) {
|
||||
$category_count = (int) ( $count * $weight );
|
||||
$category_queries = $this->get_random_from_category( $category, $category_count );
|
||||
$queries = array_merge( $queries, $category_queries );
|
||||
}
|
||||
|
||||
// Shuffle to mix categories
|
||||
shuffle( $queries );
|
||||
|
||||
// Add some variations (typos, mixed case, etc) - 20% of queries
|
||||
$queries = $this->add_query_variations( $queries, 0.20 );
|
||||
|
||||
// Ensure we have exactly the requested count
|
||||
return array_slice( $queries, 0, $count );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get random queries from a specific category.
|
||||
*
|
||||
* @param string $category Category name.
|
||||
* @param int $count Number of queries to get.
|
||||
* @return array Array of queries.
|
||||
*/
|
||||
private function get_random_from_category( $category, $count ) {
|
||||
if ( ! isset( $this->query_templates[ $category ] ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$available = $this->query_templates[ $category ];
|
||||
|
||||
// If we need more queries than available, allow duplicates
|
||||
if ( $count > count( $available ) ) {
|
||||
$queries = array();
|
||||
for ( $i = 0; $i < $count; $i++ ) {
|
||||
$queries[] = $available[ array_rand( $available ) ];
|
||||
}
|
||||
return $queries;
|
||||
}
|
||||
|
||||
// Otherwise, shuffle and slice
|
||||
shuffle( $available );
|
||||
return array_slice( $available, 0, $count );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add realistic query variations to the set.
|
||||
*
|
||||
* @param array $queries Base queries.
|
||||
* @param float $variation_ratio Ratio of queries to vary (0.0-1.0).
|
||||
* @return array Queries with variations added.
|
||||
*/
|
||||
private function add_query_variations( $queries, $variation_ratio = 0.20 ) {
|
||||
$with_variations = array();
|
||||
|
||||
foreach ( $queries as $query ) {
|
||||
// Always add original query
|
||||
$with_variations[] = $query;
|
||||
|
||||
// Randomly add variations based on ratio
|
||||
if ( mt_rand( 1, 100 ) <= ( $variation_ratio * 100 ) ) {
|
||||
$variant = $this->create_variation( $query );
|
||||
if ( $variant !== $query ) {
|
||||
$with_variations[] = $variant;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $with_variations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a variation of a query (case changes, partial queries, suffixes).
|
||||
*
|
||||
* @param string $query Original query.
|
||||
* @return string Variation of the query.
|
||||
*/
|
||||
private function create_variation( $query ) {
|
||||
$rand = mt_rand( 1, 5 );
|
||||
|
||||
switch ( $rand ) {
|
||||
case 1:
|
||||
// All uppercase
|
||||
return strtoupper( $query );
|
||||
|
||||
case 2:
|
||||
// Title case
|
||||
return ucwords( $query );
|
||||
|
||||
case 3:
|
||||
// Partial query (first word only)
|
||||
$words = explode( ' ', $query );
|
||||
return $words[0];
|
||||
|
||||
case 4:
|
||||
// Add common suffix
|
||||
$suffixes = array( ' guide', ' help', ' info', ' page', ' wordpress' );
|
||||
return $query . $suffixes[ array_rand( $suffixes ) ];
|
||||
|
||||
case 5:
|
||||
// Mixed case (simulate typo)
|
||||
$chars = str_split( $query );
|
||||
$result = '';
|
||||
foreach ( $chars as $char ) {
|
||||
$result .= ( mt_rand( 0, 1 ) === 1 ) ? strtoupper( $char ) : strtolower( $char );
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
<?php
|
||||
/**
|
||||
* Results Analyzer Class
|
||||
*
|
||||
* Analyzes speed test results and generates recommendations.
|
||||
*
|
||||
* @package MaplePress_SearchSpeedTest
|
||||
*/
|
||||
|
||||
class MPSS_Results_Analyzer {
|
||||
|
||||
/**
|
||||
* Analyze speed test results.
|
||||
*
|
||||
* @param array $all_results All profile results.
|
||||
* @return array Analyzed results with summary and recommendations.
|
||||
*/
|
||||
public function analyze( $all_results ) {
|
||||
$summary = array();
|
||||
|
||||
foreach ( $all_results as $profile_key => $data ) {
|
||||
$times = array_column( $data['results'], 'duration_ms' );
|
||||
|
||||
if ( empty( $times ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$avg_ms = array_sum( $times ) / count( $times );
|
||||
|
||||
$summary[ $profile_key ] = array(
|
||||
'profile_name' => $data['profile']['name'],
|
||||
'query_count' => count( $data['results'] ),
|
||||
'avg_ms' => round( $avg_ms, 2 ),
|
||||
'min_ms' => round( min( $times ), 2 ),
|
||||
'max_ms' => round( max( $times ), 2 ),
|
||||
'median_ms' => $this->median( $times ),
|
||||
'p95_ms' => $this->percentile( $times, 95 ),
|
||||
'p99_ms' => $this->percentile( $times, 99 ),
|
||||
'status' => $this->get_status( $avg_ms ),
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'summary' => $summary,
|
||||
'recommendations' => $this->generate_recommendations( $summary ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate median of an array.
|
||||
*
|
||||
* @param array $array Numeric array.
|
||||
* @return float Median value.
|
||||
*/
|
||||
private function median( $array ) {
|
||||
sort( $array );
|
||||
$count = count( $array );
|
||||
$middle = floor( $count / 2 );
|
||||
|
||||
if ( $count % 2 === 0 ) {
|
||||
return round( ( $array[ $middle - 1 ] + $array[ $middle ] ) / 2, 2 );
|
||||
}
|
||||
|
||||
return round( $array[ $middle ], 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate percentile of an array.
|
||||
*
|
||||
* @param array $array Numeric array.
|
||||
* @param int $percentile Percentile to calculate (e.g., 95 for P95).
|
||||
* @return float Percentile value.
|
||||
*/
|
||||
private function percentile( $array, $percentile ) {
|
||||
sort( $array );
|
||||
$index = ceil( ( $percentile / 100 ) * count( $array ) ) - 1;
|
||||
$index = max( 0, $index );
|
||||
return round( $array[ $index ], 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get performance status based on average response time.
|
||||
*
|
||||
* @param float $avg_ms Average response time in milliseconds.
|
||||
* @return string Status (excellent, good, fair, poor, critical).
|
||||
*/
|
||||
private function get_status( $avg_ms ) {
|
||||
if ( $avg_ms < 50 ) {
|
||||
return 'excellent';
|
||||
} elseif ( $avg_ms < 150 ) {
|
||||
return 'good';
|
||||
} elseif ( $avg_ms < 500 ) {
|
||||
return 'fair';
|
||||
} elseif ( $avg_ms < 1000 ) {
|
||||
return 'poor';
|
||||
} else {
|
||||
return 'critical';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current site information.
|
||||
*
|
||||
* @return array Site information.
|
||||
*/
|
||||
private function get_site_info() {
|
||||
$post_count = wp_count_posts( 'post' );
|
||||
$page_count = wp_count_posts( 'page' );
|
||||
|
||||
$published_posts = isset( $post_count->publish ) ? $post_count->publish : 0;
|
||||
$published_pages = isset( $page_count->publish ) ? $page_count->publish : 0;
|
||||
|
||||
$total_content = $published_posts + $published_pages;
|
||||
|
||||
// Determine profile
|
||||
if ( $total_content < 50 ) {
|
||||
$profile = 'tiny';
|
||||
} elseif ( $total_content < 500 ) {
|
||||
$profile = 'small';
|
||||
} elseif ( $total_content < 5000 ) {
|
||||
$profile = 'medium';
|
||||
} elseif ( $total_content < 50000 ) {
|
||||
$profile = 'big';
|
||||
} else {
|
||||
$profile = 'gigantic';
|
||||
}
|
||||
|
||||
return array(
|
||||
'posts' => $published_posts,
|
||||
'pages' => $published_pages,
|
||||
'total_content' => $total_content,
|
||||
'profile' => $profile,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate actionable recommendations based on results.
|
||||
*
|
||||
* @param array $summary Profile summaries.
|
||||
* @return array Recommendations array.
|
||||
*/
|
||||
private function generate_recommendations( $summary ) {
|
||||
$recommendations = array();
|
||||
|
||||
// Get the actual test results (could be 'custom' or any profile key)
|
||||
$test_result = reset( $summary );
|
||||
if ( ! $test_result ) {
|
||||
return $recommendations;
|
||||
}
|
||||
|
||||
$avg_ms = $test_result['avg_ms'];
|
||||
|
||||
// Performance-based recommendations
|
||||
if ( $avg_ms < 50 ) {
|
||||
$recommendations[] = array(
|
||||
'level' => 'success',
|
||||
'title' => __( 'Excellent Performance', 'maplepress-searchspeedtest' ),
|
||||
'message' => sprintf(
|
||||
/* translators: %s: average response time */
|
||||
__( 'Average response time of %.2f ms is excellent! Your search is performing very well.', 'maplepress-searchspeedtest' ),
|
||||
$avg_ms
|
||||
),
|
||||
);
|
||||
} elseif ( $avg_ms < 150 ) {
|
||||
$recommendations[] = array(
|
||||
'level' => 'success',
|
||||
'title' => __( 'Good Performance', 'maplepress-searchspeedtest' ),
|
||||
'message' => sprintf(
|
||||
/* translators: %s: average response time */
|
||||
__( 'Average response time of %.2f ms is good. Your search is performing well.', 'maplepress-searchspeedtest' ),
|
||||
$avg_ms
|
||||
),
|
||||
);
|
||||
} elseif ( $avg_ms < 500 ) {
|
||||
$recommendations[] = array(
|
||||
'level' => 'warning',
|
||||
'title' => __( 'Fair Performance - Room for Improvement', 'maplepress-searchspeedtest' ),
|
||||
'message' => sprintf(
|
||||
/* translators: %s: average response time */
|
||||
__( 'Average response time of %.2f ms is acceptable but could be improved. Consider implementing search caching or optimizing your database queries.', 'maplepress-searchspeedtest' ),
|
||||
$avg_ms
|
||||
),
|
||||
);
|
||||
} elseif ( $avg_ms < 1000 ) {
|
||||
$recommendations[] = array(
|
||||
'level' => 'error',
|
||||
'title' => __( 'Poor Performance', 'maplepress-searchspeedtest' ),
|
||||
'message' => sprintf(
|
||||
/* translators: %s: average response time */
|
||||
__( 'Average response time of %.2f ms indicates performance issues. Consider database optimization, adding indexes, or using a dedicated search solution.', 'maplepress-searchspeedtest' ),
|
||||
$avg_ms
|
||||
),
|
||||
);
|
||||
} else {
|
||||
$recommendations[] = array(
|
||||
'level' => 'critical',
|
||||
'title' => __( 'Critical: Very Slow Performance', 'maplepress-searchspeedtest' ),
|
||||
'message' => sprintf(
|
||||
/* translators: %s: average response time */
|
||||
__( 'Average response time of %.2f ms is critically slow. Your database may need optimization, or you should consider a cloud-based search solution like MaplePress.', 'maplepress-searchspeedtest' ),
|
||||
$avg_ms
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Add database optimization tip if showing slowness
|
||||
if ( $avg_ms > 200 ) {
|
||||
$recommendations[] = array(
|
||||
'level' => 'info',
|
||||
'title' => __( 'Database Optimization Tip', 'maplepress-searchspeedtest' ),
|
||||
'message' => __( 'Consider adding database indexes on post_title and post_content columns, implementing search result caching, or using a cloud-based search solution like MaplePress for better performance.', 'maplepress-searchspeedtest' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Add general optimization tips
|
||||
$recommendations[] = array(
|
||||
'level' => 'info',
|
||||
'title' => __( 'Optimization Tips', 'maplepress-searchspeedtest' ),
|
||||
'message' => __( 'Consider: 1) Implementing search result caching, 2) Adding database indexes on post_title and post_content, 3) Using a CDN, 4) Upgrading server resources, 5) Trying MaplePress for cloud-powered search.', 'maplepress-searchspeedtest' ),
|
||||
);
|
||||
|
||||
return $recommendations;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
/**
|
||||
* Serial Executor Class
|
||||
*
|
||||
* Executes search queries sequentially (one after another) via HTTP requests.
|
||||
* This ensures all WordPress hooks (including MaplePress search intercept) are triggered.
|
||||
*
|
||||
* @package MaplePress_SearchSpeedTest
|
||||
*/
|
||||
|
||||
class MPSS_Serial_Executor {
|
||||
|
||||
/**
|
||||
* Execute queries serially (one at a time) using WP_Query directly.
|
||||
*
|
||||
* @param array $queries Array of search query strings.
|
||||
* @return array Results array with timing and metadata.
|
||||
*/
|
||||
public function execute( $queries ) {
|
||||
$results = array();
|
||||
|
||||
foreach ( $queries as $index => $query ) {
|
||||
// Start timing
|
||||
$start_time = microtime( true );
|
||||
|
||||
// Execute WordPress search directly using WP_Query
|
||||
$search_query = new WP_Query(
|
||||
array(
|
||||
's' => $query,
|
||||
'post_type' => 'any',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => 10,
|
||||
)
|
||||
);
|
||||
|
||||
// End timing
|
||||
$end_time = microtime( true );
|
||||
$duration_ms = ( $end_time - $start_time ) * 1000;
|
||||
|
||||
$results[] = array(
|
||||
'query' => $query,
|
||||
'duration_ms' => round( $duration_ms, 2 ),
|
||||
'result_count' => $search_query->found_posts,
|
||||
'timestamp' => $start_time,
|
||||
'success' => true,
|
||||
);
|
||||
|
||||
// Reset post data
|
||||
wp_reset_postdata();
|
||||
|
||||
// Small delay to prevent overwhelming the database (10ms)
|
||||
usleep( 10000 );
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
<?php
|
||||
/**
|
||||
* Simple Speed Test Class
|
||||
*
|
||||
* Just runs queries and times them. No complexity.
|
||||
*
|
||||
* @package MaplePress_SearchSpeedTest
|
||||
*/
|
||||
|
||||
class MPSS_SpeedTest_Simple {
|
||||
|
||||
/**
|
||||
* Run speed test with specified number of queries.
|
||||
*
|
||||
* @param int $query_count Number of queries to run.
|
||||
* @param string $execution_mode Execution mode: 'serial' or 'parallel'.
|
||||
* @return array Results with timing data.
|
||||
*/
|
||||
public function run( $query_count = 10, $execution_mode = 'serial' ) {
|
||||
$start_time = microtime( true );
|
||||
|
||||
// Debug logging
|
||||
error_log( 'MPSS_SpeedTest_Simple::run() called with mode: ' . $execution_mode );
|
||||
|
||||
// Generate search queries
|
||||
$queries = $this->generate_queries( $query_count );
|
||||
|
||||
// Execute based on mode
|
||||
if ( $execution_mode === 'parallel' ) {
|
||||
error_log( 'MPSS: Executing in PARALLEL mode' );
|
||||
$results = $this->run_parallel( $queries );
|
||||
} else {
|
||||
error_log( 'MPSS: Executing in SERIAL mode' );
|
||||
$results = $this->run_serial( $queries );
|
||||
}
|
||||
|
||||
$end_time = microtime( true );
|
||||
$total_time = $end_time - $start_time;
|
||||
|
||||
// Calculate statistics
|
||||
$times = array_column( $results, 'duration_ms' );
|
||||
$avg_ms = array_sum( $times ) / count( $times );
|
||||
$min_ms = min( $times );
|
||||
$max_ms = max( $times );
|
||||
|
||||
return array(
|
||||
'results' => $results,
|
||||
'total_time' => round( $total_time, 2 ),
|
||||
'total_queries' => count( $results ),
|
||||
'avg_ms' => round( $avg_ms, 2 ),
|
||||
'min_ms' => round( $min_ms, 2 ),
|
||||
'max_ms' => round( $max_ms, 2 ),
|
||||
'mode' => $execution_mode,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run queries in serial mode (one at a time).
|
||||
*
|
||||
* @param array $queries Array of search query strings.
|
||||
* @return array Results array.
|
||||
*/
|
||||
private function run_serial( $queries ) {
|
||||
$results = array();
|
||||
|
||||
foreach ( $queries as $query ) {
|
||||
$query_start = microtime( true );
|
||||
|
||||
// Make HTTP request to search URL to properly trigger MaplePress hooks
|
||||
$search_url = home_url( '/?s=' . urlencode( $query ) );
|
||||
$response = wp_remote_get(
|
||||
$search_url,
|
||||
array(
|
||||
'timeout' => 30,
|
||||
'headers' => array(
|
||||
'X-MaplePress-Test' => '1',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$query_end = microtime( true );
|
||||
$duration_ms = ( $query_end - $query_start ) * 1000;
|
||||
|
||||
// Extract result count from response - try multiple patterns
|
||||
$result_count = 0;
|
||||
if ( ! is_wp_error( $response ) && wp_remote_retrieve_response_code( $response ) === 200 ) {
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
|
||||
// Try various patterns to find result count
|
||||
$patterns = array(
|
||||
'/(\d+)\s+results?/i', // "5 results" or "1 result"
|
||||
'/found\s+(\d+)/i', // "Found 5"
|
||||
'/showing\s+(\d+)/i', // "Showing 5"
|
||||
'/<article/i', // Count article tags
|
||||
'/<div[^>]*class="[^"]*post[^"]*"/i', // Count post divs
|
||||
);
|
||||
|
||||
foreach ( $patterns as $pattern ) {
|
||||
if ( $pattern === '/<article/i' || strpos( $pattern, '<div' ) === 0 ) {
|
||||
// Count HTML elements
|
||||
$count = preg_match_all( $pattern, $body );
|
||||
if ( $count > 0 ) {
|
||||
$result_count = $count;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Extract number from text
|
||||
if ( preg_match( $pattern, $body, $matches ) ) {
|
||||
$result_count = intval( $matches[1] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$results[] = array(
|
||||
'query' => $query,
|
||||
'duration_ms' => round( $duration_ms, 2 ),
|
||||
'result_count' => $result_count,
|
||||
);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run queries in parallel mode (multiple concurrent requests).
|
||||
*
|
||||
* @param array $queries Array of search query strings.
|
||||
* @return array Results array.
|
||||
*/
|
||||
private function run_parallel( $queries ) {
|
||||
error_log( 'MPSS: run_parallel called with ' . count( $queries ) . ' queries' );
|
||||
|
||||
$results = array();
|
||||
|
||||
// Build search URLs
|
||||
$search_urls = array();
|
||||
foreach ( $queries as $query ) {
|
||||
$search_urls[] = array(
|
||||
'url' => home_url( '/?s=' . urlencode( $query ) ),
|
||||
'query' => $query,
|
||||
);
|
||||
}
|
||||
|
||||
error_log( 'MPSS: Built ' . count( $search_urls ) . ' search URLs' );
|
||||
|
||||
// Initialize cURL multi handle
|
||||
$mh = curl_multi_init();
|
||||
$curl_handles = array();
|
||||
$request_info = array();
|
||||
|
||||
// Add all requests to multi handle
|
||||
foreach ( $search_urls as $index => $search_data ) {
|
||||
$ch = curl_init();
|
||||
curl_setopt( $ch, CURLOPT_URL, $search_data['url'] );
|
||||
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
|
||||
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
|
||||
curl_setopt( $ch, CURLOPT_TIMEOUT, 30 );
|
||||
curl_setopt( $ch, CURLOPT_HTTPHEADER, array(
|
||||
'X-MaplePress-Test: 1',
|
||||
) );
|
||||
|
||||
curl_multi_add_handle( $mh, $ch );
|
||||
$ch_id = (int) $ch;
|
||||
$curl_handles[ $ch_id ] = $ch;
|
||||
$request_info[ $ch_id ] = array(
|
||||
'query' => $search_data['query'],
|
||||
'index' => $index,
|
||||
'start_time' => null,
|
||||
'end_time' => null,
|
||||
);
|
||||
}
|
||||
|
||||
error_log( 'MPSS: Added ' . count( $curl_handles ) . ' handles, request_info has ' . count( $request_info ) . ' entries' );
|
||||
|
||||
// Execute all queries simultaneously and track start/end times
|
||||
$running = null;
|
||||
|
||||
// Record start time for ALL requests (they all start together)
|
||||
$batch_start = microtime( true );
|
||||
foreach ( $request_info as $ch_id => $info ) {
|
||||
$request_info[ $ch_id ]['start_time'] = $batch_start;
|
||||
}
|
||||
|
||||
// Start executing - all requests run concurrently
|
||||
do {
|
||||
curl_multi_exec( $mh, $running );
|
||||
|
||||
// Check for completed requests and record their end time
|
||||
while ( $done = curl_multi_info_read( $mh ) ) {
|
||||
if ( $done['msg'] == CURLMSG_DONE ) {
|
||||
$ch_id = (int) $done['handle'];
|
||||
// Record when THIS specific request finished
|
||||
if ( ! isset( $request_info[ $ch_id ]['end_time'] ) ) {
|
||||
$request_info[ $ch_id ]['end_time'] = microtime( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $running > 0 ) {
|
||||
curl_multi_select( $mh );
|
||||
}
|
||||
} while ( $running > 0 );
|
||||
|
||||
$batch_end = microtime( true );
|
||||
$batch_duration_ms = ( $batch_end - $batch_start ) * 1000;
|
||||
|
||||
error_log( 'MPSS: Batch completed in ' . round( $batch_duration_ms, 2 ) . 'ms, processing ' . count( $request_info ) . ' results' );
|
||||
|
||||
// Collect results - calculate duration from start/end times
|
||||
foreach ( $request_info as $ch_id => $info ) {
|
||||
$ch = $curl_handles[ $ch_id ];
|
||||
|
||||
// Calculate duration from start to end time
|
||||
if ( isset( $info['start_time'] ) && isset( $info['end_time'] ) ) {
|
||||
$duration_seconds = $info['end_time'] - $info['start_time'];
|
||||
$duration_ms = $duration_seconds * 1000;
|
||||
|
||||
// Debug: log a few samples
|
||||
static $debug_count = 0;
|
||||
if ( $debug_count < 3 ) {
|
||||
error_log( sprintf(
|
||||
'MPSS: Sample #%d - start=%.6f, end=%.6f, duration_sec=%.6f, duration_ms=%.2f',
|
||||
$debug_count,
|
||||
$info['start_time'],
|
||||
$info['end_time'],
|
||||
$duration_seconds,
|
||||
$duration_ms
|
||||
) );
|
||||
$debug_count++;
|
||||
}
|
||||
} else {
|
||||
// Fallback - shouldn't happen
|
||||
$duration_ms = 0;
|
||||
}
|
||||
|
||||
$curl_info = curl_getinfo( $ch );
|
||||
$response = curl_multi_getcontent( $ch );
|
||||
$http_code = $curl_info['http_code'];
|
||||
|
||||
// Extract result count using multiple patterns
|
||||
$result_count = 0;
|
||||
if ( $http_code === 200 && ! empty( $response ) ) {
|
||||
$patterns = array(
|
||||
'/(\d+)\s+results?/i',
|
||||
'/found\s+(\d+)/i',
|
||||
'/showing\s+(\d+)/i',
|
||||
'/<article/i',
|
||||
'/<div[^>]*class="[^"]*post[^"]*"/i',
|
||||
);
|
||||
|
||||
foreach ( $patterns as $pattern ) {
|
||||
if ( $pattern === '/<article/i' || strpos( $pattern, '<div' ) === 0 ) {
|
||||
$count = preg_match_all( $pattern, $response );
|
||||
if ( $count > 0 ) {
|
||||
$result_count = $count;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ( preg_match( $pattern, $response, $matches ) ) {
|
||||
$result_count = intval( $matches[1] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$results[ $info['index'] ] = array(
|
||||
'query' => $info['query'],
|
||||
'duration_ms' => round( $duration_ms, 2 ),
|
||||
'result_count' => $result_count,
|
||||
);
|
||||
|
||||
curl_multi_remove_handle( $mh, $ch );
|
||||
curl_close( $ch );
|
||||
}
|
||||
|
||||
curl_multi_close( $mh );
|
||||
|
||||
// Sort results by original index to maintain query order
|
||||
ksort( $results );
|
||||
|
||||
return array_values( $results );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate random search queries from existing content.
|
||||
*
|
||||
* @param int $count Number of queries to generate.
|
||||
* @return array Array of search query strings.
|
||||
*/
|
||||
private function generate_queries( $count ) {
|
||||
error_log( 'MPSS: generate_queries called with count=' . $count );
|
||||
|
||||
$posts = get_posts(
|
||||
array(
|
||||
'post_type' => array( 'post', 'page' ),
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => $count * 3,
|
||||
'orderby' => 'rand',
|
||||
)
|
||||
);
|
||||
|
||||
error_log( 'MPSS: get_posts returned ' . count( $posts ) . ' posts' );
|
||||
|
||||
$queries = array();
|
||||
|
||||
foreach ( $posts as $post ) {
|
||||
if ( count( $queries ) >= $count ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Get words from title
|
||||
$words = array_filter( explode( ' ', $post->post_title ) );
|
||||
|
||||
if ( empty( $words ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 50% single word, 50% two words
|
||||
if ( mt_rand( 1, 2 ) === 1 || count( $words ) === 1 ) {
|
||||
$queries[] = $words[ array_rand( $words ) ];
|
||||
} else {
|
||||
$start = mt_rand( 0, count( $words ) - 2 );
|
||||
$queries[] = $words[ $start ] . ' ' . $words[ $start + 1 ];
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have enough, pad with generic searches
|
||||
while ( count( $queries ) < $count ) {
|
||||
$queries[] = 'test';
|
||||
}
|
||||
|
||||
$final_queries = array_slice( $queries, 0, $count );
|
||||
error_log( 'MPSS: generate_queries returning ' . count( $final_queries ) . ' queries' );
|
||||
|
||||
return $final_queries;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue