Closed nathobson closed 3 years ago
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 howadd_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
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:
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:
acf_get_field_group_visibility()
acf_get_location_screen()
- this returns ['lang' => '', 'ajax' => false, 'post_type' => 'post',]
for the /graphql
endpointacf_match_location_rule()
against each of them, and fails if one doesn't pass.$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.
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!
@JodiWarren can you post a sample of the code here please?
@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.
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
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.
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;
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!
I believe this is similar to an issue I've just resolved, take a look at my pull request https://github.com/wp-graphql/wp-graphql-acf/pull/134
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
@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 https://github.com/wp-graphql/wp-graphql-acf/issues/135
Typo? This finally worked for me after I changed "page_type" to "post_type" here:
$allowed_page_params = [ '**page_type**', 'page_template', ];
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 howadd_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.
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..
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: https://github.com/wp-graphql/wp-graphql-acf/issues/76#issuecomment-555733586
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?
I would try using https://github.com/wp-graphql/wp-graphql-acf/pull/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: https://github.com/wp-graphql/wp-graphql-acf/pull/134) require you to edit src/class-config.php
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:
Then, we can see the Field Group available on the Template in the Schema:
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
}
}
}
}
}
}
It appears that this does not work as planned yet, see #251
@rburgst see #253. If there's still issues after that, please let me know and provide details on reproducing 🙏🏻
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
@jasonbahl I can provide more details regarding https://github.com/wp-graphql/wp-graphql-acf/issues/76#issuecomment-1563970080 if needed or open a new ticket.
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.