Skip to content

Instantly share code, notes, and snippets.

@therealgilles
Last active February 4, 2026 04:13
Show Gist options
  • Select an option

  • Save therealgilles/106ddfdfa2dd508cf542807595a3c079 to your computer and use it in GitHub Desktop.

Select an option

Save therealgilles/106ddfdfa2dd508cf542807595a3c079 to your computer and use it in GitHub Desktop.
WP GraphQL Meta Field Ordering
<?php
/**
* Plugin Name: WP GraphQL Meta Field Ordering
* Description: Adds functionality to order by a meta field as specified by the user.
* See: https://gist.github.com/jasonbahl/da87dbccb58f1323a324a9b3e8952d6c
* and also:
* https://github.com/wp-graphql/wp-graphql/issues/287
* https://github.com/wp-graphql/wp-graphql/pull/721
* https://github.com/wp-graphql/wp-graphql-meta-query/blob/develop/wp-graphql-meta-query.php
*/
namespace GQL;
defined( 'ABSPATH' ) || die( 'Direct script access disallowed.' );
/**
* WPGraphQLOrderByMetaField class
*/
class WPGraphQLOrderByMetaField {
/**
* Constructor
*/
public function __construct() {
$class = get_called_class();
add_action(
'graphql_register_types',
array( $class, 'register_types' )
);
add_filter(
'graphql_PostObjectsConnectionOrderbyEnum_values',
array(
$class,
'gql_add_orderby_enum_values',
)
);
add_filter(
'graphql_TermObjectsConnectionOrderbyEnum_values',
array(
$class,
'gql_add_orderby_enum_values',
)
);
add_filter(
'graphql_PostObjectsConnectionOrderbyInput_fields',
array(
$class,
'gql_add_orderby_input_fields',
)
);
add_filter(
'graphql_TermObjectsConnectionOrderbyInput_fields',
array(
$class,
'gql_add_orderby_input_fields',
)
);
add_filter(
'graphql_post_object_connection_query_args',
array( $class, 'gql_object_connection_query_args' ),
10,
5
);
add_filter(
'graphql_term_object_connection_query_args',
array( $class, 'gql_object_connection_query_args' ),
10,
5
);
}
/**
* Register custom GraphQL types.
*/
public static function register_types() {
register_graphql_enum_type(
'MetaKeyTypeEnum',
array(
'description' => __( 'Cast type for META_KEY ordering. Maps to WP_Query meta_type.', 'wp-graphql' ),
'values' => array(
'CHAR' => array( 'value' => 'CHAR' ),
'NUMERIC' => array( 'value' => 'NUMERIC' ),
'DECIMAL' => array( 'value' => 'DECIMAL' ),
'SIGNED' => array( 'value' => 'SIGNED' ),
'UNSIGNED' => array( 'value' => 'UNSIGNED' ),
'DATE' => array( 'value' => 'DATE' ),
'DATETIME' => array( 'value' => 'DATETIME' ),
'TIME' => array( 'value' => 'TIME' ),
'BINARY' => array( 'value' => 'BINARY' ),
),
)
);
}
/**
* Add meta key to orderby field values
*
* @param array $values Existing values
* @return array Returns update values
*/
public static function gql_add_orderby_enum_values( $values ) {
$values['META_KEY'] = array(
'value' => 'META_KEY',
'description' => __( 'META_KEY option to orderby field.', 'wp-graphql' ),
);
return $values;
}
/**
* Add meta key field to orderby fields
*
* @param array $fields Existing fields
* @return array Returns updated fields
*/
public static function gql_add_orderby_input_fields( $fields ) {
$fields['metaKeyField'] = array(
'type' => 'String',
'description' => __( 'META_KEY value for orderby field.', 'wp-graphql' ),
);
$fields['metaKeyType'] = array(
'type' => 'MetaKeyTypeEnum',
'description' => __( 'Cast type for META_KEY ordering. Defaults to CHAR (string comparison).', 'wp-graphql' ),
);
return $fields;
}
/**
* Update WP_Query args for orderby by META_KEY
*
* @param array $query_args Query arguments
* @param mixed $source Source passed down from the resolve tree
* @param array $args The inputArgs on the field
* @param \WPGraphQL\AppContext $context The AppContext passed down the GraphQL tree
* @param \WPGraphQL\ResolveInfo $info The ResolveInfo passed down the GraphQL tree
* @return array Returns updated query arguments
*/
public static function gql_object_connection_query_args(
$query_args,
$source,
$args,
$context,
$info
) {
if ( isset( $args['where']['orderby'] ) && is_array( $args['where']['orderby'] ) ) {
foreach ( $args['where']['orderby'] as $orderby ) {
if (
! isset( $orderby['field'] ) ||
'META_KEY' !== $orderby['field'] ||
! isset( $orderby['metaKeyField'] )
) {
continue;
}
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
$query_args['meta_key'] = $orderby['metaKeyField'];
// Extract the order direction from WPGraphQL's processed orderby
// array (e.g. ['META_KEY' => 'DESC']) before we overwrite it below.
// See: https://developer.wordpress.org/reference/classes/wp_query/#order-orderby-parameters
$query_args['order'] = isset( $query_args['orderby']['META_KEY'] )
? $query_args['orderby']['META_KEY']
: 'DESC';
// Use meta_value_num for numeric types, meta_value for everything else.
$meta_type = ! empty( $orderby['metaKeyType'] ) ? strtoupper( $orderby['metaKeyType'] ) : '';
$numeric_types = array( 'NUMERIC', 'DECIMAL', 'SIGNED', 'UNSIGNED' );
$query_args['orderby'] = in_array( $meta_type, $numeric_types, true )
? 'meta_value_num'
: 'meta_value';
if ( $meta_type ) {
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_type
$query_args['meta_type'] = $meta_type;
}
}
}
return $query_args;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment