Skip to content

Instantly share code, notes, and snippets.

@a-barbieri
Last active October 6, 2021 09:37
Show Gist options
  • Save a-barbieri/7802dee5938fee53e6f1a5cbd6f81cca to your computer and use it in GitHub Desktop.
Save a-barbieri/7802dee5938fee53e6f1a5cbd6f81cca to your computer and use it in GitHub Desktop.
WP_GraphQL Relevanssi Plugin

WP_GraphQL Relevanssi Plugin

A plugin to enable Relevanssi research through WP_GraphQL.

Requirements

This plugin requires Relevanssi >= 4.6.0 and WP_GraphQL >= 0.8.0.

GraphQL query format

If you want to retrieve all posts slugs that somehow contains the word "blu":

{
  postsSearch(where: {search: "blu"}) {
    edges {
      node {
        slug
      }
    }
  }
}

This obviously works with the entire post parameters (id, content, categories and so on).

You can target one post type at the time. Look at the examples: you can find the default post or the custom post type (which uses Document as an example).

In case you want the query would be:

{
  documentsSearch(where: {search: "blu"}) {
    edges {
      node {
        slug
      }
    }
  }
}

TODO

  1. Check if post_type parameters are consistent with Relevanssi configuration. Currently we assume the query will target the same post types added to Relevanssi configuration.
  2. Check if Relevanssi plugin has been enabled.

Known issues

Relevanssi is required!

Make sure Relevanssi plugin is active! The plugin currently doesn't check that.

I cannot see all results

By default GraphQL limits the number of posts. There is currently no way to avoid this limit and it's not suggested. You don't want a all parameter. You can find more on GraphQL pagination here.

A good compromise is to set the query to a reasonable number:

{
  postsSearch(first:25, where: {search: "blu"}) {
    ...
}

If you need to debug the plugin you can drop this method anywhere in the WP GraphQL functions:

// Use this to debug:
// it stops the function and dumps a value instead of the query result.
ob_start();
var_dump( $the_variable_you_want_to_debug );
$dump = ob_get_clean();
wp_send_json( $dump );

Resources

<?php
use WPGraphQL\Data\DataSource;
add_action( 'graphql_register_types', 'register_post_relevanssi_graphql_connection', 99 );
function register_post_relevanssi_graphql_connection() {
require_once('relevanssi-connection.php');
$config = [
'fromType' => 'RootQuery',
// WARNING: make sure post_type setup follows your Relevanssi configuration.
'toType' => 'Post',
'fromFieldName' => 'postsSearch',
'connectionTypeName' => 'PostsFromRelevanssiQueryConnection',
'resolve' => function( $id, $args, $context, $info ) {
// Resolve the query:
$resolver = new RelevanssiConnectionResolver( $source, $args, $context, $info, 'post' );
return $resolver->get_connection();
},
'connectionArgs' => [
'search' => [
'name' => 'search',
'type' => 'String',
'description' => __( 'Show Posts based on a keyword search', 'wp-graphql' ),
]
]
];
register_graphql_connection( $config );
};
<?php
// If you need to declare a custom post type to be used on WP GraphQL uncomment the following code:
//
// add_action( 'init', function() {
// register_post_type( 'docs', [
// 'show_ui' => true,
// 'labels' => [
// 'menu_name' => __( 'Docs', 'your-textdomain' ),//@see https://developer.wordpress.org/themes/functionality/internationalization/
// ],
// 'show_in_graphql' => true,
// 'hierarchical' => true,
// 'graphql_single_name' => 'Document',
// 'graphql_plural_name' => 'Documents',
// ] );
// }, 0 );
use WPGraphQL\Data\DataSource;
add_action( 'graphql_register_types', 'register_document_relevanssi_graphql_connection', 99 );
function register_document_relevanssi_graphql_connection() {
require_once( plugin_dir_path( __FILE__ ) . 'relevanssi-connection-resolver.php');
$config = [
// WARNING: make sure this setup follows your Relevanssi configuration.
// WARNING: change every `Document` or `document` in this file according to your custom post type settings
'fromType' => 'RootQuery',
'toType' => 'Document',
'fromFieldName' => 'DocumentSearch',
'connectionTypeName' => 'DocumentFromRelevanssiQueryConnection',
'resolve' => function( $id, $args, $context, $info ) {
// Resolve the query:
$resolver = new RelevanssiConnectionResolver( $source, $args, $context, $info, 'document' );
return $resolver->get_connection();
},
'connectionArgs' => [
'search' => [
'name' => 'search',
'type' => 'String',
'description' => __( 'Show Posts based on a keyword search', 'wp-graphql' ),
]
]
];
register_graphql_connection( $config );
};
<?php
class RelevanssiConnectionResolver extends PostObjectConnectionResolver {
/**
* @return \WP_Query
*/
public function get_query() {
$query = new \WP_Query();
$query->parse_query( array( "s" => $this->query_args['s'] ) );
$search_results = relevanssi_do_query( $query );
// Get an array of IDs and add it to the query arguments
$ids = wp_list_pluck( $search_results, 'ID' );
// Update the query to ensure results correspond to Relevanssi ones
$this->query_args['post__in'] = $ids;
// Keep Relevanssi order
$this->query_args['orderby'] = 'post__in';
// Avoid default WP pagination limit (this will ensure the limit is set by WPGraphQL)
$this->query_args['posts_per_page'] = count($ids);
// Remove search parameter to avoid breaking the query ("s" triggers the default WP_Query search which is not what we want).
unset($this->query_args["s"]);
// Generate a new query in order to be digested by the resolver
$updated_query = new \WP_Query( $this->query_args );
return $updated_query;
}
}
<?php
/*
Plugin Name: WP_GraphQL Relevanssi Plugin
Description: A plugin to enable Relevanssi research through WP_GraphQL
Version: 0.0.2
Author: Alessandro Barbieri
Author URI: https://lacolonia.studio
License: GPL2
License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/
// https://docs.wpgraphql.com/extending/types/
// https://github.com/wp-graphql/wp-graphql/blob/75062206a59ce57f1e29157e63f09db8a8c40ce4/vendor/webonyx/graphql-php/src/Executor/ExecutionResult.php
// https://github.com/webonyx/graphql-php/blob/df1b575469cb005b17088f0dcdf4d4543f7abac4/docs/error-handling.md#custom-error-handling-and-formatting
// https://github.com/wp-graphql/wp-graphql/issues/1185
// https://codex.wordpress.org/Writing_a_Plugin#Plugin_Files
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
require_once( plugin_dir_path( __FILE__ ) . 'default-post-relevanssi.php');
// Use this template if you need to apply Relevanssi on your custom post types.
// require_once( plugin_dir_path( __FILE__ ) . 'document-post-type-relevanssi.php');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment