options = get_option( $this->prefix );
}
/////////////////////////////////////////////////////////////////////////////////////
// Hooks
/////////////////////////////////////////////////////////////////////////////////////
/**
* Triggered when a post is being saved.
*/
public function edit_post( $post_id ) {
// We are going to update the post from within this filter, so we need to prevent an infinite loop.
if ( $this->allow_edit_post_filter && isset( $this->options['on_post_update'] ) && $this->options['on_post_update'] ) {
$this->crunch( $post_id );
}
}
/**
* Triggered when an attachment is being uploaded or saved.
*/
public function edit_attachment( $attachment_id ) {
error_log( 'ZZZZZZZZZZZZZZZZZZZZZ' );
if ( $this->allow_edit_post_filter && isset( $this->options['on_attachment_update'] ) && $this->options['on_attachment_update'] ) {
$attachment = get_post( $attachment_id );
$post_id = $attachment->post_parent;
if ( ! $post_id ) {
return;
}
$this->crunch( $post_id );
}
}
/**
* Triggered when an attachment is being attached to a post.
*
* Thanks for this hook to http://stackoverflow.com/users/1981996/diggy
* who answered this question http://stackoverflow.com/questions/16798615/attach-media-to-post-wordpress-hook
*/
public function wp_redirect( $location ) {
if( ! is_admin() )
return $location;
if ( $this->allow_edit_post_filter && isset( $this->options['on_attach'] ) && $this->options['on_attach'] ) {
global $pagenow;
if( 'upload.php' == $pagenow && isset( $_REQUEST['found_post_id'] ) ) {
$parent_id = (int) $_REQUEST['found_post_id'];
if ( ! $parent_id )
return $location;
$this->crunch( $parent_id );
error_log('RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR');
error_log( $parent_id );
error_log('RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR');
}
}
return $location;
}
/////////////////////////////////////////////////////////////////////////////////////
// Top Level Functions
/////////////////////////////////////////////////////////////////////////////////////
/**
* Returns IDs of all atachments added to the post content.
*/
private function get_inline_attachments( $post_id ) {
$post = get_post( $post_id );
if ( ! $post ) {
return array();
}
// Find all attachment IDs.
preg_match_all('/]*wp-image-(\d+)[^>]*\/>/', $post->post_content, $matches);
if ( isset( $matches[1] ) && is_array( $matches[1] ) ) {
return $matches[1];
} else {
return array();
}
}
/**
* Returns IDs of all atachments attached to the post.
*/
private function get_attached_attachments( $post_id ) {
// Collect attachments objects
$attachment_posts = get_posts( array(
'post_type' => 'attachment',
'numberposts' => null,
'post_status' => null,
'post_parent' => $post_id
) );
// Return only IDs.
return array_map( function ( $attachment ) {
return $attachment->ID;
}, $attachment_posts );
}
/**
* Transfers values from attachments related to post according to plugin options.
*
* @param integer $post_id ID of the post to be crunched.
*/
public function crunch( $post_id ) {
$attachment_ids = array();
// Collect inline attachments.
if ( isset( $this->options['include_inline'] ) && $this->options['include_inline'] ) {
$attachment_ids = array_merge( $attachment_ids, $this->get_inline_attachments( $post_id ) );
}
// Collect attachments atached to the post.
if ( isset( $this->options['include_attached'] ) && $this->options['include_attached'] ) {
$attachment_ids = array_merge( $attachment_ids, $this->get_attached_attachments( $post_id ) );
}
$attachment_ids = array_unique( $attachment_ids );
// crunch
$this->allow_edit_post_filter = FALSE;
$this->attachments_to_post( $post_id, $attachment_ids );
$this->allow_edit_post_filter = TRUE;
}
/**
* Transfers values from passed attachments to post according to plugin options.
*
* @param integer $post_id ID of the post to be crunched.
* @param array $attachment_ids Array of attachment IDs to be used as sources.
*/
private function attachments_to_post( $post_id, $attachment_ids ) {
$this->crunch_properties( $post_id, $attachment_ids );
$this->crunch_metas( $post_id, $attachment_ids );
$this->crunch_taxonomies( $post_id, $attachment_ids );
}
/////////////////////////////////////////////////////////////////////////////////////
// Simple post properties
/////////////////////////////////////////////////////////////////////////////////////
/**
* Returns value extracted from attachment property specified in $source_array.
*
* @param array $source_array Array of the form array('source' => 'source name', 'meta' => 'meta name').
* @param integer $attachment_id ID of the attachment.
*
* @return string The extracted value.
*/
private function get_source_value( $source_array, $attachment_ids ) {
// Dont bother if there is no source or attachments
if ( ! isset( $source_array['source'] ) || ! $source_array['source'] || ! $attachment_ids ) {
return;
}
$multiple = isset( $source_array['multiple'] ) ? $source_array['multiple'] : '';
$param = isset( $source_array['param'] ) ? $source_array['param'] : '';
// If first, slice the array to its first item.
if ( $multiple == 'first' ) {
if( isset( $attachment_ids[0] ) ) {
$attachment_ids = array( $attachment_ids[0] );
} else {
return;
}
}
// If last, slice the array to its last item.
if ( $multiple == 'last' ) {
end( $attachment_ids );
$attachment_ids = array( $attachment_ids[ key( $attachment_ids ) ] );
}
// Loop through attachment IDs/
$results = array();
foreach ( $attachment_ids as $key => $value ) {
$attachment = get_post( $value );
// Get the values.
if ( $attachment ) {
$value = '';
switch ( $source_array['source'] ) {
case 'title':
$value = $attachment->post_title;
break;
case 'caption':
$value = $attachment->post_excerpt;
break;
case 'description':
$value = $attachment->post_content;
break;
case 'alt':
$value = get_post_meta( $attachment->ID, '_wp_attachment_image_alt', TRUE );
break;
case 'meta':
if ( isset( $source_array['meta'] ) ) {
$value = get_post_meta( $attachment->ID, $source_array['meta'], TRUE );
}
break;
}
// Return first found value.
if ( $multiple == 'contains' ) {
preg_match("/.*$param.*/", $value, $match );
if ( $match && isset( $match[0] ) ) {
return $match[0];
}
}
array_push( $results, $value );
}
}
// Remove empty items and repeating values.
$results = array_filter( $results );
$results = array_unique( $results );
// Proces and return results.
switch ( $multiple ) {
case 'first':
return $results[0];
case 'last':
end( $results );
return $results[ key( $results ) ];
case 'frequent':
$c = array_count_values( $results );
return array_search( max( $c ), $c );
case 'concat':
return implode( $param, $results );
}
}
/**
* Updates the post properties according to options and passed attachments.
*
* @param integer $post_id ID of the post to be crunched.
* @param array $attachment_ids Array of attachment IDs to be used as sources.
*/
private function crunch_properties( $post_id, $attachment_ids ) {
$post = get_post( $post_id );
// Don't bother if there's no post.
if ( ! $post ) {
return;
}
if ( isset( $this->options['title'] ) ) {
$post->post_title = $this->get_source_value( $this->options['title'], $attachment_ids );
}
if ( isset( $this->options['excerpt'] ) ) {
$post->post_excerpt = $this->get_source_value( $this->options['excerpt'], $attachment_ids );
}
if ( isset( $this->options['content'] ) ) {
$post->post_content = $this->get_source_value( $this->options['content'], $attachment_ids );
}
wp_update_post( $post );
}
/////////////////////////////////////////////////////////////////////////////////////
// Post metas
/////////////////////////////////////////////////////////////////////////////////////
/**
* Updates the post metas according to options and passed attachments.
*
* @param integer $post_id ID of the post to be crunched.
* @param array $attachment_ids Array of attachment IDs to be used as source.
*/
private function crunch_metas( $post_id, $attachment_ids ) {
// loop through $this->options['metas']
if ( isset( $this->options['metas'] ) && is_array( $this->options['metas'] ) ) {
foreach ( $this->options['metas'] as $meta_key => $source_array ) {
$this->crunch_meta( $post_id, $meta_key, $source_array, $attachment_ids );
}
}
}
/**
* Updates single post meta according to options and passed attachments.
*
* @param integer $post_id ID of the post to be crunched.
* @param string $meta_key Key of the meta.
* @param array $source_array The setting array for the meta key.
* @param array $attachment_ids Array of attachment IDs to be used as source.
*/
private function crunch_meta( $post_id, $meta_key, $source_array, $attachment_ids ) {
$value = $this->get_source_value( $source_array, $attachment_ids );
add_post_meta( $post_id, $meta_key, $value, TRUE ) || update_post_meta( $post_id, $meta_key, $value );
}
/////////////////////////////////////////////////////////////////////////////////////
// Post taxonomies
/////////////////////////////////////////////////////////////////////////////////////
/**
* Crunches all taxonomies.
*/
private function crunch_taxonomies( $post_id, $attachment_ids ) {
if ( isset( $this->options['taxonomies'] ) ) {
foreach ( $this->options['taxonomies'] as $key => $value) {
$this->crunch_taxonomy( $key, $post_id, $attachment_ids );
}
}
}
private function test() {
//$res = $this->get_terms_for_taxonomy( 'post_tag', get_post(5187) );
//return gettype($res[0]);
$this->crunch_taxonomies( 5137, array(5150) );
}
/**
* Crunches the specified taxonomy of a post.
*
* @param string $taxonomy Taxonomy name.
* @param integer $post_id The ID of post to be crunched.
* @param array $attachment_ids Array of attachment IDs to be used as source.
*/
private function crunch_taxonomy( $taxonomy, $post_id, $attachment_ids ) {
$post = get_post( $post_id );
if ( taxonomy_exists( $taxonomy ) && $post ) {
$term_ids = array();
foreach ( $attachment_ids as $id ) {
$attachment_post = get_post( $id );
$term_ids = array_merge( $term_ids, $this->get_terms_for_taxonomy( $taxonomy, $attachment_post ) );
}
wp_set_object_terms( $post->ID, $term_ids, $taxonomy );
}
}
/**
* Returns an array of taxonomy terms for a taxonomy.
*/
private function get_terms_for_taxonomy( $taxonomy, $attachment_post ) {
$taxonomy_setting = isset( $this->options['taxonomies'][ $taxonomy ] ) ? $this->options['taxonomies'][ $taxonomy ] : null ;
$term_ids = array();
// Loop through properties
foreach ( $taxonomy_setting as $key => $value ) {
if ( $key != 'metas' && isset( $value['enable'] ) && $value['enable'] == 'on' ) {
$delimiter = isset( $value['delimiter'] ) ? $value['delimiter'] : '';
$handle_as = isset( $value['handle_as'] ) ? $value['handle_as'] : 'names';
$create = isset( $value['create'] ) ? $value['create'] : FALSE;
switch ( $key ) {
case 'title':
$value = $attachment_post->post_title;
break;
case 'caption':
$value = $attachment_post->post_excerpt;
break;
case 'description':
$value = $attachment_post->post_content;
break;
case 'alt':
$value = get_post_meta( $attachment_post->ID, '_wp_attachment_image_alt', TRUE );
break;
default:
$value = '';
break;
}
$term_ids = array_merge( $term_ids, $this->get_terms_for_source( $taxonomy, $value, $delimiter, $handle_as, $create ) );
}
}
// Loop through metas
if ( isset( $taxonomy_setting['metas'] ) ) {
foreach ( $taxonomy_setting['metas'] as $key => $value ) {
$delimiter = isset( $value['delimiter'] ) ? $value['delimiter'] : '';
$handle_as = isset( $value['handle_as'] ) ? $value['handle_as'] : 'names';
$create = isset( $value['create'] ) ? $value['create'] : FALSE;
$value = get_post_meta( $attachment_post->ID, $key, TRUE );
$term_ids = array_merge( $term_ids, $this->get_terms_for_source( $taxonomy, $value, $delimiter, $handle_as, $create ) );
}
}
// Remove empty values.
return array_filter( $term_ids );
}
/**
* Returns array of taxonomy term IDs extracted from a taxonomy source row
*
* @param string $taxonomy Taxonomy name.
* @param string $value Value to be parsed.
* @param string $delimiter Delimiter upon which the valus will be split.
* @param string $handle_as Either "names", "ids" or "slugs".
* @param boolean $create If TRUE, missing terms will be created.
*
* @return array Array of taxonomy term object IDs.
*/
private function get_terms_for_source( $taxonomy, $value, $delimiter, $handle_as, $create ) {
// Map handle_as names to wp field names.
$fields = array(
'names' => 'name',
'slugs' => 'slug',
'ids' => 'id',
);
// Allow creation only by names
if ( $handle_as != 'names' ) {
$create = FALSE;
}
// Resolve field.
$field = $fields[ $handle_as ];
// Split values.
$values = explode( $delimiter, $value );
// Get terms.
$term_ids = array();
foreach ( $values as $k => $v ) {
array_push( $term_ids, $this->get_or_create_term( $field, trim( $v ), $taxonomy, $create ) );
}
return $term_ids;
}
/**
* Returns an ID of taxonomy term object.
*
* @param string $field Either 'name', 'slug' or 'id'.
* @param string|integer $value Search for this term value
* @param bool $create If TRUE and the term doesn't exist, it will be created.
*
* @return integer Taxonomy term object ID.
*/
private function get_or_create_term( $field, $value, $taxonomy, $create ) {
// Get term.
$term = get_term_by( $field, $value, $taxonomy );
// Create term.
if ( !$term && $create ) {
if ( taxonomy_exists( $taxonomy ) ) {
$new_term_info = wp_insert_term( $value, $taxonomy );
if ( is_array( $new_term_info ) && isset( $new_term_info['term_id'] ) ) {
$new_term_id = $new_term_info['term_id'];
$term = get_term_by( 'id', $new_term_id, $taxonomy );
}
}
}
return isset( $term->term_id ) ? (integer) $term->term_id : null ;
}
/////////////////////////////////////////////////////////////////////////////////////
// Plugin settings
/////////////////////////////////////////////////////////////////////////////////////
/**
* Adds action links to the plugin
*
* @return updated plugin links
*/
public function plugin_action_links( $links, $file ) {
static $this_plugin;
if ( ! $this_plugin ) {
$this_plugin = plugin_basename( __FILE__ );
}
if ( $file == $this_plugin ) {
$url = esc_url( admin_url( "plugins.php?page={$this->settings_slug}" ) );
$settings_link = "Settings";
array_unshift( $links, $settings_link );
}
return $links;
}
/**
* Adds action links to the plugin row
*
* @return updated plugin links
*/
public function plugin_row_meta( $links, $file ) {
if ( $file == plugin_basename( __FILE__ ) ) {
$url = esc_url( admin_url( "plugins.php?page={$this->settings_slug}" ) );
$links[] = "Settings";
$links[] = "donate_url\">Donate";
}
return $links;
}
/**
* Plugin options callback
*/
public function admin_menu() {
$page = add_plugins_page(
$this->plugin_name,
$this->plugin_name,
'manage_options',
"{$this->settings_slug}",
array( $this, 'options_cb' )
);
add_action( 'admin_print_scripts-' . $page, array( $this, 'js' ) );
add_action( 'admin_print_styles-' . $page, array( $this, 'css' ) );
}
function js() { wp_enqueue_script( "{$this->prefix}_script" ); }
function css() { wp_enqueue_style( "{$this->prefix}_style" ); }
/**
* Default plugin options
*/
public function defaults() {
// add_option
// update_option
// delete_option( $this->prefix );
add_option( $this->prefix, array(
'version' => $this->version,
'inline_attachments' => null,
'post_attachments' => null,
'title' => array(
'source' => '',
'meta' => '',
),
'excerpt' => array(
'source' => '',
'meta' => '',
),
'metas' => array(),
'taxonomies' => array(),
) );
}
/**
* Options page callback
*/
public function options_cb() { ?>
This plugin allows you to transfer informations from media attachments to the post to which they are attached.
Choose when the plugin will do it's job.
'When the post is being saved.', 'on_attachment_update' => 'When an attachment attached to the post is being added or saved.', 'on_attach' => 'When an attachment is being attached to a post.' ); ?> $title ): ?> prefix}[$key]"; ?>" options[$key] ) ? $this->options[$key] : '' ); ?>>Choose which attachments will be taken into account.
'Inline attachments inside post content.', 'include_attached' => 'Attachments attached to the post.', ); ?> $title ): ?> prefix}[$key]"; ?>" options[$key] ) ? $this->options[$key] : '' ); ?>>Choose which attachment property will be used as the value of post properties. If you don't want a property to be changed, choose the first blank item. You can also choose what to do when there are multiple attachments. Some of the options allow you to specify an additional parameter.
Be careful with this setting, the original values of the post properties will be replaced with the new values!
Choose which attachment property will be used as the value of post meta.
Choose which attachment properties will be used as sorces for the post taxonomy terms.
To use an attachment property as a source, check the checkbox next to the property name.
Set the delimiter to split the value to terms (a coma by coma-separated values for instance).
If you omit the delimiter, the whole value will be used as a single term.
Set how the split terms should be handled.
Only existing terms will be used, except when Handle as is set to Names ,
where you can choose to create terms which were not found in the database.
You can choose multiple sources for a single taxonomy.
The plugin will first collect and eventually create all terms extracted from the source
and finally add all the terms to the post.
If you encounter any errors or unexpected behaviour, please send me the error description together with the content of the debug info.
Show debug infooptions ) ?>
Created due to popular demand by me Peter Hudec. You cand find out more about me at peterhudec.com.
The source code of the plugin is hosted on GitHub.
This plugin is and allways will be free but if you can't help yourself and want to pay for it anyway, you can do so by clicking the button below :-)