Changeset 3394691
- Timestamp:
- 11/12/2025 11:28:08 PM (5 months ago)
- Location:
- searchcraft/trunk
- Files:
-
- 1 deleted
- 4 edited
-
admin/class-searchcraft-admin.php (modified) (6 diffs)
-
includes/class-searchcraft-loader.php (deleted)
-
includes/class-searchcraft.php (modified) (7 diffs)
-
readme.txt (modified) (2 diffs)
-
searchcraft.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
searchcraft/trunk/admin/class-searchcraft-admin.php
r3393810 r3394691 84 84 $this->plugin_version = $plugin_version; 85 85 86 // Initialize all hooks. 87 $this->init_hooks(); 88 } 89 90 /** 91 * Initialize all WordPress hooks for admin functionality. 92 * 93 * @since 1.0.0 94 */ 95 private function init_hooks() { 86 96 // Only run setup if we're in the admin area and not during plugin activation. 87 97 if ( is_admin() && ! ( defined( 'WP_INSTALLING' ) && WP_INSTALLING ) ) { … … 93 103 add_action( 'publish_post', array( $this, 'clear_oldest_post_year_transient' ) ); 94 104 add_action( 'delete_post', array( $this, 'clear_oldest_post_year_transient' ) ); 105 106 // Register admin-specific hooks. 107 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_styles' ) ); 108 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); 109 add_action( 'admin_menu', array( $this, 'searchcraft_add_menu_page' ) ); 110 add_action( 'admin_init', array( $this, 'searchcraft_request_handler' ) ); 111 112 // Use wp_after_insert_post instead of transition_post_status to ensure Yoast SEO meta data is saved first. 113 add_action( 'wp_after_insert_post', array( $this, 'searchcraft_on_publish_post' ), 10, 4 ); 114 add_action( 'transition_post_status', array( $this, 'searchcraft_on_unpublish_post' ), 10, 3 ); 115 116 add_action( 'add_meta_boxes', array( $this, 'searchcraft_add_exclude_from_searchcraft_meta_box' ) ); 117 // 'save_post' happens before 'transition_post_status' in the execution order 118 // So we will have the updated '_searchcraft_exclude_from_index' value before publishing the post 119 add_action( 'save_post', array( $this, 'searchcraft_on_save_post' ) ); 95 120 } 96 121 … … 1443 1468 // Re-throw the exception so it can be caught by calling code. 1444 1469 throw $e; 1470 } finally { 1471 // Free memory: unset large variables to help garbage collection. 1472 unset( $documents, $ingest_client ); 1445 1473 } 1446 1474 } … … 1516 1544 * in batches to handle large numbers of posts efficiently. 1517 1545 * 1546 * Uses cursor-based pagination for optimal performance on large datasets. 1547 * 1518 1548 * @since 1.0.0 1519 1549 */ 1520 1550 public function searchcraft_add_all_documents() { 1521 // First, get a count of all eligible posts to determine if batching is needed. 1522 $count_query = new WP_Query( 1523 array( 1524 'post_type' => 'any', 1525 'post_status' => 'publish', 1526 'posts_per_page' => 1, 1527 'fields' => 'ids', 1551 global $wpdb; 1552 1553 // Get count of eligible posts using direct SQL for better performance. 1554 // This counts posts that are either not excluded or don't have the exclusion meta key. 1555 // Note, we replaced the previous WP_Query approach because this direct query is more efficient. 1556 $total_posts = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 1557 "SELECT COUNT(DISTINCT p.ID) 1558 FROM {$wpdb->posts} p 1559 LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id 1560 AND pm.meta_key = '_searchcraft_exclude_from_index' 1561 WHERE p.post_status = 'publish' 1562 AND (pm.meta_value != '1' OR pm.meta_value IS NULL)" 1563 ); 1564 1565 if ( 0 === $total_posts ) { 1566 return; 1567 } 1568 1569 // Remove all existing documents from the index first. 1570 $this->searchcraft_delete_all_documents(); 1571 1572 // Define batch size. 1573 $batch_size = 4000; 1574 $batches = ceil( $total_posts / $batch_size ); 1575 $last_id = 0; 1576 1577 // Process posts in batches using cursor-based pagination. 1578 for ( $batch = 0; $batch < $batches; $batch++ ) { 1579 // Build query args for this batch. 1580 $query_args = array( 1581 'post_type' => 'any', 1582 'posts_per_page' => $batch_size, 1583 'post_status' => 'publish', 1584 'orderby' => 'ID', 1585 'order' => 'ASC', 1586 'no_found_rows' => true, // Don't calculate total rows (performance optimization). 1587 'update_post_meta_cache' => false, // Don't prime meta cache (memory optimization). 1588 'update_post_term_cache' => false, // Don't prime term cache (memory optimization). 1528 1589 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 1529 'meta_query' => array(1590 'meta_query' => array( 1530 1591 'relation' => 'OR', 1531 1592 // Include posts where the exclusion flag is not set to '1'. … … 1541 1602 ), 1542 1603 ), 1543 ) 1544 ); 1545 1546 $total_posts = $count_query->found_posts; 1547 1548 if ( 0 === $total_posts ) { 1549 return; 1550 } 1551 1552 // Remove all existing documents from the index first. 1553 $this->searchcraft_delete_all_documents(); 1554 1555 // Define batch size. 1556 $batch_size = 50000; 1557 $batches = ceil( $total_posts / $batch_size ); 1558 1559 // Process posts in batches. 1560 for ( $batch = 0; $batch < $batches; $batch++ ) { 1561 $offset = $batch * $batch_size; 1604 ); 1605 1606 // Use cursor-based pagination: only fetch posts with ID greater than the last processed ID. 1607 if ( $last_id > 0 ) { 1608 $query_args['post__not_in'] = range( 1, $last_id ); 1609 } 1562 1610 1563 1611 // Query posts for this batch. 1564 $batch_query = new WP_Query( 1565 array( 1566 'post_type' => 'any', 1567 'posts_per_page' => $batch_size, 1568 'offset' => $offset, 1569 'post_status' => 'publish', 1570 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 1571 'meta_query' => array( 1572 'relation' => 'OR', 1573 // Include posts where the exclusion flag is not set to '1'. 1574 array( 1575 'key' => '_searchcraft_exclude_from_index', 1576 'value' => '1', 1577 'compare' => '!=', 1578 ), 1579 // Or where the exclusion flag doesn't exist at all. 1580 array( 1581 'key' => '_searchcraft_exclude_from_index', 1582 'compare' => 'NOT EXISTS', 1583 ), 1584 ), 1585 ) 1586 ); 1612 $batch_query = new WP_Query( $query_args ); 1587 1613 1588 1614 if ( $batch_query->have_posts() ) { 1615 $posts = $batch_query->posts; 1616 1617 // Remember the last ID for cursor-based pagination. 1618 $last_id = end( $posts )->ID; 1619 1589 1620 // Add this batch of documents to the index. 1590 $this->searchcraft_add_documents( $ batch_query->posts );1621 $this->searchcraft_add_documents( $posts ); 1591 1622 1592 1623 // Log progress. … … 1595 1626 } 1596 1627 1597 // Clean up memory.1628 // Aggressive memory cleanup between batches. 1598 1629 wp_reset_postdata(); 1630 unset( $batch_query, $posts, $query_args ); 1631 1632 // Flush WordPress object cache to prevent memory buildup. 1633 wp_cache_flush(); 1634 1635 // Force garbage collection to free memory immediately. 1636 if ( function_exists( 'gc_collect_cycles' ) ) { 1637 gc_collect_cycles(); 1638 } 1599 1639 } 1600 1640 -
searchcraft/trunk/includes/class-searchcraft.php
r3377712 r3394691 21 21 * The core plugin class 22 22 * 23 * This is used to define internationalization, admin-specific hooks, and24 * public-facing site hooks.23 * This is used to load dependencies and initialize the admin and public-facing 24 * functionality of the plugin. 25 25 * 26 26 * Also maintains the unique identifier of this plugin as well as the current … … 33 33 */ 34 34 class Searchcraft { 35 36 /**37 * The loader that's responsible for maintaining and registering all hooks that power38 * the plugin.39 *40 * @since 1.0.041 * @var Searchcraft_Loader $loader Maintains and registers all hooks for the plugin.42 */43 protected $loader;44 35 45 36 /** … … 63 54 * 64 55 * Set the plugin name and the plugin version that can be used throughout the plugin. 65 * Load the dependencies, define the locale, and set the hooks for the admin area and 66 * the public-facing side of the site. 56 * Load the dependencies and initialize the admin and public-facing functionality. 67 57 * 68 58 * @since 1.0.0 … … 77 67 78 68 $this->load_dependencies(); 79 $this->define_admin_hooks(); 80 $this->define_public_hooks(); 69 $this->init_components(); 81 70 } 82 71 … … 86 75 * Include the following files that make up the plugin: 87 76 * 88 * - Searchcraft_Loader. Orchestrates the hooks of the plugin. 77 * - Searchcraft_Config. Manages plugin configuration. 78 * - Searchcraft_Helper_Functions. Provides helper functions. 89 79 * - Searchcraft_Admin. Defines all hooks for the admin area. 90 80 * - Searchcraft_Public. Defines all hooks for the public side of the site. 91 *92 * Create an instance of the loader which will be used to register the hooks93 * with WordPress.94 81 * 95 82 * @since 1.0.0 96 83 */ 97 84 private function load_dependencies() { 98 /**99 * The class responsible for orchestrating the actions and filters of the100 * core plugin.101 */102 require_once plugin_dir_path( __DIR__ ) . 'includes/class-searchcraft-loader.php';103 104 85 /** 105 86 * The class responsible for configuration management. … … 122 103 */ 123 104 require_once plugin_dir_path( __DIR__ ) . 'public/class-searchcraft-public.php'; 124 125 $this->loader = new Searchcraft_Loader();126 105 } 127 106 128 107 /** 129 * Register all of the hooks related to the admin area functionality 130 * of the plugin. 108 * Initialize the admin and public-facing components. 109 * 110 * Creates instances of the admin and public classes, which register 111 * their own hooks in their constructors. 131 112 * 132 113 * @since 1.0.0 133 114 */ 134 private function define_admin_hooks() { 135 $plugin_admin = new Searchcraft_Admin( $this->get_plugin_name(), $this->get_plugin_version() ); 115 private function init_components() { 116 // Initialize admin functionality. 117 new Searchcraft_Admin( $this->get_plugin_name(), $this->get_plugin_version() ); 136 118 137 $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' ); 138 $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' ); 139 140 $this->loader->add_action( 'admin_menu', $plugin_admin, 'searchcraft_add_menu_page' ); 141 142 $this->loader->add_action( 'admin_init', $plugin_admin, 'searchcraft_request_handler' ); 143 144 // Use wp_after_insert_post instead of transition_post_status to ensure Yoast SEO meta data is saved first. 145 $this->loader->add_action( 'wp_after_insert_post', $plugin_admin, 'searchcraft_on_publish_post', 10, 4 ); 146 $this->loader->add_action( 'transition_post_status', $plugin_admin, 'searchcraft_on_unpublish_post', 10, 3 ); 147 148 $this->loader->add_action( 'add_meta_boxes', $plugin_admin, 'searchcraft_add_exclude_from_searchcraft_meta_box' ); 149 // 'save_post' happens before 'transition_post_status' in the execution order 150 // So we will have the updated '_searchcraft_exclude_from_index' value before publishing the post 151 $this->loader->add_action( 'save_post', $plugin_admin, 'searchcraft_on_save_post' ); 152 } 153 154 /** 155 * Register all of the hooks related to the public-facing functionality 156 * of the plugin. 157 * 158 * @since 1.0.0 159 */ 160 private function define_public_hooks() { 161 $plugin_public = new Searchcraft_Public( $this->get_plugin_name(), $this->get_plugin_version() ); 162 } 163 164 /** 165 * Run the loader to execute all of the hooks with WordPress. 166 * 167 * @since 1.0.0 168 */ 169 public function run() { 170 $this->loader->run(); 119 // Initialize public-facing functionality. 120 new Searchcraft_Public( $this->get_plugin_name(), $this->get_plugin_version() ); 171 121 } 172 122 … … 191 141 return $this->plugin_version; 192 142 } 193 194 /**195 * The reference to the class that orchestrates the hooks with the plugin.196 *197 * @since 1.0.0198 * @return Searchcraft_Loader Orchestrates the hooks of the plugin.199 */200 public function get_loader() {201 return $this->loader;202 }203 143 } -
searchcraft/trunk/readme.txt
r3393810 r3394691 5 5 Requires at least: 5.3 6 6 Tested up to: 6.8 7 Stable tag: 1.0. 17 Stable tag: 1.0.2 8 8 License: Apache 2.0 9 9 License URI: LICENSE.txt … … 70 70 == Changelog == 71 71 72 = 1.0.2 = 73 74 * Memory usage optimization for systems with large amounts of posts and small memory allocated to PHP 75 72 76 = 1.0.1 = 73 77 -
searchcraft/trunk/searchcraft.php
r3393810 r3394691 11 11 * Plugin URI: https://github.com/searchcraft-inc/searchcraft-wordpress 12 12 * Description: Bring fast, relevant search to your site. Searchcraft replaces the default search with a customizable, tunable, highly relevant search experience. 13 * Version: 1.0. 113 * Version: 1.0.2 14 14 * Author: Searchcraft, Inc. 15 15 * Author URI: https://searchcraft.io/ … … 27 27 // Define plugin constants. 28 28 if ( ! defined( 'SEARCHCRAFT_VERSION' ) ) { 29 define( 'SEARCHCRAFT_VERSION', '1.0. 0' );29 define( 'SEARCHCRAFT_VERSION', '1.0.2' ); 30 30 } 31 31 … … 147 147 148 148 /** 149 * Initialize and runthe Searchcraft plugin.149 * Initialize the Searchcraft plugin. 150 150 * 151 * This function creates an instance of the main plugin class and starts152 * the plugin execution.151 * Creates an instance of the main plugin class, which loads dependencies 152 * and initializes the admin and public-facing components. 153 153 * 154 154 * @since 1.0.0 155 155 */ 156 156 function run_searchcraft() { 157 $plugin = new Searchcraft(); 158 $plugin->run(); 157 new Searchcraft(); 159 158 } 160 159 run_searchcraft();
Note: See TracChangeset
for help on using the changeset viewer.