Plugin Directory

Changeset 3394691


Ignore:
Timestamp:
11/12/2025 11:28:08 PM (5 months ago)
Author:
searchcraft
Message:

Deploy version 1.0.2

Location:
searchcraft/trunk
Files:
1 deleted
4 edited

Legend:

Unmodified
Added
Removed
  • searchcraft/trunk/admin/class-searchcraft-admin.php

    r3393810 r3394691  
    8484        $this->plugin_version = $plugin_version;
    8585
     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() {
    8696        // Only run setup if we're in the admin area and not during plugin activation.
    8797        if ( is_admin() && ! ( defined( 'WP_INSTALLING' ) && WP_INSTALLING ) ) {
     
    93103        add_action( 'publish_post', array( $this, 'clear_oldest_post_year_transient' ) );
    94104        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' ) );
    95120    }
    96121
     
    14431468                // Re-throw the exception so it can be caught by calling code.
    14441469                throw $e;
     1470            } finally {
     1471                // Free memory: unset large variables to help garbage collection.
     1472                unset( $documents, $ingest_client );
    14451473            }
    14461474        }
     
    15161544     * in batches to handle large numbers of posts efficiently.
    15171545     *
     1546     * Uses cursor-based pagination for optimal performance on large datasets.
     1547     *
    15181548     * @since 1.0.0
    15191549     */
    15201550    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).
    15281589                // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
    1529                 'meta_query'     => array(
     1590                'meta_query'             => array(
    15301591                    'relation' => 'OR',
    15311592                    // Include posts where the exclusion flag is not set to '1'.
     
    15411602                    ),
    15421603                ),
    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            }
    15621610
    15631611            // 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 );
    15871613
    15881614            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
    15891620                // Add this batch of documents to the index.
    1590                 $this->searchcraft_add_documents( $batch_query->posts );
     1621                $this->searchcraft_add_documents( $posts );
    15911622
    15921623                // Log progress.
     
    15951626            }
    15961627
    1597             // Clean up memory.
     1628            // Aggressive memory cleanup between batches.
    15981629            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            }
    15991639        }
    16001640
  • searchcraft/trunk/includes/class-searchcraft.php

    r3377712 r3394691  
    2121 * The core plugin class
    2222 *
    23  * This is used to define internationalization, admin-specific hooks, and
    24  * public-facing site hooks.
     23 * This is used to load dependencies and initialize the admin and public-facing
     24 * functionality of the plugin.
    2525 *
    2626 * Also maintains the unique identifier of this plugin as well as the current
     
    3333 */
    3434class Searchcraft {
    35 
    36     /**
    37      * The loader that's responsible for maintaining and registering all hooks that power
    38      * the plugin.
    39      *
    40      * @since    1.0.0
    41      * @var Searchcraft_Loader $loader Maintains and registers all hooks for the plugin.
    42      */
    43     protected $loader;
    4435
    4536    /**
     
    6354     *
    6455     * 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.
    6757     *
    6858     * @since 1.0.0
     
    7767
    7868        $this->load_dependencies();
    79         $this->define_admin_hooks();
    80         $this->define_public_hooks();
     69        $this->init_components();
    8170    }
    8271
     
    8675     * Include the following files that make up the plugin:
    8776     *
    88      * - Searchcraft_Loader. Orchestrates the hooks of the plugin.
     77     * - Searchcraft_Config. Manages plugin configuration.
     78     * - Searchcraft_Helper_Functions. Provides helper functions.
    8979     * - Searchcraft_Admin. Defines all hooks for the admin area.
    9080     * - 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 hooks
    93      * with WordPress.
    9481     *
    9582     * @since 1.0.0
    9683     */
    9784    private function load_dependencies() {
    98         /**
    99          * The class responsible for orchestrating the actions and filters of the
    100          * core plugin.
    101          */
    102         require_once plugin_dir_path( __DIR__ ) . 'includes/class-searchcraft-loader.php';
    103 
    10485        /**
    10586         * The class responsible for configuration management.
     
    122103         */
    123104        require_once plugin_dir_path( __DIR__ ) . 'public/class-searchcraft-public.php';
    124 
    125         $this->loader = new Searchcraft_Loader();
    126105    }
    127106
    128107    /**
    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.
    131112     *
    132113     * @since 1.0.0
    133114     */
    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() );
    136118
    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() );
    171121    }
    172122
     
    191141        return $this->plugin_version;
    192142    }
    193 
    194     /**
    195      * The reference to the class that orchestrates the hooks with the plugin.
    196      *
    197      * @since 1.0.0
    198      * @return Searchcraft_Loader Orchestrates the hooks of the plugin.
    199      */
    200     public function get_loader() {
    201         return $this->loader;
    202     }
    203143}
  • searchcraft/trunk/readme.txt

    r3393810 r3394691  
    55Requires at least: 5.3
    66Tested up to: 6.8
    7 Stable tag:   1.0.1
     7Stable tag:   1.0.2
    88License:      Apache 2.0
    99License URI:  LICENSE.txt
     
    7070== Changelog ==
    7171
     72= 1.0.2 =
     73
     74* Memory usage optimization for systems with large amounts of posts and small memory allocated to PHP
     75
    7276= 1.0.1 =
    7377
  • searchcraft/trunk/searchcraft.php

    r3393810 r3394691  
    1111 * Plugin URI:        https://github.com/searchcraft-inc/searchcraft-wordpress
    1212 * 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.1
     13 * Version:           1.0.2
    1414 * Author:            Searchcraft, Inc.
    1515 * Author URI:        https://searchcraft.io/
     
    2727// Define plugin constants.
    2828if ( ! defined( 'SEARCHCRAFT_VERSION' ) ) {
    29     define( 'SEARCHCRAFT_VERSION', '1.0.0' );
     29    define( 'SEARCHCRAFT_VERSION', '1.0.2' );
    3030}
    3131
     
    147147
    148148/**
    149  * Initialize and run the Searchcraft plugin.
     149 * Initialize the Searchcraft plugin.
    150150 *
    151  * This function creates an instance of the main plugin class and starts
    152  * the plugin execution.
     151 * Creates an instance of the main plugin class, which loads dependencies
     152 * and initializes the admin and public-facing components.
    153153 *
    154154 * @since 1.0.0
    155155 */
    156156function run_searchcraft() {
    157     $plugin = new Searchcraft();
    158     $plugin->run();
     157    new Searchcraft();
    159158}
    160159run_searchcraft();
Note: See TracChangeset for help on using the changeset viewer.