Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Field groups not in schema when location is a page template #76

Closed
nathobson opened this issue Oct 23, 2019 · 23 comments
Closed

Field groups not in schema when location is a page template #76

nathobson opened this issue Oct 23, 2019 · 23 comments
Labels
Location Rules Issues related to ACF Location Rules Needs Discussion

Comments

@nathobson
Copy link

When a field group is tied to a page template for its location, it seems as though it is not available to pages in the GraphQL schema. I also tried combining the rules so it's set as page AND page template === whatever but that still didn't work.

Any possibility of this landing in the future? I did see you can use page === page name as the location but usually we want to tie them to template so either us or a client can create a new page based off of a template without having to change field group settings.

@intelligence
Copy link

Had this issue myself and asked for a workaround on Slack and got this helpful advice:

I added this custom method to the Config class and added it to the list of calls here: https://github.com/wp-graphql/wp-graphql-acf/blob/master/src/class-config.php#L39. This is probably a dirty way of getting this to work, but it works! It mostly follows how add_acf_fields_to_individual_posts works, so it also exposes the field groups to the general Page type in GraphQL. For example: if you have a field group assigned to only the frontpage, it'll be queryable for all pages. I assume this is fine as that is how add_acf_fields_to_individual_posts field groups work, but just be aware.

Code snippet:
add_acf_fields_to_pages.txt

Don't forget to add $this->add_acf_fields_to_pages(); in the init function

@JodiWarren
Copy link

I've got a particular variation on this issue. I have a field group which has the following location rules:

<?php
$location = [
	0 => [
		0 => [
			'param'    => 'post_type',
			'operator' => '==',
			'value'    => 'post',
		],
	],
	1 => [
		0 => [
			'param'    => 'post_type',
			'operator' => '==',
			'value'    => 'page',
		],
		1 => [
			'param'    => 'page_type',
			'operator' => '!=',
			'value'    => 'posts_page',
		],
		2 => [
			'param'    => 'page_type',
			'operator' => '!=',
			'value'    => 'front_page',
		],
		3 => [
			'param'    => 'page_template',
			'operator' => '!=',
			'value'    => 'page-locations.php',
		],
	],
];

In English, show if:

  • is a post OR
  • is a page AND
    • is not a Location template
    • is not the posts page
    • is not the front page

add_acf_fields_to_post_object_types() happily adds it to the post post type. However, this relies on the ACF core function, acf_get_field_groups(). It's called like so:

// $post_type is each of your registered post types, called one by one
$field_groups = acf_get_field_groups(
	[
		'post_type' => $post_type,
	]
);

This doesn't return the field group for the page post type, because there are some exceptions to that rule.

I took a deep dive into the ACF internals, and into how ACF resolves the visibility of a particular field group based on a set of location rules.

Here are the main functions that runs in order to determine visibility of the field group given the context:

  1. acf_get_field_group_visibility()
  2. acf_get_location_screen() - this returns ['lang' => '', 'ajax' => false, 'post_type' => 'post',] for the /graphql endpoint
  3. If there are multiple AND rules for a location, it runs acf_match_location_rule() against each of them, and fails if one doesn't pass.
  4. Finally, it runs the field group rules against the following filters:
$result = apply_filters( "acf/location/match_rule/type={$rule['param']}", $result, $rule, $screen, $field_group );
$result = apply_filters( "acf/location/match_rule", $result, $rule, $screen, $field_group );
$result = apply_filters( "acf/location/rule_match/{$rule['param']}", $result, $rule, $screen, $field_group );
$result = apply_filters( "acf/location/rule_match", $result, $rule, $screen, $field_group );

I plan on experimenting with these filters, to see if I can get the rules to pass for all fields which are registered on the page post type, and will report back if so. I just thought I'd post up some of my research in case it helps anyone else.

@JodiWarren
Copy link

JodiWarren commented Dec 1, 2019

I ended up with a pretty crude solution to this, but one that works with the plugin out of the box:

function whitelistedFieldGroups( $result, $rule, $screen, $field_group) {
	$graphqlFieldNames = [ 'homepage', 'pageFields' ];

	if (
		in_array($field_group['graphql_field_name'], $graphqlFieldNames)
		&& $screen['post_type'] === 'page'
	) {
		return true;
	}

	return $result;
}
add_filter('acf/location/rule_match', 'whitelistedFieldGroups', 10, 4);

Hopefully this might help someone else!

@izzygld
Copy link

izzygld commented Dec 2, 2019

@JodiWarren can you post a sample of the code here please?

@JodiWarren
Copy link

@izzygld This is all I have (and need) in my current setup:

function whitelistedFieldGroups( $result, $rule, $screen, $field_group) {
	$graphqlFieldNames = [ 'homepage', 'pageFields' ];

	if (
		in_array($field_group['graphql_field_name'], $graphqlFieldNames)
		&& $screen['post_type'] === 'page'
	) {
		return true;
	}

	return $result;
}
add_filter('acf/location/rule_match', 'whitelistedFieldGroups', 10, 4);

This also requires a location rule that's tied to a particular post type. So if you only want a set of fields to appear on a certain page template, you'll need to set it to a combination location rule of post type and page template.

Why this works:

Let's take a field group with the location rules of:

post_type === 'post'
OR
post_type === 'page' AND 'post_template' !== 'locations.php'

The WPGraphQL ACF plugin loops through all post types and fetches their related field groups like so:

function add_acf_fields_to_post_object_types() {
	/**
	 * Get a list of post types that have been registered to show in graphql
	 */
	$graphql_post_types = get_post_types( [ 'show_in_graphql' => true ] );

	// Do some checks

	/**
	 * Loop over the post types exposed to GraphQL
	 */
	foreach ( $graphql_post_types as $post_type ) {

		/**
		 * Get the field groups associated with the post type
		 */
		$field_groups = acf_get_field_groups(
			[
				'post_type' => $post_type,
			]
		);

		// Do the magic of adding those field groups to GraphQL etc
	}
}

We basically hijack one of the checks that happens within the function add_acf_fields_to_post_object_types(). By default, our example field group will be returned on a post, but the extra rules on the page rule mean that it won't be returned. That's because it fails the acf/location/rule_match filter that it relies on internally. By hooking into that filter, we can make our own rules.

The main takeaway should not necessarily be the exact code that I used, but that this filter allows you to adjust what gets included.

@esamattis
Copy link
Collaborator

We workaround this issue by conditionally skipping the rule definitions on the graphql context.

Using acf-codifier:

if (!is_graphql_http_request()) {
	$rule_group->add_rule( 'page_template', '==', 'template.php' );
}

We did discuss some solutions to this with @jasonbahl yesterday on Slack
https://wp-graphql.slack.com/archives/C3NM1M291/p1575991879025000

@joaokrabbe
Copy link

We workaround this issue by conditionally skipping the rule definitions on the graphql context.

Using acf-codifier:

if (!is_graphql_http_request()) {
	$rule_group->add_rule( 'page_template', '==', 'template.php' );
}

We did discuss some solutions to this with @jasonbahl yesterday on Slack
https://wp-graphql.slack.com/archives/C3NM1M291/p1575991879025000

Could you detail this application better? I would like to use WPGraphql to return the fields of an ACF group "FrontPage". But I never used the acf-codifier. I'm not able to apply it properly.

@esamattis
Copy link
Collaborator

esamattis commented Feb 11, 2020

ACF Codifier discussion is offtopic for this thread but my guess is that you are missing show_in_graphql if you see the fields on wp-admin but not in graphql. It can be done with the wpgraphql_acf_should_field_group_show_in_graphql filter:

add_filter(
		'wpgraphql_acf_should_field_group_show_in_graphql',
		function ( $show, $field_group ){
			if ( "my_group" === $field_group['key'] ) {
				return true;
			}
			return $show;
		},
		10,
		2
);

...but now that I think of it this might work too

$field_group->show_in_graphql = true;

@jasonbahl jasonbahl added the Location Rules Issues related to ACF Location Rules label Feb 24, 2020
@cfxd
Copy link

cfxd commented Apr 10, 2020

I tried @JodiWarren's setup (thank you!) but it only got me 99% of the way there because it has the unfortunate side effect of displaying all ACF fields on all pages in the admin edit screens. Then I caught a great tidbit from @esamattis's solution that brought it home, so I check for is_graphql_http_request(), like this:

function expose_acf_to_graphql_only($result, $rule, $screen, $field_group) {
  if(!is_graphql_http_request()) {
    return $result;
  }

  $page_template_acf_groups = [
    'acfPageTemplateHome',
    'acfPageTemplateAbout',
    'acfPageTemplateContact',
  ];

  if(in_array($field_group['graphql_field_name'], $page_template_acf_groups) && $screen['post_type'] === 'page') {
    return true;
  }

  return $result;
}
add_filter('acf/location/rule_match', __NAMESPACE__.'\\expose_acf_to_graphql_only', 10, 4);

