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

Post thumbnail support #16

Merged
merged 4 commits into from
Jan 10, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
250 changes: 236 additions & 14 deletions wds-multisite-aggregate.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class WDS_Multisite_Aggregate {
protected $total_imported = 0;
protected $doing_save_post = false;
protected $debug = false;
protected static $orig_img_url_key = '_wds_orig_image_url';

public function __construct() {
// Options setter/getter and handles updating options on save
Expand All @@ -79,9 +80,11 @@ function hooks() {
add_action( 'save_post', array( $this, 'do_post_sync' ), 10, 2 );
add_action( 'wds_multisite_aggregate_post_sync', array( $this, 'save_meta_fields' ), 10, 3 );
add_action( 'wp_update_comment_count', array( $this, 'do_comment_sync' ) );
add_action( 'updated_post_meta', array( $this, 'update_thumbnail_meta' ), 10, 4 );

add_action( 'trash_post', array( $this, 'sync_post_delete' ) );
add_action( 'delete_post', array( $this, 'sync_post_delete' ) );
add_action( 'deleted_post_meta', array( $this, 'delete_thumbnail_meta' ), 10, 3 );

if ( ! empty( $_GET['action'] ) && 'populate_posts_from_blog' == $_GET['action'] ) {
define( 'WDS_Multisite_Aggregate', true );
Expand Down Expand Up @@ -306,26 +309,32 @@ function do_post_sync( $post_id, $post ) {

$this->meta_to_sync['permalink'] = get_permalink( $post_id );
$this->meta_to_sync['blogid'] = $post_blog_id; // org_blog_id


// Post thumbnail
if ( $this->options->get( 'tags_blog_thumbs' ) && ( $thumb_id = get_post_thumbnail_id( $post->ID ) ) ) {


// URL for later import in aggregating blog
$this->meta_to_sync['thumbnail_url'] = wp_get_attachment_url( $thumb_id );

// Back compatibility
$thumb_sizes = apply_filters( 'sitewide_tags_thumb_size', array(
'thumbnail' ) );

// back-compat
// Backer (!) compatibility
if ( is_string( $thumb_sizes ) ) {
$this->meta_to_sync['thumbnail_html'] = wp_get_attachment_image( $thumb_id, $thumb_sizes );
} else {
// back-compat
$this->meta_to_sync['thumbnail_html'] = wp_get_attachment_image( $thumb_id, 'thumbnail' );
}

// new hawtness
// new(ish) hawtness
foreach ( (array) $thumb_sizes as $thumb_size ) {
$this->meta_to_sync[ "thumbnail_html_$thumb_size" ] = wp_get_attachment_image( $thumb_id, $thumb_size );
}

}

// custom taxonomies
$taxonomies = apply_filters( 'sitewide_tags_custom_taxonomies', array() );
if ( ! empty( $taxonomies ) && 'publish' == $post->post_status ) {
Expand Down Expand Up @@ -453,6 +462,10 @@ function check_for_site_problems() {

public function save_meta_fields( $post_id, $post, $meta_to_sync ) {
$updated = array();
if ( $this->options->get( 'tags_blog_thumbs' ) && !empty( $meta_to_sync[ 'thumbnail_url' ] ) ) {
$this->set_thumbnail_by_url( $meta_to_sync[ 'thumbnail_url' ], $post_id );
unset( $meta_to_sync[ 'thumbnail_url' ]);
}
foreach ( (array) $meta_to_sync as $key => $value ) {
if ( $value ) {
$updated[ $key ] = add_post_meta( $post_id, $key, $value );
Expand All @@ -461,7 +474,166 @@ public function save_meta_fields( $post_id, $post, $meta_to_sync ) {
// return $this->error( compact( 'post_id', 'updated', 'post' ) );
}

function do_comment_sync( $post_id ) {
/**
*
* When the thumbnail is set and nothing else is done in the admin, no 'save_post' action is fired.
* We need to watch at a lower level (the actual thumbnail meta value) to ensure proper sync to tags site.
*
* @param integer $meta_id Unused; first param for the filter
* @param integer $post_id The post possibly getting a new thumbnail
* @param string $meta_key The meta key. We have to to check all meta values because there's no filter specific to thumbnails
* @param mixed integer|string $thumbnail_id The meta value. If the key is the one we're looking for, this will be the ID to an image attachment.
*/
public function update_thumbnail_meta( $meta_id, $post_id, $meta_key, $thumbnail_id ) {
// Many, many reasons to bail out. We want to prevent needless calls to switch_to_blog. Here we go:

// Not updating a thumbnail
if ( '_thumbnail_id' != $meta_key ) {
return;
}

// Thumbnail is empty: probably means we're deleting, which we'll cover with the delete_meta hook
if ( empty( $thumbnail_id ) ) {
return;
}

$post = get_post( $post_id );

// Only published posts are synced
if ( 'publish' != $post->post_status ) {
return;
}

// Not syncing thumbnails (network config)
if ( ! $this->options->get( 'tags_blog_thumbs' ) ) {
return;
}

// Not an allowed post type
$allowed_post_types = apply_filters( 'sitewide_tags_allowed_post_types', array( 'post' => true ) );
if ( ! isset( $allowed_post_types[ $post->post_type ] ) || ! $allowed_post_types[ $post->post_type ] ) {
return;
}

// We're in the tags/aggregating blog/site
$tags_blog_id = $this->options->get( 'tags_blog_id' );
if ( ! $tags_blog_id || $tags_blog_id == get_current_blog_id() ) {
return;
}

// We're in the clear, let's go!
$post_blog_id = get_current_blog_id();

$thumbnail_url = wp_get_attachment_url( $thumbnail_id );

switch_to_blog( $tags_blog_id );

$global_post_id = $this->get_global_post_id( $post_blog_id, $post_id );

if ( null !== $global_post_id ) {
$this->set_thumbnail_by_url( $thumbnail_url, $global_post_id );
}

restore_current_blog();

}

/**
*
* Takes an image's URL, imports image in WP and assigns it as a post thumbnail
*
* @param string $thumbnail_url Image URL
* @param integer $post_id ID of the post for which the imported image will become the thumbnail
*/
private function set_thumbnail_by_url( $thumbnail_url, $post_id ) {
// Already imported? Just grab the ID
$attachment_id = $this->get_image_id_by_orig_url( $thumbnail_url );

// Not imported yet, import and associate with current post
if ( !$attachment_id ) {
$attachment_id = $this->import_image( $thumbnail_url, $post_id );
}

if ( !$attachment_id ) {
error_log( "Failed to add featured image to post $post_id" );
} else {
set_post_thumbnail( $post_id, $attachment_id );
}
}

/**
*
* Takes an image's URL, adds the image to the Media Library and associates it with a post,
* as if it was uploaded to said post.
*
* @param string $external_image_url Image URL
* @param integer $post_id ID of post to attach image to
* @return bool|int Attachement ID or false when something failed
*/
private function import_image($external_image_url, $post_id ) {
// Get the image from the original site and download to new.
$image_url = media_sideload_image( $external_image_url, $post_id, null, 'src' );
if ( is_wp_error( $image_url ) ) {
return false;
}

// Get the ID of the attachment.
$image_id = $this->get_image_id( $image_url );

// Generate thumbnails, because WP usually do this for us.
wp_generate_attachment_metadata( $image_id, get_attached_file( $image_id ) );

// Save original URL to meta field for later lookups, used to prevent importing same image multiple times
update_post_meta( $image_id, $this::$orig_img_url_key, $external_image_url );

// Add the featured image to the target post.
return $image_id;
}

/**
* Find the ID of a media item, given it's URL.
*
* @param string $image_url URL to the media item.
*
* @return int Media item's ID
*/
protected function get_image_id( $image_url ) {
global $wpdb;
// Query the DB to get the attachment ID.
// @codingStandardsIgnoreStart
$attachment = $wpdb->get_col(
$wpdb->prepare(
'SELECT ID FROM ' . $wpdb->prefix . 'posts' . " WHERE guid='%s';",
$image_url
)
);
// @codingStandardsIgnoreEnd

// ID should be the first element of the returned array.
if ( is_array( $attachment ) && isset( $attachment[0] ) ) {
return $attachment[0];
}

return false;
}


protected function get_image_id_by_orig_url( $orig_image_url ) {
$candidates = get_posts( array(
'post_type' => 'attachment',
'post_status' => 'any',
'meta_query' => array(
array(
'key' => $this::$orig_img_url_key,
'value' => $orig_image_url,
)
)
));
return empty( $candidates ) ? false : $candidates[0]->ID;
}


function do_comment_sync( $post_id ) {
global $wpdb;

$tags_blog_id = $this->options->get( 'tags_blog_id' );
Expand Down Expand Up @@ -489,23 +661,21 @@ function do_comment_sync( $post_id ) {
}

function sync_post_delete( $post_id ) {
global $wpdb;
/*
* what should we do if a post will be deleted and the tags blog feature is disabled?
* need an check if we have a post on the tags blog and if so - delete this
*/
$tags_blog_id = $this->options->get( 'tags_blog_id' );

if ( ! $tags_blog_id || $wpdb->blogid == $tags_blog_id ) {
if ( ! $tags_blog_id || $tags_blog_id == get_current_blog_id() ) {
return;
}

$post_blog_id = $wpdb->blogid;
switch_to_blog( $tags_blog_id );
$post_blog_id = get_current_blog_id();

$guid = "{$post_blog_id}.{$post_id}";
switch_to_blog( $tags_blog_id );

$global_post_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE guid IN (%s,%s)", $guid, esc_url( $guid ) ) );
$global_post_id = $this->get_global_post_id( $post_blog_id, $post_id );

if ( null !== $global_post_id ) {
wp_delete_post( $global_post_id );
Expand All @@ -514,6 +684,39 @@ function sync_post_delete( $post_id ) {
restore_current_blog();
}

/**
*
* Deletes the thumbnail from the tags site when it is deleted from a synced post (which is not deleted itself)
*
* @param array $meta_ids Unused, first parameter of the filter
* @param integer $post_id Post losing its thumbnail
* @param string $meta_key Meta key label. Since there is no filter specific for thumbnails,
* we have to hook into the generic 'meta' filter and inspect the key
*/
function delete_thumbnail_meta($meta_ids, $post_id, $meta_key ) {
if ( '_thumbnail_id' != $meta_key ) {
return;
}

$tags_blog_id = $this->options->get( 'tags_blog_id' );

if ( ! $tags_blog_id || $tags_blog_id == get_current_blog_id() ) {
return;
}

$post_blog_id = get_current_blog_id();

switch_to_blog( $tags_blog_id );

$global_post_id = $this->get_global_post_id( $post_blog_id, $post_id );

if ( null !== $global_post_id ) {
delete_post_thumbnail( $global_post_id );
}

restore_current_blog();
}

protected function get_blogs_to_import() {
if ( $this->options->get( 'populate_all_blogs' ) ) {
global $wpdb;
Expand All @@ -523,6 +726,25 @@ protected function get_blogs_to_import() {
return $this->options->get( 'blogs_to_import', array() );
}


/**
*
* Pass it the ID of a blog (subsite) and the ID of a post (on said blog/subsite)
* and you'll get the ID of the corresponding post on the aggregating blog
* Does not take care of switch_to_blog() for you.
* Beware! It makes no sense to use this outside of the aggregating blog's context
*
* @param $blog_id
* @param $post_id
* @return null|string
*/
private function get_global_post_id($blog_id, $post_id ) {
global $wpdb;
$guid = "{$blog_id}.{$post_id}";

return $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE guid IN (%s,%s)", $guid, esc_url( $guid ) ) );
}

public function save_user_notice() {
if ( $this->total_imported ) {
$class = 'updated';
Expand Down