WordPress Integration
WordPress Integration Overview
Section titled “WordPress Integration Overview”The Elasticsearch integration seamlessly integrates with WordPress through custom page templates, AJAX handlers, and the WordPress hook system. This ensures compatibility with WordPress standards while providing powerful search and monitoring capabilities.
Template System
Section titled “Template System”Custom Page Templates
Section titled “Custom Page Templates”The integration includes two custom WordPress page templates:
1. Search Page Template
Section titled “1. Search Page Template”File: page-search.php
Template Name: “Search Page”
Purpose: Public-facing search interface
<?php/*Template Name: Search Page*/
get_header(); ?>
<div class="search-container"> <div class="search-header"> <h1>Product Search</h1> <form id="search-form" class="search-form"> <input type="text" id="search-query" name="q" placeholder="Search products..."> <button type="submit">Search</button> </form> </div>
<div class="search-filters"> <?php get_template_part('template-parts/category-selector'); ?> <div class="price-filter"> <label>Price Range:</label> <input type="number" id="min-price" placeholder="Min"> <input type="number" id="max-price" placeholder="Max"> </div> </div>
<div id="search-results" class="search-results"> <!-- Results will be loaded via AJAX --> </div>
<div id="search-pagination" class="pagination"> <!-- Pagination will be loaded via AJAX --> </div></div>
<script>// Search functionalitydocument.getElementById('search-form').addEventListener('submit', function(e) { e.preventDefault(); performSearch();});
function performSearch() { const query = document.getElementById('search-query').value; const category = document.getElementById('category-select').value; const minPrice = document.getElementById('min-price').value; const maxPrice = document.getElementById('max-price').value;
// AJAX search request jQuery.post(ajaxurl, { action: 'search_products', nonce: ajax_nonce, query: query, category: category, min_price: minPrice, max_price: maxPrice, page: 1 }, function(response) { if (response.success) { displaySearchResults(response.data); } else { displayError(response.data); } });}</script>
<?php get_footer(); ?>2. Console Page Template
Section titled “2. Console Page Template”File: page-elasticsearch-console.php
Template Name: “Elasticsearch Console”
Purpose: Admin monitoring dashboard
<?php/*Template Name: Elasticsearch Console*/
// Check admin permissionsif (!current_user_can('manage_options')) { wp_die('Insufficient permissions');}
get_header(); ?>
<div class="elasticsearch-console"> <div class="console-header"> <h1>Elasticsearch Console</h1> <div class="console-actions"> <button id="refresh-stats" class="btn btn-primary">Refresh</button> <button id="test-connection" class="btn btn-secondary">Test Connection</button> <button id="reset-sync" class="btn btn-danger">Reset Sync</button> </div> </div>
<div class="console-stats"> <div class="stat-card"> <h3>Sync Status</h3> <div id="sync-status" class="stat-value">Loading...</div> </div>
<div class="stat-card"> <h3>Progress</h3> <div id="sync-progress" class="stat-value">Loading...</div> </div>
<div class="stat-card"> <h3>Products Indexed</h3> <div id="indexed-count" class="stat-value">Loading...</div> </div>
<div class="stat-card"> <h3>ETA</h3> <div id="sync-eta" class="stat-value">Loading...</div> </div> </div>
<div class="console-logs"> <h3>Recent Logs</h3> <div id="log-content" class="log-content"> <!-- Logs will be loaded via AJAX --> </div> </div></div>
<script>// Console functionalityjQuery(document).ready(function($) { loadConsoleStats();
// Auto-refresh every 30 seconds setInterval(loadConsoleStats, 30000);
$('#refresh-stats').click(loadConsoleStats); $('#test-connection').click(testConnection); $('#reset-sync').click(resetSync);});
function loadConsoleStats() { jQuery.post(ajaxurl, { action: 'get_elasticsearch_stats', nonce: ajax_nonce }, function(response) { if (response.success) { updateConsoleDisplay(response.data); } });}</script>
<?php get_footer(); ?>AJAX Endpoints
Section titled “AJAX Endpoints”AJAX Handler Registration
Section titled “AJAX Handler Registration”File: functions.php
// AJAX handlers for Elasticsearch operationsadd_action('wp_ajax_get_elasticsearch_stats', 'ajax_get_elasticsearch_stats');add_action('wp_ajax_get_elasticsearch_log', 'ajax_get_elasticsearch_log');add_action('wp_ajax_test_elasticsearch_connection', 'ajax_test_elasticsearch_connection');add_action('wp_ajax_reset_elasticsearch_sync', 'ajax_reset_elasticsearch_sync');add_action('wp_ajax_run_manual_elasticsearch_sync', 'ajax_run_manual_elasticsearch_sync');add_action('wp_ajax_search_products', 'ajax_search_products');
// Public AJAX endpoints (for search page)add_action('wp_ajax_nopriv_search_products', 'ajax_search_products');add_action('wp_ajax_nopriv_load_category_children', 'ajax_load_category_children');add_action('wp_ajax_nopriv_search_categories', 'ajax_search_categories');AJAX Handler Implementations
Section titled “AJAX Handler Implementations”Get Elasticsearch Statistics
Section titled “Get Elasticsearch Statistics”function ajax_get_elasticsearch_stats() { // Verify nonce check_ajax_referer('elasticsearch_nonce', 'nonce');
// Check permissions if (!current_user_can('manage_options')) { wp_send_json_error('Insufficient permissions'); }
try { $console_manager = new ElasticsearchConsoleManager(); $stats = $console_manager->getStats(); $performance = $console_manager->getPerformanceEstimates();
wp_send_json_success([ 'stats' => $stats, 'performance' => $performance ]); } catch (Exception $e) { wp_send_json_error('Failed to get statistics: ' . $e->getMessage()); }}Search Products
Section titled “Search Products”function ajax_search_products() { // Verify nonce check_ajax_referer('search_nonce', 'nonce');
try { $query = sanitize_text_field($_POST['query'] ?? ''); $category = sanitize_text_field($_POST['category'] ?? ''); $min_price = floatval($_POST['min_price'] ?? 0); $max_price = floatval($_POST['max_price'] ?? 0); $brand = sanitize_text_field($_POST['brand'] ?? ''); $page = intval($_POST['page'] ?? 1); $per_page = intval($_POST['per_page'] ?? 20);
$filters = []; if (!empty($category)) $filters['category'] = $category; if ($min_price > 0) $filters['min_price'] = $min_price; if ($max_price > 0) $filters['max_price'] = $max_price; if (!empty($brand)) $filters['brand'] = $brand;
$elasticsearch = new ProductElasticsearch(); $results = $elasticsearch->searchProducts($query, $filters, $page, $per_page);
wp_send_json_success($results); } catch (Exception $e) { wp_send_json_error('Search failed: ' . $e->getMessage()); }}Get Log Content
Section titled “Get Log Content”function ajax_get_elasticsearch_log() { // Verify nonce check_ajax_referer('elasticsearch_nonce', 'nonce');
// Check permissions if (!current_user_can('manage_options')) { wp_send_json_error('Insufficient permissions'); }
try { $log_type = sanitize_text_field($_POST['log_type'] ?? 'auto_sync'); $lines = intval($_POST['lines'] ?? 100);
$console_manager = new ElasticsearchConsoleManager(); $log_content = $console_manager->getLogContent($log_type, $lines);
wp_send_json_success($log_content); } catch (Exception $e) { wp_send_json_error('Failed to get log content: ' . $e->getMessage()); }}Test Connection
Section titled “Test Connection”function ajax_test_elasticsearch_connection() { // Verify nonce check_ajax_referer('elasticsearch_nonce', 'nonce');
// Check permissions if (!current_user_can('manage_options')) { wp_send_json_error('Insufficient permissions'); }
try { $elasticsearch = new ProductElasticsearch(); $is_available = $elasticsearch->isAvailable();
if ($is_available) { $document_count = $elasticsearch->getDocumentCount(); wp_send_json_success([ 'status' => 'connected', 'document_count' => $document_count, 'message' => 'Elasticsearch connection successful' ]); } else { wp_send_json_error('Elasticsearch connection failed'); } } catch (Exception $e) { wp_send_json_error('Connection test failed: ' . $e->getMessage()); }}Reset Sync
Section titled “Reset Sync”function ajax_reset_elasticsearch_sync() { // Verify nonce check_ajax_referer('elasticsearch_nonce', 'nonce');
// Check permissions if (!current_user_can('manage_options')) { wp_send_json_error('Insufficient permissions'); }
try { $console_manager = new ElasticsearchConsoleManager(); $result = $console_manager->resetSync();
wp_send_json_success($result); } catch (Exception $e) { wp_send_json_error('Reset failed: ' . $e->getMessage()); }}WordPress Hooks Integration
Section titled “WordPress Hooks Integration”Admin Menu Integration
Section titled “Admin Menu Integration”// Add admin menu itemadd_action('admin_menu', 'elasticsearch_admin_menu');
function elasticsearch_admin_menu() { add_management_page( 'Elasticsearch Sync', // Page title 'Elasticsearch Sync', // Menu title 'manage_options', // Capability 'elasticsearch-sync', // Menu slug 'elasticsearch_sync_page' // Callback );}
function elasticsearch_sync_page() { // Admin page content echo '<div class="wrap">'; echo '<h1>Elasticsearch Sync</h1>'; echo '<p>Manage Elasticsearch synchronization from here.</p>'; echo '</div>';}Theme Integration
Section titled “Theme Integration”// Include Elasticsearch classesadd_action('after_setup_theme', 'load_elasticsearch_classes');
function load_elasticsearch_classes() { require_once get_template_directory() . '/inc/elasticsearch.php'; require_once get_template_directory() . '/inc/elasticsearch-console-manager.php';}Enqueue Scripts and Styles
Section titled “Enqueue Scripts and Styles”// Enqueue scripts and stylesadd_action('wp_enqueue_scripts', 'enqueue_elasticsearch_assets');
function enqueue_elasticsearch_assets() { // Only enqueue on search and console pages if (is_page_template('page-search.php') || is_page_template('page-elasticsearch-console.php')) { wp_enqueue_script('jquery');
// Localize script with AJAX URL and nonce wp_localize_script('jquery', 'ajax_object', [ 'ajax_url' => admin_url('admin-ajax.php'), 'ajax_nonce' => wp_create_nonce('elasticsearch_nonce'), 'search_nonce' => wp_create_nonce('search_nonce') ]);
// Enqueue custom CSS wp_enqueue_style('elasticsearch-styles', get_template_directory_uri() . '/css/elasticsearch.css'); }}Template Parts
Section titled “Template Parts”Category Selector Component
Section titled “Category Selector Component”File: template-parts/category-selector.php
<div class="category-selector"> <label for="category-select">Category:</label> <select id="category-select" name="category"> <option value="">All Categories</option> <?php $categories = get_categories_hierarchy(); foreach ($categories as $category) { echo '<option value="' . esc_attr($category['id']) . '">' . esc_html($category['name']) . '</option>'; } ?> </select>
<div id="category-search" class="category-search"> <input type="text" id="category-search-input" placeholder="Search categories..."> <div id="category-search-results" class="category-search-results"></div> </div></div>
<script>// Category search functionalitydocument.getElementById('category-search-input').addEventListener('input', function(e) { const query = e.target.value;
if (query.length < 2) { document.getElementById('category-search-results').innerHTML = ''; return; }
jQuery.post(ajaxurl, { action: 'search_categories', nonce: ajax_nonce, query: query }, function(response) { if (response.success) { displayCategorySearchResults(response.data); } });});</script>Security Implementation
Section titled “Security Implementation”Nonce Verification
Section titled “Nonce Verification”// Create nonces for different actionsfunction create_elasticsearch_nonces() { return [ 'elasticsearch_nonce' => wp_create_nonce('elasticsearch_nonce'), 'search_nonce' => wp_create_nonce('search_nonce'), 'category_nonce' => wp_create_nonce('category_nonce') ];}
// Verify nonces in AJAX handlersfunction verify_elasticsearch_nonce($action) { if (!wp_verify_nonce($_POST['nonce'], $action)) { wp_send_json_error('Invalid nonce'); }}Permission Checks
Section titled “Permission Checks”// Check user capabilitiesfunction check_elasticsearch_permissions($capability = 'manage_options') { if (!current_user_can($capability)) { wp_send_json_error('Insufficient permissions'); }}
// Public search permissions (no login required)function check_search_permissions() { // Search is public, no additional checks needed return true;}Input Sanitization
Section titled “Input Sanitization”// Sanitize search inputsfunction sanitize_search_inputs($inputs) { $sanitized = [];
foreach ($inputs as $key => $value) { switch ($key) { case 'query': case 'category': case 'brand': $sanitized[$key] = sanitize_text_field($value); break; case 'min_price': case 'max_price': case 'page': case 'per_page': $sanitized[$key] = intval($value); break; default: $sanitized[$key] = sanitize_text_field($value); } }
return $sanitized;}Error Handling
Section titled “Error Handling”WordPress Error Handling
Section titled “WordPress Error Handling”// Handle WordPress errors gracefullyfunction handle_elasticsearch_error($error, $context = '') { // Log error error_log("Elasticsearch error [$context]: $error");
// Send appropriate response if (wp_doing_ajax()) { wp_send_json_error($error); } else { wp_die($error); }}
// Custom error handlerset_error_handler(function($severity, $message, $file, $line) { if (strpos($file, 'elasticsearch') !== false) { handle_elasticsearch_error("$message in $file:$line", 'PHP Error'); }});Performance Optimization
Section titled “Performance Optimization”Caching Integration
Section titled “Caching Integration”// WordPress object cache integrationfunction get_cached_search_results($cache_key, $callback) { $cached = wp_cache_get($cache_key, 'elasticsearch');
if ($cached === false) { $cached = $callback(); wp_cache_set($cache_key, $cached, 'elasticsearch', 300); // 5 minutes }
return $cached;}
// Cache search resultsfunction cached_search_products($query, $filters, $page, $per_page) { $cache_key = 'search_' . md5(serialize([$query, $filters, $page, $per_page]));
return get_cached_search_results($cache_key, function() use ($query, $filters, $page, $per_page) { $elasticsearch = new ProductElasticsearch(); return $elasticsearch->searchProducts($query, $filters, $page, $per_page); });}Database Query Optimization
Section titled “Database Query Optimization”// Optimize WordPress database queriesadd_action('pre_get_posts', 'optimize_elasticsearch_queries');
function optimize_elasticsearch_queries($query) { if (is_page_template('page-search.php')) { // Disable WordPress query for search page $query->set('post_type', 'none'); }}Next Steps
Section titled “Next Steps”- Search Functionality - Search implementation details
- Monitoring & Management - Console and monitoring features
- API Endpoints - API reference
- Configuration - System configuration