I was also able to extrapolate this and apply it to other field groups, such as a field group that applies to a post type in a certain taxonomy. Works great until there's a more solid solution within the plugin itself!

@AbeCole
Copy link

AbeCole commented May 5, 2020

I believe this is similar to an issue I've just resolved, take a look at my pull request #134

@sirichards
Copy link

Hi, is this going to be fixed? seems like quite an important feature? this fix does the trick but it would be nice to be implemented into the main build. Thanks

@AbeCole
Copy link

AbeCole commented May 6, 2020

@sirichards Yes there is discussion about a major change in how you specify which fields are added to which GraphQL types, this would address this issue, see details #135

Twansparant added a commit to clarifynl/wp-graphql-acf that referenced this issue May 14, 2020
@madderlake
Copy link

madderlake commented Jul 28, 2020

Typo? This finally worked for me after I changed "page_type" to "post_type" here:
$allowed_page_params = [ '**page_type**', 'page_template', ];

@ljanecek
Copy link
Contributor

ljanecek commented Feb 3, 2021

Had this issue myself and asked for a workaround on Slack and got this helpful advice:

I added this custom method to the Config class and added it to the list of calls here: https://github.com/wp-graphql/wp-graphql-acf/blob/master/src/class-config.php#L39. This is probably a dirty way of getting this to work, but it works! It mostly follows how add_acf_fields_to_individual_posts works, so it also exposes the field groups to the general Page type in GraphQL. For example: if you have a field group assigned to only the frontpage, it'll be queryable for all pages. I assume this is fine as that is how add_acf_fields_to_individual_posts field groups work, but just be aware.

Code snippet:
add_acf_fields_to_pages.txt

Don't forget to add $this->add_acf_fields_to_pages(); in the init function

Is there some merge request? I do not understand why does not include yet.

@maweo-mathis
Copy link

Is there a solution for this problem? The ACF-Fields aren't in the schema, when the condition is set to a specific page-template..

@ljanecek
Copy link
Contributor

Is there a solution for this problem? The ACF-Fields aren't in the schema, when the condition is set to a specific page-template..

Sure, this comment: #76 (comment)

@maweo-mathis
Copy link

Is there a solution for this problem? The ACF-Fields aren't in the schema, when the condition is set to a specific page-template..

Sure, this comment: #76 (comment)

So I have to edit the class-config.php?

@AbeCole
Copy link

AbeCole commented Feb 24, 2021

I would try using #207 if possible, that seems like the most relevant/new solution and probably the one that will be used going forward.

@maweo-mathis any of the 'workaround' solutions such as the one suggested here (or my own one: #134) require you to edit src/class-config.php

@jasonbahl jasonbahl added this to the ACF Schema Location Rules milestone Mar 5, 2021
@jasonbahl jasonbahl moved this from Upcoming to In Progress in ACF Schema Location Rules Mar 30, 2021
@jasonbahl jasonbahl moved this from In Progress to Upcoming in ACF Schema Location Rules Mar 30, 2021
@jasonbahl jasonbahl removed this from Upcoming in ACF Schema Location Rules Mar 30, 2021
@jasonbahl
Copy link
Contributor

This is addressed by v0.5.0 (#250).

With this release, we can now assign field groups to templates and we can see that it's properly assigned to the GraphQL Type for the template:

Screen Shot 2021-04-20 at 2 12 05 PM

Then, we can see the Field Group available on the Template in the Schema:

Screen Shot 2021-04-20 at 2 13 15 PM

Then, we can query like so:

{
  posts {
    nodes {
      id
      template {
        __typename
        ... on Template_AboutUs {
          acfDocs { # <-- This is the ACF Field Group assigned to the Template location
            text
          }
        }
      }
    }
  }
}

@rburgst
Copy link

rburgst commented Apr 23, 2021

It appears that this does not work as planned yet, see #251

@jasonbahl
Copy link
Contributor

@rburgst see #253. If there's still issues after that, please let me know and provide details on reproducing 🙏🏻

@ivanyankov
Copy link

Hey team, I still have the same issue. I am using the latest version of the plugin and also the latest version of the graphql plugin. When I assign the ACF fields to a page template they appear in the admin page but they does not appear in the graphql schema.
My wordpress version is 6.2.2

@ivanyankov
Copy link

@jasonbahl I can provide more details regarding #76 (comment) if needed or open a new ticket.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Location Rules Issues related to ACF Location Rules Needs Discussion
Projects
None yet
Development

No branches or pull requests