Location: PHPKode > scripts > wpSearch > wpsearch/WPSearch/Core.php
<?php
/**
 * This file acts as the 'Controller' of the application. It contains a class
 *  that will load the required hooks, and the callback functions that those
 *  hooks execute.
 *
 * @author Kenny Katzgrau <hide@address.com>
 */

require_once dirname(__FILE__) . '/Ajax.php';
require_once dirname(__FILE__) . '/Config.php';
require_once dirname(__FILE__) . '/Document.php';
require_once dirname(__FILE__) . '/Benchmark.php';
require_once dirname(__FILE__) . '/Log.php';
require_once dirname(__FILE__) . '/Model.php';
require_once dirname(__FILE__) . '/Net.php';
require_once dirname(__FILE__) . '/Search.php';
require_once dirname(__FILE__) . '/Utility.php';
require_once dirname(__FILE__) . '/View.php';
require_once dirname(__FILE__) . '/Drivers/Search.php';
require_once dirname(__FILE__) . '/Exception.php';

if (! class_exists('WPSearch_Core')):

/**
 * This class contains the core code and callback for the behavior of Wordpress.
 *  It is instantiated and executed directly by the WPSearch plugin loader file
 *  (which is most likely at the root of the WPSearch installation).
 */
class WPSearch_Core
{
    CONST KEY_INDEX_CATEGORIES    = 'WPSearch_Index_Categories';
    CONST KEY_INDEX_COMMENTS      = 'WPSearch_Index_Comments';
    CONST KEY_INDEXED_CATEGORIES  = 'WPSearch_Indexed_Categories';
    CONST KEY_INDEXED_COMMENTS    = 'WPSearch_Indexed_Comments';
    CONST KEY_INSTALL_REPORT      = 'WPSearch_Install_Report';
    CONST KEY_LAST_MESSAGE        = 'WPSearch_Last_Message';
    CONST KEY_LAST_MESSAGE_DATE   = 'WPSearch_Last_Message_Date';
    CONST KEY_TITLE_BOOST         = 'WPSearch_Key_Title_Boost';
    CONST KEY_CONTENT_BOOST       = 'WPSearch_Key_Content_Boost';
    CONST KEY_SEARCH_TYPES        = 'WPSearch_Key_Search_Types';

    CONST DEFAULT_TITLE_BOOST     = 50;
    CONST DEFAULT_CONTENT_BOOST   = 30;

    CONST DEFAULT_BASE_LOW        = 0;
    CONST DEFAULT_BASE_HIGH       = 100;

    public static $_defaultSearchTypes = array ('post', 'page');

    public static $_page          = 0;
    public static $_perPage       = 10;

    private static $_addPostHookRan  = FALSE;
    private static $_editPostHookRan = FALSE;

    /**
     * The constructor
     */
    public function __construct()
    {
        WPSearch_Log::add('debug', "WPSearch initializing..");
    }

    /**
     * Get the WPSearch environment loaded and register Wordpress hooks
     */
    public function execute()
    {
        $this->_registerHooks();
    }

    /**
     * Register Wordpress hooks required for WPSearch
     */
    private function _registerHooks()
    {
        WPSearch_Log::add('debug', "Registering hooks..");

        # -- Below is core functionality --
        # TODO: Find out if the below is needed
        add_action('edit_post', 	array($this, 'editCallback'  ));
        add_action('delete_post', 	array($this, 'deleteCallback'    ));
        add_action('publish_post', 	array($this, 'postCallback'      ));
        add_action('publish_page', 	array($this, 'pageCallback'      ));
        add_action('admin_menu', 	array($this, 'adminCallback'     ));
        add_action('admin_init', 	array($this, 'adminInitCallback' ));
        add_action('admin_notices',     array($this, 'adminWarningCallback'));
        add_filter('posts_where', 	array($this, 'searchCallback'    ));
        add_filter('post_limits', 	array($this, 'limitCallback'     ));
        add_filter('the_posts', 	array($this, 'queryCallback'     ));

        # -- Below is administration AJAX functionality
        add_action('wp_ajax_get_stats',              array('WPSearch_Ajax', 'getStats'));
        add_action('wp_ajax_save_index_comments'   , array('WPSearch_Ajax', 'saveIndexComments'));
        add_action('wp_ajax_save_index_categories' , array('WPSearch_Ajax', 'saveIndexCategories'));
        add_action('wp_ajax_save_title_boost'      , array('WPSearch_Ajax', 'saveTitleBoost'));
        add_action('wp_ajax_save_content_boost'    , array('WPSearch_Ajax', 'saveContentBoost'));
        add_action('wp_ajax_save_search_types'     , array('WPSearch_Ajax', 'saveSearchTypes'));
        add_action('wp_ajax_rebuild_index'         , array('WPSearch_Ajax', 'rebuildIndex'));
        add_action('wp_ajax_search'                , array('WPSearch_Ajax', 'search'));
        add_action('wp_ajax_nopriv_search'         , array('WPSearch_Ajax', 'search'));
    }

    /**
     * A callback called whenever a post is edited or commented on
     * @param int $postId The id of the post/page
     */
    public function editCallback($postId)
    {
        WPSearch_Log::add('debug', "Edit post callback executed for post #$postId");
        if(self::$_addPostHookRan) return;
        WPSearch_Search::instance()->addToIndex($postId);
        self::$_editPostHookRan = TRUE;
    }

    /**
     * A callback executed whenever a post/page is deleted
     * @param int $postId
     */
    public function deleteCallback($postId)
    {
        WPSearch_Log::add('debug', "Page/Post delete callback executed for post #$postId");
        WPSearch_Search::instance()->removeFromIndex($postId);
    }

    /**
     * A callback executed wheeever a post is posted
     * @param int $postId
     */
    public function postCallback($postId)
    {
        WPSearch_Log::add('debug', "Post published callback executed for post #$postId");
        if(self::$_editPostHookRan) return;
        WPSearch_Search::instance()->addToIndex($postId);
        self::$_addPostHookRan = TRUE;
    }

    /**
     * A callback executed whenever a page is published
     * @param int $postId
     */
    public function pageCallback($postId)
    {
        WPSearch_Log::add('debug', "Page published callback executed for post #$postId");
        WPSearch_Search::instance()->addToIndex($postId);
    }

    /**
     * A callback executed whenever the user tried to access the WPSearch admin page
     */
    public function adminCallback()
    {
        add_options_page('WPSearch Settings', 'WPSearch 2', 'edit_pages', 'wpsearch/wpsearch.php', array($this, 'adminMenuCallback'));
    }

    /**
     * Emit a warning that the search index hasn't been built (if it hasn't)
     */
    public function adminWarningCallback()
    {
        $stats = WPSearch_Search::instance()->getStats();

        if(!$stats->last_rebuild)
            WPSearch_View::load('_buildWarning');
    }

    /**
     * A callback executed when the admin page callback is a about to be called.
     *  Use this for loading stylesheets/css.
     */
    public function adminInitCallback()
    {
        # Only register javascript and css if the wpsearch admin page is loading
        if(strstr($_SERVER['QUERY_STRING'], 'wpsearch') === FALSE) return;

        wp_enqueue_style ('wpsearch-styles',  WPSearch_Utility::getCSSBaseURL() . 'wpsearch.css');
        wp_enqueue_style ('jquery-theme',    'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css');
        wp_enqueue_style ('multisel-styles',  WPSearch_Utility::getCSSBaseURL() . 'jquery.multiselect.css');
        wp_enqueue_script('wpsearch-timers',  WPSearch_Utility::getJSBaseURL().'jquery.timers-1.2.js');
        wp_enqueue_script('wpsearch-slider',  'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js');
        wp_enqueue_script('wpsearch-multis',  WPSearch_Utility::getJSBaseURL().'jquery.multiselect.min.js');
        wp_enqueue_script('wpsearch-main'  ,  WPSearch_Utility::getJSBaseURL().'wpsearch.js');
    }

    /**
     * A callback executed whenever Wordpress is building the WHERE clause for
     *  a search. The goal here is to append a condition which could never be
     *  possible (0 = 1) so MySQL instantly returns an empty result set.
     *
     * This will clear the way for inserting our own results.
     * 
     * @param string $where The original WHERE clause
     * @return string The impossible WHERE clause
     */
    public function searchCallback($where)
    {
        if(! WPSearch_Search::instance()->isReady()) return $where;
        
        # Cut off the default Wordpress SQL search
        if (is_search() && !is_admin())
        {
            $where = "AND (0=1)";
        }

    	return $where;
    }

    /**
     * Parse out the limit and offset values from the limit clause. We'll use
     *  this to figure out with page number we need to grab, and how many
     *  results we should find. We'll then store them as class variables for
     *  future use.
     * 
     * @param string $limit_clause
     * @return string The same limit clause
     */
    public function limitCallback($limit_clause)
    {
        if(! WPSearch_Search::instance()->isReady()) return $limit_clause;
        # Parse out the range of search items to retreive
        if(is_search() && !is_admin())
        {
            WPSearch_Log::add('debug', "Query limit callback executed");
            
            $limit                      = str_replace("LIMIT", "", $limit_clause);
            list($offset, $limit) 		= split(",", $limit);

            $offset = intval($offset);
            $limit  = intval($limit);

            self::$_page    = $offset / $limit;
            self::$_perPage = $limit;
        }

        return $limit_clause;
    }

    /**
     * 
     * @global object $wp_query The Wordpress query object (available from the Wordpress env.)
     * @global object $wp The Wordpress super-oobject, also available from the Wordpress env.
     * @param array $posts The array of posts Wordpress found originall. This should be empty
     *   from the LIMIT clause manipulation hook
     * @return array[WPSearch_Document] An array of objects that maintain all of the
     *   properties expected of the Wordpress search results
     */
    public function queryCallback($posts)
    {
        if(!is_search() || is_admin()) return $posts;

        WPSearch_Log::add('debug', "Search callback executed");

        global $wp_query; # Think I like doing this? You're off your rocker
	global $wp;       # Wp super object
        
        $term = array();
        $term['q']        = $wp->query_vars["s"]; # The search term
        $term['page']     = self::$_page;
        $term['per_page'] = self::$_perPage;

        $category_id = WPSearch_Utility::arrayGet($_GET, 'c_id', FALSE);

        if($category_id !== FALSE) $term['category_id'] = $category_id;

        if(! WPSearch_Search::instance()->isReady())
        {
            WPSearch_Log::add('debug', "Search is in execution for term '{$term['q']}', but the driver is either not installed or indexing."
                                      ." Falling back to Wordpress search..");
            return $posts;
        }

        $count_per_page = self::$_perPage;

        $posts = array(); # Empty what should be an empty array

        WPSearch_Log::add('debug', "Grabbing term from Wordpress query variabled ({$term['q']})");

        try
        {
            $result = WPSearch_Search::instance()->search($term, self::$_page, self::$_perPage);
            $wp_query->found_posts   = count($result->hits);
            $wp_query->max_num_pages = ceil($result->total / $count_per_page);

            WPSearch_Log::add('debug', "Total number of posts found: {$result->total}");
            WPSearch_Log::add('debug', "Set Wordpress vars - # Retrieved posts for page, {$wp_query->found_posts}; # Pages, {$wp_query->max_num_pages}");
            return $result->hits;
        }
        catch (Exception $ex)
        {
            $wp_query->found_posts   = 0;
            $wp_query->max_num_pages = 0;
            WPSearch_Log::add('error', "There was an error searching the index!" . $ex->__toString());
            return array();
        }
    }

    /**
     * The callback that is executed when the user is loading the admin page.
     *  Basically, output the page content for the admin page. The function
     *  acts just like a controller method for and MVC app. That is, it loads
     *  a view.
     */
    public function adminMenuCallback()
    {
        WPSearch_Log::add('debug', "Admin page callback executed");
        WPSearch_Utility::sendInstallReportIfNew();

        $stats   = WPSearch_Search::instance()->getStats();
        $about   = WPSearch_Search::instance()->getAbout();
        $errors  = WPSearch_Search::instance()->runTests();
        
        $search_types = unserialize(WPSearch_Utility::getOption(self::KEY_SEARCH_TYPES, FALSE));
        $search_types = ($search_types !== FALSE ? $search_types : self::$_defaultSearchTypes);
        
        $data = array();

        if($about)
        {
            $data['is_alive']          = true;
            $data['total_docs']        = $stats->total;
            $data['indexed_docs']      = $stats->current;
            $data['is_building']       = $stats->reindexing;
            $data['last_reindex']      = $stats->last_rebuild;
            $data['about']             = $about;
            $data['errors']            = $errors;
            $data['searched_types']    = $search_types;
            $data['post_types']        = get_post_types();
            $data['index_comments']    = (WPSearch_Utility::getOption(self::KEY_INDEX_COMMENTS)    == 'true');
            $data['index_categories']  = (WPSearch_Utility::getOption(self::KEY_INDEX_CATEGORIES)  == 'true');
            $data['indexed_comments']  = (WPSearch_Utility::getOption(self::KEY_INDEXED_COMMENTS)  == 'true');
            $data['indexed_categories']= (WPSearch_Utility::getOption(self::KEY_INDEXED_CATEGORIES)== 'true');
            $data['title_boost']       = (WPSearch_Utility::getOption(self::KEY_TITLE_BOOST, self::DEFAULT_TITLE_BOOST));
            $data['content_boost']     = (WPSearch_Utility::getOption(self::KEY_CONTENT_BOOST, self::DEFAULT_CONTENT_BOOST));
            $data['service_tag']       = WPSearch_Utility::getServiceTag();
        }
        else
        {
            $data['is_alive']     = false;
            $data['error_message']= 'The backend WPSearch Driver is not responding.';
        }

        WPSearch_View::load('admin', $data);
    }
}

endif;
Return current item: wpSearch