Skip to content

Commit

Permalink
Merge pull request #152 from wp-graphql/fix/performance-issues
Browse files Browse the repository at this point in the history
fix: performance issues for mapping field groups to the Schema
  • Loading branch information
jasonbahl committed Jan 19, 2024
2 parents 65a8384 + c06163f commit 3b34a89
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 132 deletions.
105 changes: 9 additions & 96 deletions src/LocationRules/LocationRules.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function __construct( array $acf_field_groups = [] ) {
* @param string $graphql_type_name The name of the GraphQL Type
*/
public function set_graphql_type( string $field_group_name, string $graphql_type_name ): void {
$this->mapped_field_groups[ Utils::format_field_name( $field_group_name, true ) ][] = ucfirst( Utils::format_field_name( $graphql_type_name, true ) );
$this->mapped_field_groups[ strtolower( Utils::format_field_name( $field_group_name, true ) ) ][] = ucfirst( Utils::format_field_name( $graphql_type_name, true ) );
}

/**
Expand Down Expand Up @@ -267,12 +267,10 @@ public function determine_rules( string $field_group_name, string $param, string
$this->determine_post_template_rules( $field_group_name, $param, $operator, $value );
break;
case 'post_status':
$this->determine_post_status_rules( $field_group_name, $param, $operator, $value );
break;
case 'post_format':
case 'post_category':
case 'post_taxonomy':
$this->determine_post_taxonomy_rules( $field_group_name, $param, $operator, $value );
break;
case 'post':
$this->determine_post_rules( $field_group_name, $param, $operator, $value );
Expand Down Expand Up @@ -489,37 +487,6 @@ public function determine_post_template_rules( string $field_group_name, string
}
}

/**
* Determines how the ACF Rules should apply to the WPGraphQL Schema
*
* @param string $field_group_name The name of the ACF Field Group the rule applies to
* @param string $param The parameter of the rule
* @param string $operator The operator of the rule
* @param string $value The value of the rule
*/
public function determine_post_status_rules( string $field_group_name, string $param, string $operator, string $value ): void {
// @todo: Should post status affect the GraphQL Schema at all?
// If a field group is set to show on "post_status == publish" as the only rule, what post type does that apply to? All? 🤔
// If a field group is set to show on "post_status != draft" does that mean the field group should be available on all post types in the Schema by default?
// This seems like a very difficult rule to translate to the Schema.
// Like, lets say I add a field group called: "Editor Notes" that I want to show for any status that is not "publish". In theory, if that's my only rule, that seems like it should apply to all post types across the board, and show in the Admin in any state of the post, other than publish. 🤔

// ACF Admin behavior seems to add it to the Admin on all post types, so WPGraphQL
// should respect this rule and also add it to all post types. The resolver should
// then determine whether to resolve the data or not, based on this rule.

// If Post Status is used to qualify a field group location,
// It will be added to the Schema for any Post Type that is set to show in GraphQL
$allowed_post_types = get_post_types( [ 'show_in_graphql' => true ] );
foreach ( $allowed_post_types as $post_type ) {
$post_type_object = get_post_type_object( $post_type );
$graphql_name = $post_type_object->graphql_single_name ?? null;
if ( ! empty( $graphql_name ) ) {
$this->set_graphql_type( $field_group_name, $graphql_name );
}
}
}

/**
* Determines how the ACF Rules should apply to the WPGraphQL Schema
*
Expand Down Expand Up @@ -551,21 +518,6 @@ public function determine_post_format_rules( string $field_group_name, string $p
}
}

/**
* Determines how the ACF Rules should apply to the WPGraphQL Schema
*
* @param string $field_group_name The name of the ACF Field Group the rule applies to
* @param string $param The parameter of the rule
* @param string $operator The operator of the rule
* @param string $value The value of the rule
*/
public function determine_post_taxonomy_rules( string $field_group_name, string $param, string $operator, string $value ): void {

// If Post Taxonomy is used to qualify a field group location,
// It will be added to the Schema for the Post post type
$this->set_graphql_type( $field_group_name, 'Post' );
}

/**
* Determines how the ACF Rules should apply to the WPGraphQL Schema
*
Expand All @@ -580,35 +532,20 @@ public function determine_post_rules( string $field_group_name, string $param, s
// It will be added to the Schema for the GraphQL Type for the post_type of the Post
// it is assigned to

if ( '==' === $operator ) {
if ( absint( $value ) ) {
$post = get_post( absint( $value ) );
if ( $post instanceof \WP_Post ) {
$post_type_object = get_post_type_object( $post->post_type );
if ( $post_type_object && true === $post_type_object->show_in_graphql && isset( $post_type_object->graphql_single_name ) ) {
$this->set_graphql_type( $field_group_name, $post_type_object->graphql_single_name );
}
if ( ( '==' === $operator ) && absint( $value ) ) {
$post = get_post( absint( $value ) );
if ( $post instanceof \WP_Post ) {
$post_type_object = get_post_type_object( $post->post_type );
if ( $post_type_object && true === $post_type_object->show_in_graphql && isset( $post_type_object->graphql_single_name ) ) {
$this->set_graphql_type( $field_group_name, $post_type_object->graphql_single_name );
}
}
}

// If a single post is used as not equal,
// the field group should be added to ALL post types in the Schema
// the field group should not be added to any type
if ( '!=' === $operator ) {
$allowed_post_types = get_post_types( [ 'show_in_graphql' => true ] );

if ( empty( $allowed_post_types ) ) {
return;
}

// loop over and set all post types
foreach ( $allowed_post_types as $allowed_post_type ) {
$post_type_object = get_post_type_object( $allowed_post_type );
$graphql_name = $post_type_object->graphql_single_name ?? null;
if ( ! empty( $graphql_name ) ) {
$this->set_graphql_type( $field_group_name, $graphql_name );
}
}
return;
}
}

Expand All @@ -627,30 +564,6 @@ public function determine_page_type_rules( string $field_group_name, string $par
if ( in_array( $value, [ 'front_page', 'posts_page' ], true ) ) {
$this->set_graphql_type( $field_group_name, 'Page' );
}

// If top_level, parent, or child is set as equal_to or not_equal_to
// then the field group should be shown on all hierarchical post types
if ( in_array( $value, [ 'top_level', 'parent', 'child' ], true ) ) {
$hierarchical_post_types = get_post_types(
[
'show_in_graphql' => true,
'hierarchical' => true,
]
);

if ( empty( $hierarchical_post_types ) ) {
return;
}

// loop over and set all post types
foreach ( $hierarchical_post_types as $allowed_post_type ) {
$post_type_object = get_post_type_object( $allowed_post_type );
$graphql_name = $post_type_object->graphql_single_name ?? null;
if ( ! empty( $graphql_name ) ) {
$this->set_graphql_type( $field_group_name, $graphql_name );
}
}
}
}

/**
Expand Down
121 changes: 88 additions & 33 deletions src/Registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use WPGraphQL\Acf\Model\AcfOptionsPage;
use WPGraphQL\AppContext;
use WPGraphQL\Registry\TypeRegistry;
use WPGraphQL\Utils\Utils;

class Registry {

Expand All @@ -17,6 +16,18 @@ class Registry {
*/
protected $registered_fields = [];

/**
* Stores location rules once they've been mapped
*
* @var array<mixed>
*/
protected $mapped_location_rules = [];

/**
* @var array<mixed>
*/
protected $all_acf_field_groups = [];

/**
* @todo should be protected with getter/setter?
* @var array<mixed>
Expand Down Expand Up @@ -61,6 +72,15 @@ public function get_type_registry(): TypeRegistry {
return $this->type_registry;
}

/**
* Returns the mapped location rules
*
* @return array<mixed>
*/
public function get_mapped_location_rules(): array {
return $this->mapped_location_rules;
}

/**
* @param string $key
* @param mixed $field_group
Expand All @@ -82,7 +102,7 @@ public function has_registered_field_group( string $key ): bool {
* @param array<mixed> $acf_field_group
*/
public function should_field_group_show_in_graphql( array $acf_field_group ): bool {
return \WPGraphQL\Acf\Utils::should_field_group_show_in_graphql( $acf_field_group );
return Utils::should_field_group_show_in_graphql( $acf_field_group );
}

/**
Expand All @@ -91,6 +111,11 @@ public function should_field_group_show_in_graphql( array $acf_field_group ): bo
* @return array<mixed>
*/
public function get_acf_field_groups(): array {

if ( ! empty( $this->all_acf_field_groups ) ) {
return $this->all_acf_field_groups;
}

$all_acf_field_groups = acf_get_field_groups();

$graphql_field_groups = [];
Expand All @@ -105,7 +130,8 @@ public function get_acf_field_groups(): array {
$graphql_field_groups[ $acf_field_group['key'] ] = $acf_field_group;
}

return $graphql_field_groups;
$this->all_acf_field_groups = $graphql_field_groups;
return $this->all_acf_field_groups;
}

/**
Expand Down Expand Up @@ -286,7 +312,8 @@ public function get_field_group_interfaces( array $acf_field_group ): array {
* @throws \Exception
*/
public function register_options_pages(): void {
$graphql_options_pages = \WPGraphQL\Acf\Utils::get_acf_options_pages();

$graphql_options_pages = Utils::get_acf_options_pages();

if ( empty( $graphql_options_pages ) ) {
return;
Expand Down Expand Up @@ -342,7 +369,7 @@ public function register_options_pages(): void {
]
);

$field_name = Utils::format_field_name( $type_name );
$field_name = \WPGraphQL\Utils\Utils::format_field_name( $type_name );

$interface_name = 'WithAcfOptionsPage' . $type_name;

Expand Down Expand Up @@ -499,7 +526,7 @@ public function map_acf_field_to_graphql( array $acf_field, array $acf_field_gro
* @throws \GraphQL\Error\Error
*/
public function get_field_group_name( array $field_group ): string {
return \WPGraphQL\Acf\Utils::get_field_group_name( $field_group );
return Utils::get_field_group_name( $field_group );
}

/**
Expand All @@ -508,7 +535,7 @@ public function get_field_group_name( array $field_group ): string {
* @throws \GraphQL\Error\Error
*/
public function get_graphql_field_name( array $acf_field ): string {
return Utils::format_field_name( $this->get_field_group_name( $acf_field ), true );
return \WPGraphQL\Utils\Utils::format_field_name( $this->get_field_group_name( $acf_field ), true );
}

/**
Expand Down Expand Up @@ -540,7 +567,7 @@ public function get_field_group_graphql_type_name( array $field_group ): ?string
return null;
}

return Utils::format_type_name( $replaced );
return \WPGraphQL\Utils\Utils::format_type_name( $replaced );
}

/**
Expand All @@ -551,6 +578,11 @@ public function get_field_group_graphql_type_name( array $field_group ): ?string
* @return array<mixed>
*/
public function get_location_rules( array $acf_field_groups = [] ): array {

if ( ! empty( $this->get_mapped_location_rules() ) ) {
return $this->get_mapped_location_rules();
}

$field_groups = $acf_field_groups;
$rules = [];

Expand All @@ -571,7 +603,36 @@ public function get_location_rules( array $acf_field_groups = [] ): array {
$rules = new LocationRules();
$rules->determine_location_rules();

return $rules->get_rules();
// Set the mapped location rules for future use
$rules_by_group = $rules->get_rules();

$this->mapped_location_rules = $rules_by_group;

// Return them
return $this->mapped_location_rules;
}

/**
* Get the location rules grouped by location instead of grouped by field group
*
* @return array<mixed>
*/
public function get_location_rules_grouped_by_location(): array {
$location_rules = $this->get_location_rules();
$rules_by_location = [];
if ( ! empty( $location_rules ) ) {
foreach ( $location_rules as $group => $locations ) {
if ( ! empty( $locations ) ) {
foreach ( $locations as $location ) {
if ( ! array_key_exists( $location, $rules_by_location ) ) {
$rules_by_location[ $location ] = [];
}
$rules_by_location[ $location ][] = $group;
}
}
}
}
return $rules_by_location;
}

/**
Expand All @@ -583,37 +644,31 @@ public function get_location_rules( array $acf_field_groups = [] ): array {
* @return array<mixed>
*/
public function get_graphql_locations_for_field_group( array $field_group, array $acf_field_groups ): array {
if ( ! $this->should_field_group_show_in_graphql( $field_group ) ) {
return [];
}

$graphql_types = $field_group['graphql_types'] ?? [];
$graphql_types = [];

$field_group_name = '';
if ( ! $this->should_field_group_show_in_graphql( $field_group ) ) {
return $graphql_types;
}

if ( ! empty( $field_group['graphql_field_name'] ) ) {
$field_group_name = $field_group['graphql_field_name'];
} elseif ( ! empty( $field_group['title'] ) ) {
$field_group_name = $field_group['title'];
} elseif ( ! empty( $field_group['name'] ) ) {
$field_group_name = $field_group['name'];
if ( ! empty( $field_group['graphql_types'] ) && is_array( $field_group['graphql_types'] ) ) {
return $field_group['graphql_types'];
}

if ( empty( $field_group_name ) ) {
return [];
if ( empty( $field_group['location'] ) ) {
return $graphql_types;
}

$field_group_name = Utils::format_field_name( $field_group_name, true );
$field_group_name = Utils::get_field_group_name( $field_group );
$field_group_name = \WPGraphQL\Utils\Utils::format_field_name( $field_group_name, true );
// The fields are mapped as lowercase strings and should be retrieved as such
// see: LocationRules.php
$field_group_name = strtolower( $field_group_name );

$manually_set_graphql_types = isset( $field_group['map_graphql_types_from_location_rules'] ) && (bool) $field_group['map_graphql_types_from_location_rules'];
$location_rules = $this->get_location_rules( $acf_field_groups );

if ( false === $manually_set_graphql_types || empty( $graphql_types ) ) {
if ( empty( $field_group['graphql_types'] ) ) {
$location_rules = $this->get_location_rules( $acf_field_groups );
if ( isset( $location_rules[ $field_group_name ] ) ) {
$graphql_types = $location_rules[ $field_group_name ];
}
}
if ( isset( $location_rules[ $field_group_name ] ) ) {
$graphql_types = $location_rules[ $field_group_name ];
}

return ! empty( $graphql_types ) && is_array( $graphql_types ) ? array_unique( array_filter( $graphql_types ) ) : [];
Expand Down Expand Up @@ -648,7 +703,7 @@ public function register_acf_field_groups_to_graphql( array $acf_field_groups =
if ( ! empty( $locations ) ) {
$with_field_group_interface_name = 'WithAcf' . $type_name;

$field_name = Utils::format_field_name( $type_name, true );
$field_name = \WPGraphQL\Utils\Utils::format_field_name( $type_name, true );

if ( ! $this->has_registered_field_group( $with_field_group_interface_name ) ) {
register_graphql_interface_type(
Expand Down Expand Up @@ -680,7 +735,7 @@ public function register_acf_field_groups_to_graphql( array $acf_field_groups =
}

// If the field group has locations defined (Types to be added to)
// Add the
// Add the WithAcf$FieldGroup Interface to the corresponding graphql_types
register_graphql_interfaces_to_types( [ $with_field_group_interface_name ], $locations );
}

Expand Down

0 comments on commit 3b34a89

Please sign in to comment.