I have an Instagram widget uses an instagram-scrapper that caches its data in a transient to display photos, based on an username input from the Customizer.
Unfortunately, when I update my username, the transient doesn't update. It uses the old one (from the old username), this, effectively, doesn't let me render photos from the new username, making the widget somewhat useless after the first use.
In short I'm looking for something like:
if( is_updated($username) ? new_transient($username) : get_transient($username)
.
scrapper[skip to next block for the transient bit]:
<?php
namespace Social_Space;
/**
* Interface to scrape most popular JSON-enabled social networks.
*/
interface Scrape_Interface {
/* Builds the end-point, or the link that will be queried */
public function build_endpoint();
/* Ingests the pure, non-altered JSON data */
public function get_json();
/* Handles and cleans the data */
public function get_data();
}
class Scrape_Instagram implements Scrape_Interface {
private $username;
public function set_username( $username ) {
$this->username = $username;
}
/**
* Builds the endpoint for the Instagram API, provided the username from constructor.
* @param $end_cursor Used in case the user wants more pictures to be scrapped.
*/
public function build_endpoint() {
return 'https://www.instagram.com/' . trim( strtolower( $this->username ) ) . '/?__a=1';
}
/**
* GETs the data from Instagram, provided the endpoint.
*/
public function get_json() {
if ( false === ( $data = get_transient( 'instagram_data' ) ) ) {
$request = wp_remote_get( $this->build_endpoint() );
if( is_wp_error( $request ) ) {
return new WP_Error( 'site-down', esc_html__( 'Instagram may be down. Unable to communicate.', '_s') );
}
elseif( wp_remote_retrieve_response_code( $request ) !== 200 ) {
return new WP_Error( 'invalid-response', esc_html__( 'Got an invalid response.', '_s') );
}
else {
set_transient( 'instagram_data', wp_remote_retrieve_body( $request ), 5 );
}
}
return $data;
}
/**
* Ingests the data from get_json() then converts / decodes into an array.
*/
public function get_data() {
$json = $this->get_json();
if( is_wp_error( $json ) ) {
return new WP_Error( 'invalid-json', esc_html__( 'Something is wrong. Did you enter the right username?', '_s' ) );
}
$data = json_decode( $json, true);
if( is_wp_error( $data ) ) {
return new WP_Error( 'invalid-data', esc_html__( 'Something is wrong. Did you enter the right username?', '_s' ) );
} else {
return $data;
}
}
}
class Generate_Instagram_Links {
private $instagram_object;
private $username;
public function __construct( $username, Scrape_Instagram $instagram_object = null ) {
$this->username = $username;
$this->instagram_object = $instagram_object === null ? new Scrape_Instagram : $instagram_object;
$this->instagram_object->set_username( $this->username );
}
/**
* Generates the link to the source image, as well as to the instagram post of each image
* requested by our script.
*/
public function get_links() {
$response = $this->instagram_object->get_data();
/**
* Based on the array generated from get_data(), some nodes have resulted that contain * information about
* each photo the user has, as such, we'll loop through each photo and access any data.
* @see ['user']['media']['nodes'] - individual node / image.
*/
if( is_wp_error( $response ) ) {
return new WP_Error( 'invalid-json', esc_html__( 'Ouch. The data was not parsed correctly. Cannot continue.' ) );
} else {
foreach( $response['user']['media']['nodes'] as $node ) {
$image = array('real_link' => 'src' );
$image['real_link'] = 'https://www.instagram.com/p/' . $node['code'] . '?taken-by=' . $this->username;
$image['src'] = $node['thumbnail_resources'][0]['src'];
$images_links[] = $image;
}
}
return $images_links;
}
/**
* Getter for the instagram links (non-local).
*/
public function get_instagram_photos_links() {
$links = $this->get_links();
if( is_wp_error( $links) ) {
return new WP_error( 'unknown-error', esc_html__( 'Something went wrong. Cannot get data. Check username or contact developer.') );
} else {
return $links;
}
}
/**
* Gets the local photo links of the newly added instagram photo links, or retrieves the
* links if they already exist(to not flood the media library).
* @todo Add an "expiry" date for each image, or remove if no longer used.
*/
private function get_local_links() {
// Requires loading of the wp-admin scripts.
require_once ('wp-load.php');
require_once ('wp-admin/includes/admin.php');
$urls = $this->get_instagram_photos_links();
$local_images = array();
foreach( $urls as $url ) {
$tmp = download_url( $url['src'] );
$file_array = array(
'name' => basename( $url['src'] ),
'tmp_name' => $tmp
);
$wp_upload_dir = wp_get_upload_dir();
$local_url = $wp_upload_dir['path'] . '/' . $file_array['name'];
if( file_exists( $local_url ) ) {
array_push( $local_images, ($wp_upload_dir['url'] . '/' . $file_array['name']) );
} else {
if ( is_wp_error( $tmp ) ) {
@unlink( $file_array[ 'tmp_name' ] );
return $tmp;
}
$GLOBALS['post'] = null;
$post_id = '0';
$id = media_handle_sideload( $file_array, $post_id, $desc = null, $post_data = array('post_content' => 'insta_image' ) );
if ( is_wp_error( $id ) ) {
@unlink( $file_array['tmp_name'] );
return $id;
}
$value = wp_get_attachment_url( $id );
array_push( $local_images, $value );
}
}
return $local_images;
}
/**
* Getter for the instagram links (local).
*/
public function get_instagram_local_photos_links() {
$links = $this->get_local_links();
if( is_wp_error( $links) ) {
return new WP_error( 'unknown-error', esc_html__( 'I cannot get the local links of the pictures. Check with the developer.' ) );
} else {
return $links;
}
}
}
namely the function "get_json":
public function get_json() {
if ( false === ( $data = get_transient( 'instagram_data' ) ) ) {
$request = wp_remote_get( $this->build_endpoint() );
if( is_wp_error( $request ) ) {
return new WP_Error( 'site-down', esc_html__( 'Instagram may be down. Unable to communicate.', '_s') );
}
elseif( wp_remote_retrieve_response_code( $request ) !== 200 ) {
return new WP_Error( 'invalid-response', esc_html__( 'Got an invalid response.', '_s') );
}
else {
set_transient( 'instagram_data', wp_remote_retrieve_body( $request ), 5 );
}
}
return $data;
}
As stated, this won't work. Here's my widget where I check for an update of $username
before doing anything, in the widget()
function.
<?php
/**
* Plugin Name: Instagram Widget
*/
add_action( 'widget_init', 'custom_widget_instagram_pictures');
register_widget( 'custom_widget_instagram_pictures' );
class custom_widget_instagram_pictures extends Wp_Widget {
/**
* Setup the Widget
*/
public function __construct() {
$widget_ops = array('classname' => 'custom_widget_instagram_pictures',
'description' => esc_html__('A widget to display instagram photos.', '_s')
);
$control_ops = array('id_base' => 'custom_widget_instagram_pictures');
parent::__construct( 'custom_widget_instagram_pictures', __('_s: Instagram Widget', '_s_instagram_widget'), $widget_ops, $control_ops );
}
public function widget( $args, $instance ) {
extract( $args );
$title = isset( $instance['title'] ) ? apply_filters('widget_title', $instance['title'] ) : '';
$username = isset( $instance['username'] ) ? $instance['username'] : '';
$profile_link = isset( $instance['profile_link'] ) ? $instance['profile_link'] : '';
$columns = isset( $instance['columns'] ) ? $instance[ 'columns'] : '';
$save_local = isset( $instance['save_local'] ) ? $instance['save_local'] : '';
$number_of_photos = isset( $instance['number_of_photos'] ) ? $instance['number_of_photos'] : '';
echo ent2ncr( $before_widget );
if ( $title ) {
echo ent2ncr( $before_title . $title . $after_title );
}
?>
<div class="instagram-widget">
<?php
if( $username ) {
$instagram_object = new Social_Space\Generate_Instagram_Links( $username, new Social_Space\Scrape_Instagram );
if ( !$save_local ) {
$instagram_links = $instagram_object->get_instagram_photos_links();
if( is_wp_error( $instagram_links ) ) {
echo "Ouch. Something's wrong. Did you enter the right username?";
} else {
$instagram_links_parsed = 0;
?>
<ul class="instagram-widget-list">
<?php
foreach( $instagram_links as $link ) {
if ( $instagram_links_parsed < absint( $number_of_photos ) ) {
$instagram_links_parsed++;
?>
<li class="instagram-thumb instagram-thumb-<?php echo $columns ?>-col">
<a href="<?php echo $link['real_link']; ?>"><img src="<?php echo $link['src']; ?>"/></a>
</li>
<?php
}
else {
break;
}
}
?>
</ul>
<?php
}
}
elseif ( $save_local ) {
$instagram_links = $instagram_object->get_instagram_local_photos_links();
if( is_wp_error( $instagram_links ) ) {
echo "Ouch. Something's wrong. Did you enter the right username?";
} else {
$instagram_links_parsed = 0;
?>
<ul class="instagram-widget-list">
<?php
foreach( $instagram_links as $link ) {
if ( $instagram_links_parsed < absint( $number_of_photos ) ) {
$instagram_links_parsed++;
?>
<li class="instagram-thumb instagram-thumb-<?php echo $columns ?>-col">
<a href="<?php echo $link; ?>"><img src="<?php echo $link; ?>"/></a>
</li>
<?php
}
else {
break;
}
}
?>
</ul>
<?php
}
}
} else {
echo _s_setup_widget_notification();
} ?>
<?php if( 'on' == $profile_link ) : ?>
<button class="instagram-widget-profile-link"><a href="<?php echo 'https://www.instagram.com/' . $username; ?>"><i class="sf-4"></i><p><?php echo $username ?></p></a></button>
<?php endif; ?>
</div>
<?php
echo ent2ncr( $after_widget );
}
function update( $new_instance, $old_instance ) {
$instance['title'] = ( isset( $new_instance['title'] ) ) ? strip_tags($new_instance['title'] ) : '';
$instance['username'] = ( isset( $new_instance['username'] ) ) ? strip_tags( $new_instance['username'] ) : '';
$instance['profile_link'] = ( isset( $new_instance['profile_link'] ) ) ? strip_tags( $new_instance['profile_link'] ) : '';
$instance['columns'] = ( isset( $new_instance['columns'] ) ) ? strip_tags( $new_instance['columns'] ) : '';
$instance['save_local'] = ( isset( $new_instance['save_local'] ) ) ? strip_tags( $new_instance['save_local'] ) : '';
$instance['number_of_photos'] = ( isset( $new_instance['number_of_photos'] ) ) ? strip_tags( $new_instance['number_of_photos'] ) : '';
return $instance;
}
function form( $instance ) {
$defaults = array( 'title' => '',
'username' => '',
'profile_link' => '',
'columns' => '3',
'save_local' => '',
'number_of_photos' => '12',
);
$instance = wp_parse_args( (array) $instance, $defaults ); ?>
<!-- Custom Message -->
<div class="customizer-custom-message-1">
<p>Hey! Just one second. We strongly advise you keep an "even" number of images, 3 columns should have 3,6,9...photos. A 2 columns layout should have 2,4,6 and so on. Looks much better this way! </p>
</div>
<!-- Form for Title -->
<p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>">Widget Title:<strong>(Leave Blank to Hide)</strong></label>
<br>
<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo $instance['title'];?>" />
</p>
<!-- Form for Username -->
<p>
<label for="<?php echo $this->get_field_id( 'username' ); ?>">Username:</label>
<br>
<input class="widefat" id="<?php echo $this->get_field_id( 'username' ); ?>" name="<?php echo $this->get_field_name( 'username' ); ?>" value="<?php echo $instance['username'];?>" />
</p>
<!-- Checkbox for Local -->
<p>
<input class="checkbox" type="checkbox" <?php checked( $instance[ 'save_local' ], 'on' ); ?> id="<?php echo $this->get_field_id( 'save_local' ); ?>" name="<?php echo $this->get_field_name( 'save_local' ); ?>" />
<label for="<?php echo $this->get_field_id( 'save_local' ); ?>">Save Images to Local</label>
</p>
<!-- Checkbox for Profile Link -->
<p>
<input class="checkbox" type="checkbox" <?php checked( $instance[ 'profile_link' ], 'on' ); ?> id="<?php echo $this->get_field_id( 'profile_link' ); ?>" name="<?php echo $this->get_field_name( 'profile_link' ); ?>" />
<label for="<?php echo $this->get_field_id( 'profile_link' ); ?>">Show Instagram Button?</label>
</p>
<!-- Columns -->
<p>
<label for="<?php echo $this->get_field_id( 'columns' ); ?>">How Many Columns to Display?<strong>(Leave Blank to Hide)</strong></label>
<br>
<input class="widefat" id="<?php echo $this->get_field_id( 'columns' ); ?>" name="<?php echo $this->get_field_name( 'columns' ); ?>" value="<?php echo $instance['columns'];?>" />
</p>
<!-- Number of Photos -->
<p>
<label for="<?php echo $this->get_field_id( 'number_of_photos' ); ?>">How Many Pictures?</label>
<br>
<input class="widefat" id="<?php echo $this->get_field_id( 'number_of_photos' ); ?>" name="<?php echo $this->get_field_name( 'number_of_photos' ); ?>" value="<?php echo $instance['number_of_photos'];?>" />
</p>
<?php
}
}