Ryan Malloy 0028738e33 Initial commit: TigerStyle Heat v2.0.0
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.
2026-05-27 13:41:35 -06:00

485 lines
21 KiB
JavaScript

/**
* TigerStyle Heat Admin JavaScript
*/
// Tab switching functionality - Available immediately
window.switchTab = function(evt, tabName) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tab-content");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].classList.remove("active");
}
tablinks = document.getElementsByClassName("nav-tab");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].classList.remove("nav-tab-active");
}
document.getElementById(tabName).classList.add("active");
evt.currentTarget.classList.add("nav-tab-active");
};
jQuery(document).ready(function($) {
// SEO Health Checker functionality
window.runSEOHealthCheck = function() {
const button = document.getElementById('seo-health-check-btn');
if (!button) return;
const originalText = button.textContent;
// Update button state
button.textContent = tigerstyleSEO.strings.runningAnalysis;
button.disabled = true;
// Show loading indicator
const loadingDiv = document.createElement('div');
loadingDiv.id = 'seo-loading';
loadingDiv.innerHTML = '<div style="text-align: center; padding: 20px;"><div class="spinner is-active" style="float: none; margin: 0 auto;"></div><p>Analyzing SEO health...</p></div>';
const resultsContainer = document.getElementById('seo-health-results');
if (resultsContainer) {
resultsContainer.innerHTML = '';
resultsContainer.appendChild(loadingDiv);
}
// Make AJAX request
$.ajax({
url: tigerstyleSEO.ajaxurl,
type: 'POST',
data: {
action: 'seo_health_check',
nonce: tigerstyleSEO.nonce
},
success: function(response) {
button.textContent = originalText;
button.disabled = false;
if (response.success && resultsContainer) {
displaySEOResults(response.data);
} else {
showError(tigerstyleSEO.strings.analysisFailed);
}
},
error: function() {
button.textContent = originalText;
button.disabled = false;
showError(tigerstyleSEO.strings.networkError);
}
});
};
function displaySEOResults(data) {
const resultsContainer = document.getElementById('seo-health-results');
if (!resultsContainer) return;
let html = '<div class="seo-results-container">';
html += '<div class="seo-score-display" style="text-align: center; margin-bottom: 30px;">';
html += '<h3>SEO Health Score: ' + Math.round((data.score / data.max_score) * 100) + '%</h3>';
html += '</div>';
if (data.recommendations && data.recommendations.length > 0) {
html += '<div class="seo-section"><h3>Recommendations</h3>';
data.recommendations.forEach(function(item) {
html += createSEOItem(item);
});
html += '</div>';
}
html += '</div>';
resultsContainer.innerHTML = html;
}
function createSEOItem(item) {
let html = '<div class="seo-item" style="border: 1px solid #ddd; border-radius: 5px; padding: 15px; margin-bottom: 10px;">';
html += '<h4>' + item.title + '</h4>';
html += '<p>' + item.description + '</p>';
if (item.action && item.action.url) {
html += '<a href="' + item.action.url + '" class="button button-primary">' + item.action.text + '</a>';
}
html += '</div>';
return html;
}
function showError(message) {
const resultsContainer = document.getElementById('seo-health-results');
if (resultsContainer) {
resultsContainer.innerHTML = '<div class="notice notice-error"><p>' + message + '</p></div>';
}
}
// Cache Analysis functionality
$('#analyze-cache-btn').on('click', function() {
const button = $(this);
const originalText = button.text();
const loadingDiv = $('#cache-analysis-loading');
const resultsDiv = $('#cache-analysis-results');
// Update button state
button.text('Analyzing...').prop('disabled', true);
loadingDiv.show();
resultsDiv.hide().empty();
// Make AJAX request
$.ajax({
url: tigerstyleSEO.ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_analyze_cache',
nonce: tigerstyleSEO.cache_analysis_nonce
},
success: function(response) {
button.text(originalText).prop('disabled', false);
loadingDiv.hide();
if (response.success) {
displayCacheAnalysisResults(response.data);
resultsDiv.show();
} else {
showCacheAnalysisError('Analysis failed. Please try again.');
}
},
error: function() {
button.text(originalText).prop('disabled', false);
loadingDiv.hide();
showCacheAnalysisError('Network error. Please check your connection and try again.');
}
});
});
function displayCacheAnalysisResults(data) {
const resultsDiv = $('#cache-analysis-results');
let html = '<div class="cache-analysis-container">';
// Summary section
html += '<div class="cache-summary" style="background: #f0f8ff; border: 1px solid #007cba; border-radius: 5px; padding: 20px; margin-bottom: 20px;">';
html += '<h4>📊 Analysis Summary</h4>';
html += '<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-top: 15px;">';
html += '<div><strong>Total Content Size:</strong><br><span style="color: #007cba; font-size: 18px;">' + data.total_size_formatted + '</span></div>';
html += '<div><strong>Potential Savings:</strong><br><span style="color: #46b450; font-size: 18px;">' + data.potential_savings_formatted + '</span></div>';
html += '<div><strong>Compression Ratio:</strong><br><span style="color: #46b450; font-size: 18px;">' + data.savings_percentage + '%</span></div>';
html += '</div></div>';
// Compression estimates
if (data.compression_estimates) {
html += '<div class="compression-estimates" style="margin-bottom: 25px;">';
html += '<h4>🎯 Compression Method Comparison</h4>';
html += '<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 15px; margin-top: 10px;">';
Object.values(data.compression_estimates).forEach(function(estimate) {
html += '<div style="padding: 15px; background: #f9f9f9; border-radius: 5px; border-left: 4px solid #007cba;">';
html += '<strong>' + estimate.method + '</strong><br>';
html += '<span style="color: #666;">Compression: ' + estimate.ratio + '%</span><br>';
html += '<span style="color: #46b450; font-weight: bold;">Saves: ' + estimate.savings_formatted + '</span>';
html += '</div>';
});
html += '</div></div>';
}
// Pages analysis
if (data.pages && data.pages.length > 0) {
html += '<div class="pages-analysis" style="margin-bottom: 25px;">';
html += '<h4>📄 Page Analysis</h4>';
html += '<div style="overflow-x: auto;">';
html += '<table class="wp-list-table widefat fixed striped" style="margin-top: 10px;">';
html += '<thead><tr><th>Page</th><th>Size</th><th>Compression Ratio</th><th>Potential Savings</th></tr></thead>';
html += '<tbody>';
data.pages.forEach(function(page) {
html += '<tr>';
html += '<td><strong>' + page.title + '</strong><br><small style="color: #666;">' + page.url + '</small></td>';
html += '<td>' + page.size_formatted + '</td>';
html += '<td><span style="color: #46b450;">' + page.compression_ratio + '%</span></td>';
html += '<td><span style="color: #46b450; font-weight: bold;">' + page.savings_formatted + '</span></td>';
html += '</tr>';
});
html += '</tbody></table></div></div>';
}
// Assets analysis
if (data.assets && data.assets.length > 0) {
html += '<div class="assets-analysis" style="margin-bottom: 25px;">';
html += '<h4>🗂️ Static Assets Analysis</h4>';
html += '<div style="overflow-x: auto;">';
html += '<table class="wp-list-table widefat fixed striped" style="margin-top: 10px;">';
html += '<thead><tr><th>File</th><th>Type</th><th>Size</th><th>Compression Ratio</th><th>Potential Savings</th></tr></thead>';
html += '<tbody>';
data.assets.forEach(function(asset) {
html += '<tr>';
html += '<td><strong>' + asset.filename + '</strong></td>';
html += '<td><span class="asset-type-' + asset.type.toLowerCase() + '">' + asset.type + '</span></td>';
html += '<td>' + asset.size_formatted + '</td>';
html += '<td><span style="color: #46b450;">' + asset.compression_ratio + '%</span></td>';
html += '<td><span style="color: #46b450; font-weight: bold;">' + asset.savings_formatted + '</span></td>';
html += '</tr>';
});
html += '</tbody></table></div></div>';
}
// Recommendations
html += '<div class="cache-recommendations" style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 5px; padding: 20px;">';
html += '<h4>💡 Recommendations</h4>';
html += '<ul style="margin: 10px 0 0 20px;">';
html += '<li><strong>Enable Compression:</strong> Turn on the compression system above to automatically compress all content.</li>';
html += '<li><strong>Use Auto Mode:</strong> The automatic Brotli + Gzip fallback provides the best compatibility and performance.</li>';
html += '<li><strong>Monitor Performance:</strong> Check the statistics regularly to track your bandwidth savings.</li>';
if (data.savings_percentage > 60) {
html += '<li><strong>Excellent Potential:</strong> Your site has high compression potential! Enable compression for significant performance gains.</li>';
}
html += '</ul></div>';
html += '</div>';
resultsDiv.html(html);
}
function showCacheAnalysisError(message) {
const resultsDiv = $('#cache-analysis-results');
resultsDiv.html('<div class="notice notice-error" style="margin: 0;"><p>' + message + '</p></div>').show();
}
// AI Provider functionality
$('.test-api-key').on('click', function() {
const button = $(this);
const provider = button.data('provider');
const originalText = button.text();
const resultsDiv = $('#provider-results-' + provider);
button.text('Testing...').prop('disabled', true);
resultsDiv.html('<div class="notice notice-info"><p>Testing API key...</p></div>');
$.ajax({
url: tigerstyleSEO.ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_test_api_key',
provider_name: provider,
nonce: tigerstyleSEO.ai_nonce || tigerstyleSEO.nonce
},
success: function(response) {
button.text(originalText).prop('disabled', false);
if (response.success) {
resultsDiv.html('<div class="notice notice-success"><p>' + response.message + '</p></div>');
// Refresh the page to show updated models
setTimeout(function() {
location.reload();
}, 2000);
} else {
resultsDiv.html('<div class="notice notice-error"><p>Error: ' + response.error + '</p></div>');
}
},
error: function() {
button.text(originalText).prop('disabled', false);
resultsDiv.html('<div class="notice notice-error"><p>Network error. Please try again.</p></div>');
}
});
});
$('.refresh-models').on('click', function() {
const button = $(this);
const provider = button.data('provider');
const originalText = button.text();
const resultsDiv = $('#provider-results-' + provider);
button.text('Refreshing...').prop('disabled', true);
resultsDiv.html('<div class="notice notice-info"><p>Refreshing models...</p></div>');
$.ajax({
url: tigerstyleSEO.ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_refresh_models',
provider_name: provider,
nonce: tigerstyleSEO.ai_nonce || tigerstyleSEO.nonce
},
success: function(response) {
button.text(originalText).prop('disabled', false);
if (response.success) {
resultsDiv.html('<div class="notice notice-success"><p>' + response.message + '</p></div>');
// Refresh the page to show updated models
setTimeout(function() {
location.reload();
}, 2000);
} else {
resultsDiv.html('<div class="notice notice-error"><p>Error: ' + response.error + '</p></div>');
}
},
error: function() {
button.text(originalText).prop('disabled', false);
resultsDiv.html('<div class="notice notice-error"><p>Network error. Please try again.</p></div>');
}
});
});
$('.delete-provider').on('click', function() {
const button = $(this);
const provider = button.data('provider');
if (!confirm('Are you sure you want to delete the "' + provider + '" provider? This action cannot be undone.')) {
return;
}
const originalText = button.text();
button.text('Deleting...').prop('disabled', true);
$.ajax({
url: tigerstyleSEO.ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_delete_api_key',
provider_name: provider,
nonce: tigerstyleSEO.ai_nonce || tigerstyleSEO.nonce
},
success: function(response) {
if (response.success) {
// Remove the provider card from the page
button.closest('.provider-card').fadeOut(function() {
$(this).remove();
});
} else {
button.text(originalText).prop('disabled', false);
alert('Error: ' + response.message);
}
},
error: function() {
button.text(originalText).prop('disabled', false);
alert('Network error. Please try again.');
}
});
});
$('.model-toggle').on('change', function() {
const checkbox = $(this);
const provider = checkbox.data('provider');
const model = checkbox.data('model');
const enabled = checkbox.is(':checked');
// Create a hidden form and submit it
const form = $('<form method="post" action="' + tigerstyleSEO.ajaxurl.replace('admin-ajax.php', 'admin-post.php') + '">');
form.append('<input type="hidden" name="action" value="update_ai_provider_settings">');
form.append('<input type="hidden" name="ai_action" value="toggle_model">');
form.append('<input type="hidden" name="provider_name" value="' + provider + '">');
form.append('<input type="hidden" name="model_id" value="' + model + '">');
if (enabled) {
form.append('<input type="hidden" name="enabled" value="1">');
}
form.append('<input type="hidden" name="ai_provider_nonce" value="' + (tigerstyleSEO.ai_nonce || tigerstyleSEO.nonce) + '">');
$('body').append(form);
form.submit();
});
// AI Chat Interface functionality
$('#ai-chat-provider').on('change', function() {
const hasProvider = $(this).val() !== '';
$('#ai-chat-send').prop('disabled', !hasProvider);
if (hasProvider) {
$('#ai-chat-status').text('Ready to chat with ' + $(this).find('option:selected').text());
} else {
$('#ai-chat-status').text('');
}
});
$('#ai-chat-clear').on('click', function() {
$('#ai-chat-messages').html('<div class="chat-message system-message" style="color: #666; font-style: italic;">💡 Ask me anything about SEO, content optimization, meta tags, or website improvement!</div>');
});
$('#ai-chat-send').on('click', function() {
sendChatMessage();
});
$('#ai-chat-input').on('keypress', function(e) {
if (e.which === 13 && e.ctrlKey) { // Ctrl+Enter
sendChatMessage();
}
});
function sendChatMessage() {
const provider = $('#ai-chat-provider').val();
const message = $('#ai-chat-input').val().trim();
if (!provider || !message) {
return;
}
const [providerName, modelId] = provider.split('|');
// Add user message to chat
addChatMessage('user', message);
$('#ai-chat-input').val('');
// Show loading
const loadingId = 'loading_' + Date.now();
addChatMessage('assistant', '<div id="' + loadingId + '" style="display: flex; align-items: center; gap: 10px;"><div class="spinner is-active" style="float: none; margin: 0;"></div>Thinking...</div>');
// Send AJAX request
$.ajax({
url: tigerstyleSEO.ajaxurl,
type: 'POST',
data: {
action: 'tigerstyle_ai_chat',
provider_name: providerName,
model_id: modelId,
message: message,
nonce: tigerstyleSEO.ai_nonce || tigerstyleSEO.nonce
},
success: function(response) {
$('#' + loadingId).closest('.chat-message').remove();
if (response.success) {
addChatMessage('assistant', response.data.response);
} else {
addChatMessage('error', 'Error: ' + (response.data || 'Failed to get response'));
}
},
error: function() {
$('#' + loadingId).closest('.chat-message').remove();
addChatMessage('error', 'Network error. Please try again.');
}
});
}
function addChatMessage(sender, content) {
const timestamp = new Date().toLocaleTimeString();
let messageClass = 'chat-message';
let senderIcon = '';
let senderLabel = '';
switch(sender) {
case 'user':
messageClass += ' user-message';
senderIcon = '🙋‍♀️';
senderLabel = 'You';
break;
case 'assistant':
messageClass += ' assistant-message';
senderIcon = '🤖';
senderLabel = 'AI Assistant';
break;
case 'error':
messageClass += ' error-message';
senderIcon = '⚠️';
senderLabel = 'Error';
break;
}
const messageHtml = '<div class="' + messageClass + '" style="margin-bottom: 15px; padding: 10px; border-radius: 5px; ' +
(sender === 'user' ? 'background: #e3f2fd; margin-left: 20px;' :
sender === 'error' ? 'background: #ffebee; border-left: 3px solid #f44336;' :
'background: white; border: 1px solid #e0e0e0;') + '">' +
'<div style="font-size: 12px; color: #666; margin-bottom: 5px;">' +
'<strong>' + senderIcon + ' ' + senderLabel + '</strong> <span style="float: right;">' + timestamp + '</span>' +
'</div>' +
'<div style="line-height: 1.5;">' + content + '</div>' +
'</div>';
$('#ai-chat-messages').append(messageHtml);
$('#ai-chat-messages').scrollTop($('#ai-chat-messages')[0].scrollHeight);
}
});