msaari / relevanssi-light

Relevanssi Light fulltext search
17 stars 1 forks source link

Extending to support custom post types #4

Closed ottok closed 4 years ago

ottok commented 4 years ago

Here is an example of how WordPress search can be extended to cover custom post meta fields:

if ( ! class_exists( 'Seravo_Search' ) ) {

  /**
   * Class Seravo_Partners
   *
   * @author Seravo Oy
   */
  class Seravo_Search {

    /**
     * Join posts and postmeta tables
     *
     * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_join
     */
    public static function postmeta_search_join( $join ) {
      global $wpdb;

      if ( is_search() ) {
        $join .= ' LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts .
                 '.ID = ' . $wpdb->postmeta . '.post_id ';
      }

      return $join;
    }

    /**
     * Modify the search query with posts_where
     *
     * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_where
     */
    public static function postmeta_search_where( $where ) {
      global $pagenow, $wpdb;

      if ( is_search() ) {
        $where = preg_replace(
          "/\(\s*" . $wpdb->posts . ".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
          "(" . $wpdb->posts . ".post_title LIKE $1) OR (" . $wpdb->postmeta .
          ".meta_value LIKE $1)", $where
        );
      }

      return $where;
    }

    /**
     * Prevent duplicates
     *
     * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_distinct
     */
    public static function postmeta_search_distinct( $where ) {
      global $wpdb;

      if ( is_search() ) {
        return 'DISTINCT';
      }

      return $where;
    }

  }
}

This is however completely incompatible with the basic technique to do FULLTEXT search now in your (and others) plugin.

It could be nice to come up with a way to extend the FULLTEXT search to either allow the custom post searches (in the old way as done above) and absolutely cool if there was a way to apply the FULLTEXT search on the custom post type searches as well (indexing wp_postmeta meta_value column.

msaari commented 4 years ago

This is one of the tricky parts indeed. It would be splendid to be able to combine data from two tables to one FULLTEXT index, but since that's not possible, my current idea for this is to add a new column to the wp_posts table.

That column can be indexed for the FULLTEXT index, and a filter function can be used to fetch any content related to the post. That way custom field data can be included in the index (and you can easily massage the data to pick the parts you want; usually it's not a good idea to index all custom field content as often a large part of it is metadata that's just garbage in searches), and it'll give plenty of flexibility.

The downside is the need to add a new column to the wp_posts database table which is rarely the best approach, but here I think it's reasonable and more importantly the only solution. Also, the column will only hold computed values and no original data, which means it doesn't matter if it's not picked up by backups and so on.

(It's a bit of a can of worms, though. If updating the column is triggered on post save, there should probably be a method of updating the column for all existing posts and that's already going into indexing territory this plugin was supposed to avoid in the first place. It would probably be fairly easy to write a WP CLI command to seed the column, but unfortunately WP CLI availability is limited...)