Make your WordPress site irresistible. Natural SEO attraction with: - robots.txt management - sitemap.xml generation - LLMs.txt support - Google integration (Analytics, Search Console, Tag Manager) - Schema.org structured data - Open Graph / Twitter Card meta tags - AMP support - Visual elements gallery - Built-in backup/restore module Includes build.sh and .distignore for WordPress-installable release ZIPs.
332 lines
12 KiB
PHP
332 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* AMP (Accelerated Mobile Pages) Module
|
|
*
|
|
* Handles AMP page generation and Signed Exchange (SXG) support
|
|
*
|
|
* @package TigerStyle_SEO
|
|
* @subpackage Modules
|
|
* @since 2.1.0
|
|
*/
|
|
|
|
// Prevent direct access
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
class TigerStyleSEO_AMP {
|
|
|
|
private $options;
|
|
private $cache_dir;
|
|
private $sxg_enabled;
|
|
|
|
/**
|
|
* Single instance
|
|
*/
|
|
private static $instance = null;
|
|
|
|
/**
|
|
* Get instance
|
|
*/
|
|
public static function instance() {
|
|
if (is_null(self::$instance)) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
private function __construct() {
|
|
$this->options = get_option('tigerstyle_heat_amp', array());
|
|
$this->cache_dir = WP_CONTENT_DIR . '/cache/tigerstyle-heat-amp/';
|
|
$this->sxg_enabled = isset($this->options['sxg_enabled']) ? $this->options['sxg_enabled'] : false;
|
|
|
|
$this->init();
|
|
}
|
|
|
|
/**
|
|
* Initialize the module
|
|
*/
|
|
private function init() {
|
|
// Create cache directory
|
|
if (!file_exists($this->cache_dir)) {
|
|
wp_mkdir_p($this->cache_dir);
|
|
}
|
|
|
|
// AMP detection and generation
|
|
add_action('template_redirect', array($this, 'handle_amp_request'));
|
|
add_action('wp_head', array($this, 'add_amp_link'));
|
|
|
|
// SXG support
|
|
if ($this->sxg_enabled) {
|
|
add_action('template_redirect', array($this, 'handle_sxg_request'), 5);
|
|
add_filter('wp_headers', array($this, 'add_sxg_headers'));
|
|
}
|
|
|
|
// Admin hooks
|
|
if (is_admin()) {
|
|
add_action('admin_post_update_amp_settings', array($this, 'handle_form_submission'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle AMP requests
|
|
*/
|
|
public function handle_amp_request() {
|
|
if (!isset($_GET['amp']) || is_admin()) {
|
|
return;
|
|
}
|
|
|
|
// Generate AMP page
|
|
$this->generate_amp_page();
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Add AMP link to head
|
|
*/
|
|
public function add_amp_link() {
|
|
if (is_singular() && !is_admin()) {
|
|
$amp_url = add_query_arg('amp', '1', get_permalink());
|
|
echo '<link rel="amphtml" href="' . esc_url($amp_url) . '">' . "\n";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate AMP page
|
|
*/
|
|
private function generate_amp_page() {
|
|
// Basic AMP page structure
|
|
?>
|
|
<!doctype html>
|
|
<html amp lang="<?php echo get_locale(); ?>">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
|
|
<title><?php wp_title(); ?></title>
|
|
<script async src="https://cdn.ampproject.org/v0.js"></script>
|
|
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
|
|
<style amp-custom>
|
|
body { font-family: sans-serif; margin: 20px; }
|
|
h1 { color: #333; }
|
|
p { line-height: 1.6; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1><?php the_title(); ?></h1>
|
|
<div class="content">
|
|
<?php
|
|
if (have_posts()) {
|
|
while (have_posts()) {
|
|
the_post();
|
|
the_content();
|
|
}
|
|
}
|
|
?>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Handle SXG requests
|
|
*/
|
|
public function handle_sxg_request() {
|
|
if (!isset($_GET['sxg']) || !$this->sxg_enabled) {
|
|
return;
|
|
}
|
|
|
|
// Check if SXG service is available
|
|
if (!$this->is_sxg_service_available()) {
|
|
wp_die('SXG service not available', 'Service Unavailable', ['response' => 503]);
|
|
}
|
|
|
|
$this->serve_signed_exchange();
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Check if SXG service is available
|
|
*/
|
|
private function is_sxg_service_available() {
|
|
return !empty($this->options['sxg_api_key']) && !empty($this->options['sxg_api_endpoint']);
|
|
}
|
|
|
|
/**
|
|
* Serve Signed Exchange
|
|
*/
|
|
public function serve_signed_exchange() {
|
|
$current_url = $this->get_current_url();
|
|
|
|
// Check cache first
|
|
$cache_key = 'sxg_' . md5($current_url);
|
|
$cached_sxg = get_transient($cache_key);
|
|
|
|
if ($cached_sxg !== false) {
|
|
header('Content-Type: application/signed-exchange;v=b3');
|
|
header('Cache-Control: public, max-age=300');
|
|
echo $cached_sxg;
|
|
return;
|
|
}
|
|
|
|
// Generate fresh SXG
|
|
ob_start();
|
|
$this->generate_amp_page();
|
|
$amp_content = ob_get_clean();
|
|
|
|
$sxg_data = $this->create_signed_exchange($amp_content, $current_url);
|
|
|
|
if ($sxg_data) {
|
|
// Cache for 5 minutes
|
|
set_transient($cache_key, $sxg_data, 300);
|
|
|
|
header('Content-Type: application/signed-exchange;v=b3');
|
|
header('Cache-Control: public, max-age=300');
|
|
echo $sxg_data;
|
|
} else {
|
|
wp_die('Failed to create signed exchange', 'SXG Error', ['response' => 500]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create signed exchange using API
|
|
*/
|
|
private function create_signed_exchange($content, $url) {
|
|
$api_endpoint = $this->options['sxg_api_endpoint'];
|
|
$api_key = $this->options['sxg_api_key'];
|
|
|
|
$response = wp_remote_post($api_endpoint, array(
|
|
'headers' => array(
|
|
'Authorization' => 'Bearer ' . $api_key,
|
|
'Content-Type' => 'application/json'
|
|
),
|
|
'body' => json_encode(array(
|
|
'url' => $url,
|
|
'content' => $content,
|
|
'headers' => array(
|
|
'content-type' => 'text/html; charset=utf-8'
|
|
)
|
|
)),
|
|
'timeout' => 30
|
|
));
|
|
|
|
if (is_wp_error($response)) {
|
|
error_log('TigerStyle Heat: SXG API error: ' . $response->get_error_message());
|
|
return false;
|
|
}
|
|
|
|
$body = wp_remote_retrieve_body($response);
|
|
$data = json_decode($body, true);
|
|
|
|
if (isset($data['sxg_package'])) {
|
|
return base64_decode($data['sxg_package']);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get current URL
|
|
*/
|
|
private function get_current_url() {
|
|
return (is_ssl() ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
|
}
|
|
|
|
/**
|
|
* Add SXG headers
|
|
*/
|
|
public function add_sxg_headers($headers) {
|
|
if ($this->sxg_enabled && isset($_GET['amp'])) {
|
|
$headers['Link'] = '</wp-content/cache/tigerstyle-heat-amp/sxg-cert.pem>; rel="alternate"; type="application/cert-chain+cbor"';
|
|
$headers['Vary'] = 'Accept, AMP-Cache-Transform';
|
|
}
|
|
|
|
return $headers;
|
|
}
|
|
|
|
/**
|
|
* Handle form submission
|
|
*/
|
|
public function handle_form_submission() {
|
|
if (!isset($_POST['amp_nonce']) || !wp_verify_nonce($_POST['amp_nonce'], 'update_amp_settings')) {
|
|
wp_die('Security check failed');
|
|
}
|
|
|
|
$options = array();
|
|
$options['sxg_enabled'] = isset($_POST['sxg_enabled']) ? 1 : 0;
|
|
$options['sxg_api_endpoint'] = sanitize_url($_POST['sxg_api_endpoint']);
|
|
$options['sxg_api_key'] = sanitize_text_field($_POST['sxg_api_key']);
|
|
|
|
update_option('tigerstyle_heat_amp', $options);
|
|
|
|
wp_redirect(admin_url('admin.php?page=tigerstyle-heat#amp-tab&updated=1'));
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Render admin page
|
|
*/
|
|
public function render_admin_page() {
|
|
$options = $this->options;
|
|
?>
|
|
<div class="seo-info-box">
|
|
<h3><?php _e('AMP & SXG Configuration', 'tigerstyle-heat'); ?></h3>
|
|
<p class="description">
|
|
<?php _e('Configure AMP (Accelerated Mobile Pages) and SXG (Signed Exchange) support for faster mobile loading.', 'tigerstyle-heat'); ?>
|
|
</p>
|
|
|
|
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
|
|
<input type="hidden" name="action" value="update_amp_settings">
|
|
<?php wp_nonce_field('update_amp_settings', 'amp_nonce'); ?>
|
|
|
|
<table class="form-table">
|
|
<tr>
|
|
<th scope="row"><?php _e('Enable SXG Support', 'tigerstyle-heat'); ?></th>
|
|
<td>
|
|
<label>
|
|
<input type="checkbox" name="sxg_enabled" value="1" <?php checked(isset($options['sxg_enabled']) ? $options['sxg_enabled'] : 0, 1); ?>>
|
|
<?php _e('Enable Signed Exchange support for AMP pages', 'tigerstyle-heat'); ?>
|
|
</label>
|
|
<p class="description"><?php _e('Requires valid SXG API credentials.', 'tigerstyle-heat'); ?></p>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><?php _e('SXG API Endpoint', 'tigerstyle-heat'); ?></th>
|
|
<td>
|
|
<input type="url" name="sxg_api_endpoint" value="<?php echo esc_attr(isset($options['sxg_api_endpoint']) ? $options['sxg_api_endpoint'] : ''); ?>" class="regular-text">
|
|
<p class="description"><?php _e('SXG API service endpoint URL.', 'tigerstyle-heat'); ?></p>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row"><?php _e('SXG API Key', 'tigerstyle-heat'); ?></th>
|
|
<td>
|
|
<input type="password" name="sxg_api_key" value="<?php echo esc_attr(isset($options['sxg_api_key']) ? $options['sxg_api_key'] : ''); ?>" class="regular-text">
|
|
<p class="description"><?php _e('API key for SXG service authentication.', 'tigerstyle-heat'); ?></p>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p class="submit">
|
|
<input type="submit" name="submit" class="button button-primary" value="<?php _e('Save AMP Settings', 'tigerstyle-heat'); ?>">
|
|
</p>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="seo-info-box">
|
|
<h4><?php _e('AMP Status', 'tigerstyle-heat'); ?></h4>
|
|
<p>
|
|
<?php _e('AMP pages are automatically generated for all posts and pages.', 'tigerstyle-heat'); ?>
|
|
<?php if (is_singular()): ?>
|
|
<br><strong><?php _e('Current page AMP URL:', 'tigerstyle-heat'); ?></strong>
|
|
<a href="<?php echo add_query_arg('amp', '1', get_permalink()); ?>" target="_blank">
|
|
<?php echo add_query_arg('amp', '1', get_permalink()); ?>
|
|
</a>
|
|
<?php endif; ?>
|
|
</p>
|
|
</div>
|
|
<?php
|
|
}
|
|
}
|