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

How to get ACF post object field with ACF fields #109

Closed
josephdonnelly opened this issue Mar 1, 2017 · 34 comments
Closed

How to get ACF post object field with ACF fields #109

josephdonnelly opened this issue Mar 1, 2017 · 34 comments

Comments

@josephdonnelly
Copy link

Hey, maybe I am missing something, but I am having trouble retrieving custom post ACF data within a post object field.

I have a custom post type call Rentals where I have set up ACF fields.

I can retrieve all of the acf data by getting /wp-json/wp/v2/rentals/{id}

When I create a page with an ACF Post Object field where I select a specific rental, I don't see any of the ACF data in the response. When I get /wp-json/wp/v2/pages/{id} I get this response:

...page data
"acf": {
    "rental": {
      "ID": 191,
      "post_author": "1",
      "post_date": "2017-02-28 18:24:35",
      "post_date_gmt": "2017-02-28 18:24:35",
      "post_content": "",
      "post_title": "Rental 1",
      "post_excerpt": "",
      "post_status": "publish",
      "comment_status": "closed",
      "ping_status": "closed",
      "post_password": "",
      "post_name": "rental-1",
      "to_ping": "",
      "pinged": "",
      "post_modified": "2017-02-28 18:24:35",
      "post_modified_gmt": "2017-02-28 18:24:35",
      "post_content_filtered": "",
      "post_parent": 0,
      "guid": "http://wordpress.site.local/?post_type=rentals&p=191",
      "menu_order": 0,
      "post_type": "rentals",
      "post_mime_type": "",
      "comment_count": "0",
      "filter": "raw"
    }
  },

How do I set it up so the ACF data is included within that Post Object field?

@airesvsg
Copy link
Owner

airesvsg commented Mar 1, 2017

Hi @josephdonnelly,
Thanks for using my plugin.
Please, see this issue #9 (comment)
Thanks


Edit:

Get ACF Fields Recursively:
https://github.com/airesvsg/acf-to-rest-api-recursive

@josephdonnelly
Copy link
Author

josephdonnelly commented Mar 1, 2017

Thanks for the extremely quick response!

I used that snippet, and it works great:

add_filter( 'acf/rest_api/page/get_fields', function( $data, $request, $response ) {
    if ( $response instanceof WP_REST_Response ) {
        $data = $response->get_data();
    }
    if ( isset($data['acf']) && isset( $data['acf']['rental'] ) ) {
        $data['acf']['rental'] = get_fields($data['acf']['rental']->ID);
    }
    return $data;
}, 10, 3);

However, is there a way to set it up so that any time a Rental posts is being used it displays the acf data? I am going to be using that Rental post type within several custom fields (repeaters/flexcontent/etc) and it will get tedius having to check for those fields manually.

Thanks again for the quick response

@josephdonnelly
Copy link
Author

Also worth noting, with the above snippet I was receiving this error using version 3 of the plugin:
Warning: Missing argument 3 for {closure}()
for this line of code:
add_filter( 'acf/rest_api/page/get_fields', function( $data, $request, $response ) {

Error goes away when switching back to v2

@airesvsg
Copy link
Owner

airesvsg commented Mar 1, 2017

At this time manually, but you can do a recursive function to check.

Yes, in third version the argument $response not exists.

add_filter( 'acf/rest_api/page/get_fields', function( $data, $request ) {
...
}, 10, 2 );

Arguments of add_filter:

add_filter( $tag, $function_to_add, $priority, $accepted_args );

The $accepted_args argument in the v3 accepts values greater than 0 and less than 3.

Thanks

@josephdonnelly
Copy link
Author

josephdonnelly commented Mar 1, 2017

Thanks again. I got it working with a recursive function

add_filter( 'acf/rest_api/page/get_fields', function( $data, $request, $response ) {
    if ( $response instanceof WP_REST_Response ) {
        $data = $response->get_data();
    }

    array_walk_recursive( $data, 'deepIncludeRentalFields' );
    
    return $data;
}, 10, 3);

function deepIncludeRentalFields( &$item, $key ) {
    if ( $key == 'rental' ) {
        $item = get_fields( $item->ID );
    }
}

@josephdonnelly
Copy link
Author

josephdonnelly commented Mar 1, 2017

here is a cleaner way for anyone else who finds this issue:

add_filter( 'acf/rest_api/page/get_fields', function( $data, $request, $response ) {
    if ( $response instanceof WP_REST_Response ) {
        $data = $response->get_data();
    }

    array_walk_recursive( $data, 'deepIncludeACFFields', array( 'rentals' ) );

    return $data;
}, 10, 3 );


function deepIncludeACFFields( &$item, $key, $postTypes ) {
    if ( isset( $item->post_type ) && in_array( $item->post_type, $postTypes ) ) {
        $item = get_fields( $item->ID );
    }
}

@ghost
Copy link

ghost commented Mar 14, 2017

@josephdonnelly I am dealing with this same thing... I think. Can you help provide a better explanation of how you fixed this?

I have a custom post type I am pulling info for via the API. On each post there is a Relationship field where you can select other posts from the same post type. The JSON shows the objects from the relationship but NOT any of their custom fields. I want to pull field data from the relationship objects. The snippet above you listed doesn't appear to be working for me. Any help would be awesome!

Thanks!

@airesvsg
Copy link
Owner

Hi @travis-zookacreative,
Thanks for using my plugin, bellow I wrote an example most generic.

V3

add_filter( 'acf/rest_api/{type}/get_fields', function( $data ) {
	if ( ! empty( $data ) ) {
		array_walk_recursive( $data, 'get_fields_recursive' );
	}

	return $data;
} );

V2

add_filter( 'acf/rest_api/{type}/get_fields', function( $data, $request, $response ) {
	if ( $response instanceof WP_REST_Response ) {
		$data = $response->get_data();
	}

	if ( ! empty( $data ) ) {
		array_walk_recursive( $data, 'get_fields_recursive' );
	}

	return $data;
}, 10, 3 );

Function to use for both versions:

function get_fields_recursive( $item ) {
	if ( is_object( $item ) ) {
		$item->acf = array();
		if ( $fields = get_fields( $item ) ) {
			$item->acf = $fields;					
			array_walk_recursive( $item->acf, 'get_fields_recursive' );
		}
	}
}

@ghost
Copy link

ghost commented Mar 15, 2017

hey @airesvsg thanks for sharing! Unfortunately that throws an error and doesn't load. Any ideas? I am using V2 at the moment. My custom post type is "product" so my first line looks like the following.

add_filter( 'acf/rest_api/product/get_fields', function( $data, $request, $response ) {

@ghost
Copy link

ghost commented Mar 15, 2017

Actually looks like V3 failed as well. Am I missing something? Im adding these snippets to my functions file. Here is a screen shot of the result when routing directly to the relationship field.

screen shot 2017-03-14 at 5 37 28 pm

@josephdonnelly
Copy link
Author

josephdonnelly commented Mar 16, 2017

@travis-zookacreative , Try this one out. It will run the same recursive lookup if the item is an array. I just ran into this and solved it this way

add_filter( 'acf/rest_api/product/get_fields', function( $data, $request, $response ) {
    if ( $response instanceof WP_REST_Response ) {
        $data = $response->get_data();
    }

    array_walk_recursive($data, 'deepIncludeACFFields', array('product'));

    return $data;
}, 10, 3);

function deepIncludeACFFields(&$item, $key, $postTypes) {

    if( isset($item->post_type) && in_array($item->post_type, $postTypes) ) {
        $item = get_fields($item->ID);
    }
    // Add this portion here to look up arrays within the array
    if(is_array($item)) {
        array_walk_recursive($item, 'deepIncludeACFFields', $postTypes);
    }
}

@ghost
Copy link

ghost commented Mar 16, 2017

@josephdonnelly I saw you posted something similar earlier up the chain. I've messed around with both but they are throwing a fatal error of "Too few arguments to function {closure}()". I also saw you had this same issue, how did you resolve?

@josephdonnelly
Copy link
Author

Can you post the full code you're using?

@ghost
Copy link

ghost commented Mar 16, 2017

add_filter( 'acf/rest_api/product/get_fields', function( $data, $request, $response ) {
    if ( $response instanceof WP_REST_Response ) {
        $data = $response->get_data();
    }
    array_walk_recursive($data, 'deepIncludeACFFields', array('product'));
    return $data;
}, 10, 3);

function deepIncludeACFFields(&$item, $key, $postTypes) {

    if( isset($item->post_type) && in_array($item->post_type, $postTypes) ) {
        $item = get_fields($item->ID);
    }
    // Add this portion here to look up arrays within the array
    if(is_array($item)) {
        array_walk_recursive($item, 'deepIncludeACFFields', $postTypes);
    }
}

I changed my local server from PHP 7 to 5.6 and that got rid of the too few arguments error. Now instead it just times out hahaha

@josephdonnelly
Copy link
Author

Ah, so the timeout likely is because you're going in an infinite loop. You get acf fields for a product, which gets acf fields for a product, which gets acf fields for a product... and so on. You will have to add some checks into the deepincludeACFFields to prevent the infinite loop. I'm afraid I don't know enough about PHP or your specific situation to help. Best of luck though,

@ghost
Copy link

ghost commented Mar 16, 2017

ahhh that would make sense! Thanks man! Much Appreciated!

@ghost
Copy link

ghost commented Mar 23, 2017

Gents, got this working! Great news! However do you know of any ways to ALSO get WP data from the relationship posts? I would also like to grab the slug, and featured img, etc. Not just the ACF fields. Code I got to work is below.

add_filter( 'acf/rest_api/product/get_fields', function( $data, $request, $response ) {
    if ( $response instanceof WP_REST_Response ) {
        $data = $response->get_data();
    }
    array_walk_recursive($data, 'deepIncludeACFFields', array('product'));

    return $data;
}, 10, 3);

function deepIncludeACFFields(&$item, $key, $postTypes, $level=0, $post) {
	if( isset($item->post_type) && in_array($item->post_type, $postTypes) ) {
		$item = get_fields($item->ID);
	}
}

@lithiumlab
Copy link

Great information.
You should consider adding this reply code:
#109 (comment)
To the Readme.
Another suggestion is to use {custom_post_type} instead of {type} in your route examples. Makes understanding easier. At first i was not sure what type was referring to.

@jhalvorson
Copy link

jhalvorson commented May 11, 2017

Hi,

Fixed - see end of comment

I've been able to use one of the code snippets above:

add_filter( 'acf/rest_api/product/get_fields', function( $data, $request, $response ) {
    if ( $response instanceof WP_REST_Response ) {
        $data = $response->get_data();
    }
    array_walk_recursive($data, 'deepIncludeACFFields', array('product'));

    return $data;
}, 10, 3);

function deepIncludeACFFields(&$item, $key, $postTypes, $level=0, $post) {
	if( isset($item->post_type) && in_array($item->post_type, $postTypes) ) {
		$item = get_fields($item->ID);
	}
}

To successfully get the ACF fields from a page or post-type. However, I am struggling to get the fields from a custom options page. I've tried replacing:

add_filter( 'acf/rest_api/product/get_fields', function( $data, $request, $response ) {

With

add_filter( 'acf/rest_api/options/get_fields', function( $data, $request, $response ) {

but I haven't had any success yet.

How should I go about getting relational fields from options pages?

The structure that I am working with looks like this:

{
  "acf": {
    "locations": [
      {
        "latitude": "55.9767554",
        "longitdue": "-3.1734137",
        ...
      }
    ],
    "explore_section": [
      {
        "navigation_title": "Testing 123",
        "explore_section_hero": false,
        ...
        "product_testing": {  //I'm looking to get the fields from product testing
          "ID": 63,
          "post_author": "2",
          "post_date": "2017-05-11 05:31:56",
          "post_date_gmt": "2017-05-11 05:31:56",
         ...
        }
      },
      {
        "navigation_title": "Another",
        ...
      }
    ]
  }
}

I'm looking to get the ACF fields from product_testing.

Thanks!

Fix

  • I upgraded to V3
  • Changed the function to:
add_filter( 'acf/rest_api/option/get_fields', function( $data ) {
	if ( ! empty( $data ) ) {
		array_walk_recursive( $data, 'deepIncludeACFFields', array('product') );
	}

	return $data;
} );

Also turns out that I was saying options instead of option - Doh!

@maxsupera
Copy link

hi everyone. for the life of me i cant seem to get this to work!

I have tried both post object as well as post relationship. none of these snippets are returning acf data in the returned post object...

im using the default wp-api. any help is much appreciated! :D

@dblodorn
Copy link

Hi @airesvsg - I am using the above snippets (specifically @travis-zookacreative to return acf post objects in a repeater that is in a custom post type.

the endpoint URL looks like this:
http://138.197.53.59/wp-json/wp/v2/directors-api?filter[name]=oscar-boyson

When I apply deepIncludeACFFields function & filter I get the acf data but i loose the normal post data, I need to be able to pull the title of the post and the slug for a permalink. After reading through the various tickets and trying some different things still cant seem to get both - so is this possible or is it one or the other - and I should include things like title and slug as custom fields.

Thanks!

@ghost
Copy link

ghost commented Jul 19, 2017

Hey @airesvsg. Ok, so its been a while since I worked on this project but here is my code at the moment. I'll do my best to remember what it's doing.

So essentially I decided it best to get just the acf fields I want if they exist. So for each custom type that has the repeater field product_scents return the post and the custom fields of it. I can't fully remember all of the details to this as I only did a little and a coworker did the rest.

// Get ACF fields and their related objects
add_filter( 'acf/rest_api/product/get_fields', function( $data, $request, $response ) {
    if ( $response instanceof WP_REST_Response ) {
        $data = $response->get_data();
    }

	foreach( $data['acf']['product_scents'] as $_key => $_product ){
	//	Add Link
		$data['acf']['product_scents'][$_key]->link = get_permalink($_product);
	//	Add Category
		$data['acf']['product_scents'][$_key]->category = get_the_terms($_product->ID, 'product_cat' )[1];
	//	Add All Other Custom Fields
		$_custom_fields	=	get_post_custom($_product->ID);
		foreach( $_custom_fields as $_field => $_value ){
			if( preg_match('/^(_|faqs_)/',$_field) )	continue;
			$data['acf']['product_scents'][$_key]->{$_field}	=	$_value;
		}//foreach
	}//foreach

	foreach( $data['acf']['related_products'] as $_key => $_product ){
	//	Add Link
		$data['acf']['related_products'][$_key]->link = get_permalink($_product);
		$data['acf']['related_products'][$_key]->thumbnail = get_the_post_thumbnail_url($_product);
	//	Add Category
		$data['acf']['related_products'][$_key]->category = get_the_terms($_product->ID, 'product_cat' )[1];
	//	Add All Other Custom Fields
		$_custom_fields	=	get_post_custom($_product->ID);
		foreach( $_custom_fields as $_field => $_value ){
			if( preg_match('/^(_|faqs_)/',$_field) )	continue;
			$data['acf']['related_products'][$_key]->{$_field}	=	$_value;
		}//foreach
	}//foreach

	return $data;

}, 10, 3);

@stevendaoud
Copy link

stevendaoud commented Nov 19, 2017

Setting the $item to the full ACF field overwrites all the default post object data. I instead looped through the fields and append them to the item in order to presever the default data:

function deepIncludeACFFields( &$item, $key, $postTypes, $level=0, $post ) {
    if ( isset( $item->post_type ) && in_array( $item->post_type, $postTypes ) ) {
         $acf_fields = get_fields( $item->ID );
         foreach( $acf_fields as $key => $value ) {
             $item->{$key} = $value;
        }
    }
}

@timbomckay
Copy link

timbomckay commented Mar 2, 2018

Instead of defining it for every possible post type. I added a $types array so it loops through the types and also uses it for the array_walk_recursive() function.

/**
 * ACF Data in Post Object Response
 */

$types = ['post', 'page', 'product']

foreach ($types as $type) {
  add_filter( 'acf/rest_api/'.$type.'/get_fields', function( $data, $response ) use ($types) {

    if ( $response instanceof WP_REST_Response ) {
      $data = $response->get_data();
    }

    array_walk_recursive( $data, 'deepIncludeACFFields', $types );

    return $data;

  }, 10, 3 );
}

function deepIncludeACFFields( &$item, $key, $postTypes ) {
  if ( isset( $item->post_type ) && in_array( $item->post_type, $postTypes ) ) {
    $item->acf = get_fields( $item->ID );
  }
}

I like @stevendaoud's solution for adding the fields to the top level object. I opted to follow the plugin's format of placing all the fields in the acf key. Both adding to the response as opposed to replacing it.

Also, I was getting an error with function( $data, $request, $response ) so I removed $request and it appears to be working. Not sure why mine was giving me the error, guess it's possible it's been deprecated.

@stevendaoud
Copy link

function( $data, $request, $response ) breaks in PHP 7.x, I haven't done too much digging as to why. If anyone has an answer that'd be great.

Still works in PHP 5.x

@alexabbott
Copy link

can you provide simple instructions for where to add this filter? what file?

@airesvsg
Copy link
Owner

airesvsg commented Apr 10, 2018

@alexabbott install that plugin:
https://github.com/airesvsg/acf-to-rest-api#get-acf-fields-recursively

@alexabbott
Copy link

@airesvsg thank you! works like a charm

@mattprudente
Copy link

Hi @airesvsg

I'm trying to implement on the site that I'm developing. I've installed your recursive plugin but the response still doesn't have the acf fields included. I'm on v3 of the acf-to-rest-api plugin.
Please see response here:-

https://nationalgridpurpose.com/wp-json/wp/v2/actionbox/10084

Any advice please?

@nikosolihin
Copy link

@mattprudente Did you figure this out? I've installed the plugin but still no acf fields.

@roryheaney
Copy link

Did anyone else figure this out, for adding fields to the base post object as detailed above?

not just the ACF fields, but things like Categories or the Featured Image.

@kgrosvenor
Copy link

kgrosvenor commented Oct 16, 2018

How could i enrich this

"acf": {
"audio_file_url": false,
"summary": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ",
"video_file_url": "http://techslides.com/demos/sample-videos/small.mp4",
"attached_resources": [
{
"attachable": [
{
"ID": 115,
"post_author": "1",
"post_date": "2018-10-16 18:32:38",
"post_date_gmt": "2018-10-16 18:32:38",
"post_content": "",
"post_title": "fghfghfgh",
"post_excerpt": "",
"post_status": "publish",
"comment_status": "closed",
"ping_status": "closed",
"post_password": "",
"post_name": "fghfghfgh",
"to_ping": "",
"pinged": "",
"post_modified": "2018-10-16 18:32:38",
"post_modified_gmt": "2018-10-16 18:32:38",
"post_content_filtered": "",
"post_parent": 0,
"guid": "http://104.248.160.79/?post_type=resources&p=115",
"menu_order": 0,
"post_type": "resources",
"post_mime_type": "",
"comment_count": "0",
"filter": "raw"
}
]
}

@albertoavv
Copy link

Hello
I'm trying to make a post and it doesn't give me a mistake, please help
image

@mevadakalpesh
Copy link

this plugins get api one load is properly but when i edit act content so this update content is not show in my react project and my costume api is working fine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests