diff --git a/README.md b/README.md index eb6dee43..bfa8bd02 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ [![Build Status](https://travis-ci.org/simplur/ql-events.svg?branch=develop)](https://travis-ci.org/simplur/ql-events) [![Coverage Status](https://coveralls.io/repos/github/simplur/ql-events/badge.svg?branch=develop)](https://coveralls.io/github/simplur/ql-events?branch=develop) ## Quick Install -1. Install & activate [The Events Calendar/The Events Calendar Prop](https://woocommerce.com/) - - (Optional) Install & activate [Ticket Events/Ticket Events Pro](https://woocommerce.com/) +1. Install & activate [The Events Calendar/The Events Calendar Pro](https://theeventscalendar.com/) + - (Optional) Install & activate [Ticket Events/Ticket Events Plus](https://theeventscalendar.com/products/wordpress-event-tickets/) 2. Install & activate [WPGraphQL](https://www.wpgraphql.com/) - (Optional) Install & activate [WPGraphQL-JWT-Authentication](https://github.com/wp-graphql/wp-graphql-jwt-authentication) to add a `login` mutation that returns a JSON Web Token. 3. Clone or download the zip of this repository into your WordPress plugin directory & activate the **QL Events** plugin diff --git a/includes/class-core-schema-filters.php b/includes/class-core-schema-filters.php index 93fbba65..7383f864 100644 --- a/includes/class-core-schema-filters.php +++ b/includes/class-core-schema-filters.php @@ -75,6 +75,33 @@ public static function add_filters() { 10, 5 ); + + add_filter( + 'graphql_post_object_connection_query_args', + array( + '\WPGraphQL\QL_Events\Data\Connection\RSVPAttendee_Connection_Resolver', + 'get_query_args', + ), + 10, + 5 + ); + + add_filter( + 'graphql_post_object_connection_query_args', + array( + '\WPGraphQL\QL_Events\Data\Connection\PayPalAttendee_Connection_Resolver', + 'get_query_args', + ), + 10, + 5 + ); + + add_filter( + 'graphql_input_fields', + array( __CLASS__, 'attendees_where_args' ), + 10, + 2 + ); } if ( \QL_Events::is_ticket_events_plus_loaded() ) { @@ -97,6 +124,23 @@ public static function add_filters() { 10, 6 ); + + add_filter( + 'graphql_post_object_connection_query_args', + array( + '\WPGraphQL\QL_Events\Data\Connection\WooAttendee_Connection_Resolver', + 'get_query_args', + ), + 10, + 5 + ); + + add_filter( + 'graphql_input_fields', + array( __CLASS__, 'ticket_plus_attendees_where_args' ), + 10, + 2 + ); } } @@ -201,4 +245,47 @@ public static function events_where_args( $fields = array(), $type_name ) { } return $fields; } + + /** + * Adds "where" arguments to Attendees connections + * + * @param array $fields Attendees where args. + * @param string $type_name Connection "where" input type name. + * + * @return array + */ + public static function attendees_where_args( $fields = array(), $type_name ) { + if ( self::ends_with( $type_name, 'RSVPAttendeeConnectionWhereArgs' ) ) { + $fields = array_merge( + $fields, + \WPGraphQL\QL_Events\Connection\RSVPAttendees::where_args() + ); + } + + if ( self::ends_with( $type_name, 'PayPalAttendeeConnectionWhereArgs' ) ) { + $fields = array_merge( + $fields, + \WPGraphQL\QL_Events\Connection\PayPalAttendees::where_args() + ); + } + return $fields; + } + + /** + * Adds "where" arguments to WooAttendee connections + * + * @param array $fields WooAttendee where args. + * @param string $type_name Connection "where" input type name. + * + * @return array + */ + public static function ticket_plus_attendees_where_args( $fields = array(), $type_name ) { + if ( self::ends_with( $type_name, 'WooAttendeeConnectionWhereArgs' ) ) { + $fields = array_merge( + $fields, + \WPGraphQL\QL_Events\Connection\WooAttendees::where_args() + ); + } + return $fields; + } } diff --git a/includes/class-type-registry.php b/includes/class-type-registry.php index e58cd37b..2d127463 100644 --- a/includes/class-type-registry.php +++ b/includes/class-type-registry.php @@ -39,6 +39,8 @@ public function init( \WPGraphQL\Registry\TypeRegistry $type_registry ) { // Event Tickets Connections. \WPGraphQL\QL_Events\Connection\Tickets::register_connections(); + \WPGraphQL\QL_Events\Connection\RSVPAttendees::register_connections(); + \WPGraphQL\QL_Events\Connection\PayPalAttendees::register_connections(); } if ( \QL_Events::is_ticket_events_plus_loaded() ) { @@ -47,6 +49,8 @@ public function init( \WPGraphQL\Registry\TypeRegistry $type_registry ) { // Event Tickets Plus Connections. \WPGraphQL\QL_Events\Connection\Tickets_Plus::register_connections(); + \WPGraphQL\QL_Events\Connection\WooAttendees::register_connections(); + } } } diff --git a/includes/connection/class-paypalattendees.php b/includes/connection/class-paypalattendees.php new file mode 100644 index 00000000..58d202d0 --- /dev/null +++ b/includes/connection/class-paypalattendees.php @@ -0,0 +1,45 @@ + 'Event', + 'toType' => 'PayPalAttendee', + 'fromFieldName' => 'payPalAttendees', + ) + ) + ); + } + + public static function where_args() { + return array( + 'eventsIn' => array( + 'type' => array( 'list_of' => 'ID'), + 'description' => __( 'Filter the connection based on event Id'), + ) + ); + } +} diff --git a/includes/connection/class-attendees.php b/includes/connection/class-rsvpattendees.php similarity index 56% rename from includes/connection/class-attendees.php rename to includes/connection/class-rsvpattendees.php index 60ef7ec8..ab1ac52e 100644 --- a/includes/connection/class-attendees.php +++ b/includes/connection/class-rsvpattendees.php @@ -1,8 +1,8 @@ 'Event', - 'toType' => 'Attendee', - 'fromFieldName' => 'attendees', + 'toType' => 'RSVPAttendee', + 'fromFieldName' => 'rSVPAttendees', ) ) ); } + + public static function where_args() { + return [ + 'eventsIn' => [ + 'type' => [ 'list_of' => 'ID' ], + 'description' => __( 'Filter the connection based on event Id', 'ql-events' ), + ] + ]; + } } diff --git a/includes/connection/class-wooattendees.php b/includes/connection/class-wooattendees.php new file mode 100644 index 00000000..b48dfe25 --- /dev/null +++ b/includes/connection/class-wooattendees.php @@ -0,0 +1,45 @@ + 'Event', + 'toType' => 'WooAttendee', + 'fromFieldName' => 'wooAttendees', + ] + ) + ); + } + + public static function where_args() { + return [ + 'eventsIn' => [ + 'type' => [ 'list_of' => 'ID' ], + 'description' => __( 'Filter the connection based on event Id', 'ql-events' ), + ] + ]; + } +} diff --git a/includes/data/connection/class-paypalattendee-connection-resolver.php b/includes/data/connection/class-paypalattendee-connection-resolver.php new file mode 100644 index 00000000..e3f25750 --- /dev/null +++ b/includes/data/connection/class-paypalattendee-connection-resolver.php @@ -0,0 +1,112 @@ +source get set, and where mapping the input $args to the actual $query_args occurs. + * + * @param array $query_args - WP_Query args. + * @param mixed $source - Connection parent resolver. + * @param array $args - Connection arguments. + * @param AppContext $context - AppContext object. + * @param ResolveInfo $info - ResolveInfo object. + * + * @return mixed + */ + public static function get_query_args( $query_args, $source, $args, $context, $info ) { + + /** + * Collect the input_fields and sanitize them to prepare them for sending to the WP_Query + */ + $input_fields = array(); + if ( ! empty( $args['where'] ) ) { + $input_fields = self::sanitize_input_fields( $args['where'] ); + } + + if ( ! empty( $input_fields ) ) { + $query_args = array_merge( $query_args, $input_fields ); + } + + // Determine where we're at in the Graph and adjust the query context appropriately. + // @Todo: this was left over from class-attendee-connection-resolver.php which wasnt loaded. May not be necessary. + if ( true === is_object( $source ) ) { + + switch ( $source->post_type ) { + case Main::POSTTYPE: + // @codingStandardsIgnoreLine + if ( 'payPalAttendees' === $info->fieldName ) { + if ( ! isset( $query_args['meta_query'] ) ) { + $query_args['meta_query'] = []; // WPCS: slow query ok. + } + $query_args['meta_query'][] = [ + 'key' => PAYPAL::ATTENDEE_EVENT_KEY, + 'value' => $source->ID, + 'compare' => '=', + ]; + } + break; + } + // @codingStandardsIgnoreLine + + } + + $query_args = apply_filters( + 'graphql_paypal_attendee_connection_query_args', + $query_args, + $source, + $args, + $context, + $info + ); + + return $query_args; + } + + /** + * This sets up the "allowed" args, and translates the GraphQL-friendly keys to WP_Query + * friendly keys. There's probably a cleaner/more dynamic way to approach this, but + * this was quick. I'd be down to explore more dynamic ways to map this, but for + * now this gets the job done. + * + * @since 0.0.5 + * @access private + * + * @param array $args Where argument input. + * + * @return array + */ + + private static function sanitize_input_fields( $args ){ + $query_args = array(); + + if ( !empty( $args['eventsIn'])){ + $query_args['meta_query'] = array(); // WPCS: slow query ok. + $query_args['meta_query'][] = array( + 'key' => PAYPAL::ATTENDEE_EVENT_KEY, + 'value' => $args['eventsIn'], + 'compare' => 'IN', + ); + } + + return $query_args; + } +} diff --git a/includes/data/connection/class-attendee-connection-resolver.php b/includes/data/connection/class-rsvpattendee-connection-resolver.php similarity index 53% rename from includes/data/connection/class-attendee-connection-resolver.php rename to includes/data/connection/class-rsvpattendee-connection-resolver.php index b61d3a2e..3d39c2d6 100644 --- a/includes/data/connection/class-attendee-connection-resolver.php +++ b/includes/data/connection/class-rsvpattendee-connection-resolver.php @@ -1,8 +1,8 @@ source get set, and where mapping the input $args to the actual $query_args occurs. @@ -33,13 +33,28 @@ class Attendee_Connection_Resolver { * @return mixed */ public static function get_query_args( $query_args, $source, $args, $context, $info ) { - $rsvp = RSVP::get_instance(); + + /** + * Collect the input_fields and sanitize them to prepare them for sending to the WP_Query + */ + $input_fields = array(); + if ( ! empty( $args['where'] ) ) { + $input_fields = self::sanitize_input_fields( $args['where'] ); + } + + if ( ! empty( $input_fields ) ) { + $query_args = array_merge( $query_args, $input_fields ); + } + // Determine where we're at in the Graph and adjust the query context appropriately. + // @Todo: this was left over from class-attendee-connection-resolver.php which wasnt loaded. May not be necessary. if ( true === is_object( $source ) ) { + + switch ( $source->post_type ) { case Main::POSTTYPE: // @codingStandardsIgnoreLine - if ( 'attendees' === $info->fieldName ) { + if ( 'rsvpAttendees' === $info->fieldName ) { if ( ! isset( $query_args['meta_query'] ) ) { $query_args['meta_query'] = array(); // WPCS: slow query ok. } @@ -64,6 +79,35 @@ public static function get_query_args( $query_args, $source, $args, $context, $i $info ); + return $query_args; + } + + /** + * This sets up the "allowed" args, and translates the GraphQL-friendly keys to WP_Query + * friendly keys. There's probably a cleaner/more dynamic way to approach this, but + * this was quick. I'd be down to explore more dynamic ways to map this, but for + * now this gets the job done. + * + * @since 0.0.5 + * @access private + * + * @param array $args Where argument input. + * + * @return array + */ + + private static function sanitize_input_fields( $args ){ + $query_args = []; + + if ( ! empty( $args['eventsIn'] ) ) { + $query_args['meta_query'] = []; // WPCS: slow query ok. + $query_args['meta_query'][] = [ + 'key' => RSVP::ATTENDEE_EVENT_KEY, + 'value' => $args['eventsIn'], + 'compare' => 'IN', + ]; + } + return $query_args; } } diff --git a/includes/data/connection/class-wooattendee-connection-resolver.php b/includes/data/connection/class-wooattendee-connection-resolver.php new file mode 100644 index 00000000..88fe3f16 --- /dev/null +++ b/includes/data/connection/class-wooattendee-connection-resolver.php @@ -0,0 +1,112 @@ +source get set, and where mapping the input $args to the actual $query_args occurs. + * + * @param array $query_args - WP_Query args. + * @param mixed $source - Connection parent resolver. + * @param array $args - Connection arguments. + * @param AppContext $context - AppContext object. + * @param ResolveInfo $info - ResolveInfo object. + * + * @return mixed + */ + public static function get_query_args( $query_args, $source, $args, $context, $info ) { + + /** + * Collect the input_fields and sanitize them to prepare them for sending to the WP_Query + */ + $input_fields = array(); + if ( ! empty( $args['where'] ) ) { + $input_fields = self::sanitize_input_fields( $args['where'] ); + } + + if ( ! empty( $input_fields ) ) { + $query_args = array_merge( $query_args, $input_fields ); + } + + // Determine where we're at in the Graph and adjust the query context appropriately. + // @Todo: this was left over from class-attendee-connection-resolver.php which wasnt loaded. May not be necessary. + if ( true === is_object( $source ) ) { + + + switch ( $source->post_type ) { + case Main::POSTTYPE: + // @codingStandardsIgnoreLine + if ( 'wooAttendees' === $info->fieldName ) { + if ( ! isset( $query_args['meta_query'] ) ) { + $query_args['meta_query'] = []; // WPCS: slow query ok. + } + $query_args['meta_query'][] = [ + 'key' => WOO::ATTENDEE_EVENT_KEY, + 'value' => $source->ID, + 'compare' => '=', + ]; + } + break; + } + } + + $query_args = apply_filters( + 'graphql_woo_attendee_connection_query_args', + $query_args, + $source, + $args, + $context, + $info + ); + + return $query_args; + } + + /** + * This sets up the "allowed" args, and translates the GraphQL-friendly keys to WP_Query + * friendly keys. There's probably a cleaner/more dynamic way to approach this, but + * this was quick. I'd be down to explore more dynamic ways to map this, but for + * now this gets the job done. + * + * @since 0.0.5 + * @access private + * + * @param array $args Where argument input. + * + * @return array + */ + + private static function sanitize_input_fields( $args ){ + $query_args = []; + + + if ( ! empty( $args['eventsIn'] ) ) { + $query_args['meta_query'] = []; // WPCS: slow query ok. + $query_args['meta_query'][] = [ + 'key' => WOO::ATTENDEE_EVENT_KEY, + 'value' => $args['eventsIn'], + 'compare' => 'IN', + ]; + } + + return $query_args; + } +} diff --git a/includes/types/object/class-event-type.php b/includes/types/object/class-event-type.php index cd533d9b..8a59535f 100644 --- a/includes/types/object/class-event-type.php +++ b/includes/types/object/class-event-type.php @@ -243,7 +243,7 @@ function( $date ) use ( $query ) { case '<': return $left_date < $right_date; } - }, + } ); } diff --git a/includes/types/object/class-rsvpattendee-type.php b/includes/types/object/class-rsvpattendee-type.php index 918e64a5..6f551fe8 100644 --- a/includes/types/object/class-rsvpattendee-type.php +++ b/includes/types/object/class-rsvpattendee-type.php @@ -41,7 +41,7 @@ private static function manager() { } /** - * Registers "Attendee" type fields. + * Registers "RSVPAttendee" type fields. */ public static function register_fields() { register_graphql_fields( diff --git a/ql-events.php b/ql-events.php index 4853e50d..535e3bd1 100644 --- a/ql-events.php +++ b/ql-events.php @@ -1,7 +1,7 @@ * @author Jordi Boggiano - * @see http://www.php-fig.org/psr/psr-0/ - * @see http://www.php-fig.org/psr/psr-4/ + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ */ class ClassLoader { @@ -60,7 +60,7 @@ class ClassLoader public function getPrefixes() { if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', $this->prefixesPsr0); + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); } return array(); diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 9cd33cca..e003a5f3 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,17 +6,23 @@ $baseDir = dirname($vendorDir); return array( + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'QL_Events' => $baseDir . '/includes/class-ql-events.php', - 'WPGraphQL\\QL_Events\\Connection\\Attendees' => $baseDir . '/includes/connection/class-attendees.php', + 'WPGraphQL\\Extensions\\QL_Events\\Type\\WPUnion\\Linked_Data_Union' => $baseDir . '/includes/types/union/class-linked-data-union.php', 'WPGraphQL\\QL_Events\\Connection\\Events' => $baseDir . '/includes/connection/class-events.php', 'WPGraphQL\\QL_Events\\Connection\\Organizers' => $baseDir . '/includes/connection/class-organizers.php', + 'WPGraphQL\\QL_Events\\Connection\\PayPalAttendees' => $baseDir . '/includes/connection/class-paypalattendees.php', + 'WPGraphQL\\QL_Events\\Connection\\RSVPAttendees' => $baseDir . '/includes/connection/class-rsvpattendees.php', 'WPGraphQL\\QL_Events\\Connection\\Tickets' => $baseDir . '/includes/connection/class-tickets.php', 'WPGraphQL\\QL_Events\\Connection\\Tickets_Plus' => $baseDir . '/includes/connection/class-tickets-plus.php', + 'WPGraphQL\\QL_Events\\Connection\\WooAttendees' => $baseDir . '/includes/connection/class-wooattendees.php', 'WPGraphQL\\QL_Events\\Core_Schema_Filters' => $baseDir . '/includes/class-core-schema-filters.php', - 'WPGraphQL\\QL_Events\\Data\\Connection\\Attendee_Connection_Resolver' => $baseDir . '/includes/data/connection/class-attendee-connection-resolver.php', 'WPGraphQL\\QL_Events\\Data\\Connection\\Event_Connection_Resolver' => $baseDir . '/includes/data/connection/class-event-connection-resolver.php', 'WPGraphQL\\QL_Events\\Data\\Connection\\Organizer_Connection_Resolver' => $baseDir . '/includes/data/connection/class-organizer-connection-resolver.php', + 'WPGraphQL\\QL_Events\\Data\\Connection\\PayPalAttendee_Connection_Resolver' => $baseDir . '/includes/data/connection/class-paypalattendee-connection-resolver.php', + 'WPGraphQL\\QL_Events\\Data\\Connection\\RSVPAttendee_Connection_Resolver' => $baseDir . '/includes/data/connection/class-rsvpattendee-connection-resolver.php', 'WPGraphQL\\QL_Events\\Data\\Connection\\Ticket_Connection_Resolver' => $baseDir . '/includes/data/connection/class-ticket-connection-resolver.php', + 'WPGraphQL\\QL_Events\\Data\\Connection\\WooAttendee_Connection_Resolver' => $baseDir . '/includes/data/connection/class-wooattendee-connection-resolver.php', 'WPGraphQL\\QL_Events\\Data\\Factory' => $baseDir . '/includes/data/class-factory.php', 'WPGraphQL\\QL_Events\\Type\\WPObject\\Attendee' => $baseDir . '/includes/types/object/common/trait-attendee.php', 'WPGraphQL\\QL_Events\\Type\\WPObject\\Event_Linked_Data_Type' => $baseDir . '/includes/types/object/class-event-linked-data-type.php', diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 04cc55b9..3db7fa22 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -13,6 +13,9 @@ public static function loadClassLoader($class) } } + /** + * @return \Composer\Autoload\ClassLoader + */ public static function getLoader() { if (null !== self::$loader) { diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 805fcd89..404900c2 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -21,17 +21,23 @@ class ComposerStaticInit8e59707a5d3582830b47ec9f532e7191 ); public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'QL_Events' => __DIR__ . '/../..' . '/includes/class-ql-events.php', - 'WPGraphQL\\QL_Events\\Connection\\Attendees' => __DIR__ . '/../..' . '/includes/connection/class-attendees.php', + 'WPGraphQL\\Extensions\\QL_Events\\Type\\WPUnion\\Linked_Data_Union' => __DIR__ . '/../..' . '/includes/types/union/class-linked-data-union.php', 'WPGraphQL\\QL_Events\\Connection\\Events' => __DIR__ . '/../..' . '/includes/connection/class-events.php', 'WPGraphQL\\QL_Events\\Connection\\Organizers' => __DIR__ . '/../..' . '/includes/connection/class-organizers.php', + 'WPGraphQL\\QL_Events\\Connection\\PayPalAttendees' => __DIR__ . '/../..' . '/includes/connection/class-paypalattendees.php', + 'WPGraphQL\\QL_Events\\Connection\\RSVPAttendees' => __DIR__ . '/../..' . '/includes/connection/class-rsvpattendees.php', 'WPGraphQL\\QL_Events\\Connection\\Tickets' => __DIR__ . '/../..' . '/includes/connection/class-tickets.php', 'WPGraphQL\\QL_Events\\Connection\\Tickets_Plus' => __DIR__ . '/../..' . '/includes/connection/class-tickets-plus.php', + 'WPGraphQL\\QL_Events\\Connection\\WooAttendees' => __DIR__ . '/../..' . '/includes/connection/class-wooattendees.php', 'WPGraphQL\\QL_Events\\Core_Schema_Filters' => __DIR__ . '/../..' . '/includes/class-core-schema-filters.php', - 'WPGraphQL\\QL_Events\\Data\\Connection\\Attendee_Connection_Resolver' => __DIR__ . '/../..' . '/includes/data/connection/class-attendee-connection-resolver.php', 'WPGraphQL\\QL_Events\\Data\\Connection\\Event_Connection_Resolver' => __DIR__ . '/../..' . '/includes/data/connection/class-event-connection-resolver.php', 'WPGraphQL\\QL_Events\\Data\\Connection\\Organizer_Connection_Resolver' => __DIR__ . '/../..' . '/includes/data/connection/class-organizer-connection-resolver.php', + 'WPGraphQL\\QL_Events\\Data\\Connection\\PayPalAttendee_Connection_Resolver' => __DIR__ . '/../..' . '/includes/data/connection/class-paypalattendee-connection-resolver.php', + 'WPGraphQL\\QL_Events\\Data\\Connection\\RSVPAttendee_Connection_Resolver' => __DIR__ . '/../..' . '/includes/data/connection/class-rsvpattendee-connection-resolver.php', 'WPGraphQL\\QL_Events\\Data\\Connection\\Ticket_Connection_Resolver' => __DIR__ . '/../..' . '/includes/data/connection/class-ticket-connection-resolver.php', + 'WPGraphQL\\QL_Events\\Data\\Connection\\WooAttendee_Connection_Resolver' => __DIR__ . '/../..' . '/includes/data/connection/class-wooattendee-connection-resolver.php', 'WPGraphQL\\QL_Events\\Data\\Factory' => __DIR__ . '/../..' . '/includes/data/class-factory.php', 'WPGraphQL\\QL_Events\\Type\\WPObject\\Attendee' => __DIR__ . '/../..' . '/includes/types/object/common/trait-attendee.php', 'WPGraphQL\\QL_Events\\Type\\WPObject\\Event_Linked_Data_Type' => __DIR__ . '/../..' . '/includes/types/object/class-event-linked-data-type.php',