Skip to content

Instantly share code, notes, and snippets.

@gsarig
Last active May 21, 2022 10:12
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save gsarig/4fd50c4d9495a1cdd91eecde2c4ca5b8 to your computer and use it in GitHub Desktop.
Save gsarig/4fd50c4d9495a1cdd91eecde2c4ca5b8 to your computer and use it in GitHub Desktop.
Get Instagram media on WordPress using the current Instagram (Facebook) API (details: https://www.gsarigiannidis.gr/instagram-feed-api-after-june-2020/)
<?php
/**
* Get Instagram media on WordPress using the current Instagram (Facebook) API
*
* @param $token // Info on how to retrieve the token: https://www.gsarigiannidis.gr/instagram-feed-api-after-june-2020/
* @param $user // User ID can be found using the Facebook debug tool: https://developers.facebook.com/tools/debug/accesstoken/
* @param int $limit // Add a limit to prevent excessive calls.
* @param string $fields // More options here: https://developers.facebook.com/docs/instagram-basic-display-api/reference/media
* @param array $restrict // Available options: IMAGE, VIDEO, CAROUSEL_ALBUM
*
* @return array|mixed // Use it like that (minimal example): get_instagram_media(TOKEN, USER_ID);
*/
function get_instagram_media(
$token,
$user,
$limit = 10,
$fields = 'media_url,permalink,media_type,caption',
$restrict = [ 'IMAGE' ]
) {
// The request URL. see: https://developers.facebook.com/docs/instagram-basic-display-api/reference/user
$request_url = 'https://graph.instagram.com/' . $user . '?fields=media&access_token=' . $token;
// We use transients to cache the results and fetch them once every hour, to avoid bumping into Instagram's limits (see: https://developers.facebook.com/docs/graph-api/overview/rate-limiting#instagram-graph-api)
$output = get_transient( 'instagram_feed_' . $user ); // Our transient should have a unique name, so we pass the user id as an extra precaution.
if ( false === ( $data = $output ) || empty( $output ) ) {
// Prepare the data variable and set it as an empty array.
$data = [];
// Make the request
$response = wp_safe_remote_get( $request_url );
$response_body = '';
if ( is_array( $response ) && ! is_wp_error( $response ) ) {
$response_body = json_decode( $response['body'] );
}
if ( $response_body && isset( $response_body->media->data ) ) {
$i = 0;
// Get each media item from it's ID and push it to the $data array.
foreach ( $response_body->media->data as $media ) {
if ( $limit > $i ) {
$request_media_url = 'https://graph.instagram.com/' . $media->id . '?fields=' . $fields . '&access_token=' . $token;
$media_response = wp_safe_remote_get( $request_media_url );
if ( is_array( $media_response ) && ! is_wp_error( $media_response ) ) {
$media_body = json_decode( $media_response['body'] );
}
if ( in_array( $media_body->media_type, $restrict, true ) ) {
$i ++;
$data[] = $media_body;
}
}
}
}
// Store the data in the transient and keep if for an hour.
set_transient( 'instagram_feed_' . $user, $data, HOUR_IN_SECONDS );
// Refresh the token to make sure it never expires (see: https://developers.facebook.com/docs/instagram-basic-display-api/guides/long-lived-access-tokens#refresh-a-long-lived-token)
wp_safe_remote_get( 'https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token=' . $token );
$output = $data;
}
return $output;
}
@thiagobraga
Copy link

Thank you friend, your post helped me a lot. I've used your implementation in JavaScript and it worked perfectly. Facebook has made this process of obtaining data from the API increasingly bureaucratic. It seems that it is not for anyone to use.

@esbenholk
Copy link

This is perfect! @thiagobragga, i am also very interested in hearing how the js syntax has played out for you?

@gsarig
Copy link
Author

gsarig commented Aug 1, 2020

@esbenholk
If you want to use it with JavaScript, and given that we always need it on a WordPress implementation, the simplest way I could think of, would be to simply pass the output of the PHP function to your script using wp_localize_script().

@thiagobraga
Copy link

thiagobraga commented Aug 3, 2020

This is perfect! @thiagobragga, i am also very interested in hearing how the js syntax has played out for you?

Hi friend, I created this Gist. There's some code specific from my project, like the render() function or some jQuery selectors, I'm sorry 🤷‍♂️
Maybe I cleanup sometime lol. I hope it helps anyway!

https://gist.github.com/thiagobraga/0794a33f908eef48d590d19d95fe5e75

@LukeVibes
Copy link

First of all, incredible article. Well written, well coded. One of the only websites explaining this annoying change by Facebook so well :).

My one worry is how you use Transients. According to the WordPress documentation:
transient expiration times are a maximum time. There is no minimum age. Transients might disappear one second after you set them, or 24 hours, but they will never be around after the expiration time.

So it seems possible for the call to be made many times within an hour, as the hour parameter is only acting as a maximum time to wait. Am I misunderstanding something?

@gsarig
Copy link
Author

gsarig commented Dec 16, 2020

First of all, incredible article. Well written, well coded. One of the only websites explaining this annoying change by Facebook so well :).

My one worry is how you use Transients. According to the WordPress documentation:
transient expiration times are a maximum time. There is no minimum age. Transients might disappear one second after you set them, or 24 hours, but they will never be around after the expiration time.

So it seems possible for the call to be made many times within an hour, as the hour parameter is only acting as a maximum time to wait. Am I misunderstanding something?

Hi Luke, and thank you for your comment.

Indeed, you can't rely on transients for time sensitive data, as they can be deleted by a plugin or some other unexpected factor. On that particular case, though, they seem like a nice fit, as we only use them to make sure that no excessive calls will be made. Doing a few more calls withing the timeframe of an hour, which is Instagram's limit, won't hurt, as it is highly unlikely that they will be enough to exceed the limit.

On that note, one improvement that I want to make at some point (probably during Christmas, when hopefully I'll find some free time) is to locally download and store the photos and their IDs. That way, we can have a fallback in case the API call fails to fetch all the photos (on which case we would have to wait an hour until we re-fetch them) and we could also minimize the API calls, avoiding to re-fetch already existing photos, or even further optimize them locally.

@LukeVibes
Copy link

LukeVibes commented Dec 16, 2020

Ah yes! Storing this data Locally as a back-up would be a great idea! Thanks for the response!

Also where do you recommend this code be placed? I am not a WordPress pro (yet) so I'm still not very confident on where to best house this kind of code within a WordPress structure.

@gsarig
Copy link
Author

gsarig commented Dec 17, 2020

Ah yes! Storing this data Locally as a back-up would be a great idea! Thanks for the response!

Also where do you recommend this code be placed? I am not a WordPress pro (yet) so I'm still not very confident on where to best house this kind of code within a WordPress structure.

As a general principle, I would store this in a plugin. For my personal use, I've included it on DareDev, the mu-plugin that I use on most of my sites. In general, anything that has to do with the site's appearance should go to the theme (e.g. the functions.php), and functionality should be on plugins. That way, you can keep the functionality when switching themes.

@Jamiewarb
Copy link

Thanks, this was super helpful. Instagram don't make it clear how to do this unless you know exactly what you're looking for

@kiwopdev
Copy link

@gsarig I only can get one image. do you know what can be the problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment