Skip to content
This repository has been archived by the owner on Dec 17, 2021. It is now read-only.

Include subtitles in search results; #37 #49

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,18 @@ if ( function_exists( 'get_the_subtitle' ) ) {

An ID isn't necessary for `get_the_subtitle`, but will work for retrieving subtitles from posts that aren't currently being viewed.

---

### Searching Subtitles ###

The plugin will filter search queries to also check the subtitle field in addition to the `post_title` and `post_content` fields, both in the Admin Dashboard and front-end search function. If you wish to disable this functionality, you can do so in your plugin or themes setup file:

```php
if ( class_exists( 'Subtitles' ) && method_exists( 'Subtitles', 'search_subtitles' ) ) {
remove_action( 'pre_get_posts', array( Subtitles::getInstance(), 'search_subtitles' ) );
}
```

## Changelog

All versions of _Subtitles_ can be found on the [Releases](https://github.com/philiparthurmoore/Subtitles/releases) page.
Expand Down
115 changes: 115 additions & 0 deletions public/class-subtitles.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ protected function __construct() {
*/
add_action( 'wp_head', array( &$this, 'subtitle_styling' ) );

/**
* Include Subtitles in search results, in both themes and the admin Dashboard.
*/
add_filter( 'pre_get_posts', array( &$this, 'search_subtitles' ) );

/**
* Filter post titles to display subtitles properly.
*
Expand Down Expand Up @@ -246,6 +251,116 @@ protected function __construct() {
}
} // end method __construct

/**
* Include Subtitles in search queries
*
* This function checks to see if the current query is a search query,
* and if it is then it adds additional query filters to check the
* subtitle field in addition to the post_title and post_content fields.
*
* @link https://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts
* @link https://github.com/philiparthurmoore/Subtitles/issues/37
*/
public function search_subtitles( $query ) {

/**
* Only apply our subtitle query filter if the current query is a search query
*/
if ( $query->is_search ) {

/**
* Filter the query clauses directly
*
* @link https://codex.wordpress.org/Plugin_API/Filter_Reference/posts_clauses
*/
add_filter( 'posts_clauses', array( $this, 'filter_mysql_clauses_for_search' ), 10, 2 );
}

/**
* Make sure to return the query for further use by WordPress;
* No modifications have been made to the query object at this time.
*/
return $query;
}

/**
* Change the MySQL query clauses to include the Subtitles meta field
*
* This function conditionally applies some filters to the $clauses array in order
* to check the Subtitles meta field.
*
* Notes:
* 1. The subtitle field will not be searched if a Meta Query has also
* been set by another plugin or theme.
*
* 2. It would be preferable to avoid altering the query directly, however
* it is not currently possible in WordPress 4.2.2 to perform this type of
* inclusive search query using the available Meta Query parameters.
*
* @link https://codex.wordpress.org/Plugin_API/Filter_Reference/posts_clauses
* @link http://wordpress.stackexchange.com/questions/50305/how-to-extend-wp-query-to-include-custom-table-in-query#answer-50818
* @link https://codex.wordpress.org/Class_Reference/WP_Query
*/
public function filter_mysql_clauses_for_search( $clauses, $query ) {

/**
* Reference the $wpdb object because the names of the tables may change
* in WP Multisite, or depending on how the WordPress installation is configured.
*/
global $wpdb;

/**
* Perform a regex replacement on the WHERE clause.
*
* 1. Perform a regex search for:
* wp_posts.post_title LIKE 'user_search_term'
*
* 2. If found, append an additional clause which looks something like this:
* OR ( wp_postmeta.meta_key = '_subtitle' AND wp_postmeta.meta_value LIKE 'user_search_term' )
*
* This change alters the MySQL query to check not only
* the post_title and post_content fields, but also
* the postmeta field called '_subtitle'. If no match is
* found, the query is unaltered.
*/
$clauses['where'] = preg_replace(
"/\(\s*$wpdb->posts.post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
"($wpdb->posts.post_title LIKE $1) OR ( $wpdb->postmeta.meta_key = '".self::SUBTITLE_META_KEY."' AND $wpdb->postmeta.meta_value LIKE $1 )",
$clauses['where']
);

/**
* Ensure that the query joins the postmeta table, since that is
* where the Subtitle meta values are stored.
*
* Only append our parameters if they do not already exist.
*/
if ( false === strpos($clauses['join'], "$wpdb->postmeta") ) {
$clauses['join'] .= " LEFT JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id) ";
}

/**
* Ensure that our results are grouped by Post ID;
*
* Only append our parameters if they do not already exist.
*/
if ( false === strpos($clauses['groupby'], "$wpdb->posts.ID") ) {
$clauses['groupby'] .= " $wpdb->posts.ID ";
}

/**
* Remove this filter so that it is not run again on other queries
* that are not explicitly search queries. This filter will get re-added
* on each search query, and then removed as soon as the filtering is complete.
*/
remove_filter( 'posts_clauses', array( $this, 'filter_mysql_clauses_for_search' ), 10 );

/**
* Return the modified array of clauses for use by WordPress
*/
return $clauses;
}

/**
* Make sure that Subtitles plays nice with WordPress SEO plugin by Yoast.
*
Expand Down