.
*
* Followed the following tutorials
* http://wpengineer.com/2076/add-custom-field-attachment-in-wordpress/
* http://bueltge.de/eigene-felder-dateiverwaltung-wordpress/1226/ (same like above, but in German)
*
*
*/
//avoid direct calls to this file
if (!function_exists('add_action')) {
header('Status: 403 Forbidden');
header('HTTP/1.1 403 Forbidden');
exit();
}
define('ISCVERSION', '1.1.3');
define('ISCNAME', 'Image Source Control');
define('ISCTEXTDOMAIN', 'isc');
define('ISCDIR', basename(dirname(__FILE__)));
define('ISCPATH', plugin_dir_path(__FILE__));
load_plugin_textdomain(ISCTEXTDOMAIN, false, dirname(plugin_basename(__FILE__)) . '/languages/');
if (!class_exists('ISC_CLASS')) {
class ISC_CLASS
{
/**
* define default meta fields
*/
protected $_fields = array(
'image_source' => array(
'id' => 'isc_image_source',
'default' => '',
),
'image_source_own' => array(
'id' => 'isc_image_source_own',
'default' => '',
)
);
/**
* allowed image file types/extensions
* @since 1.1
*/
protected $_allowedExtensions = array(
'jpg', 'png', 'gif'
);
/**
* Setup registers filterts and actions.
*/
public function __construct()
{
// insert all function for the frontend here
add_shortcode('isc_list', array($this, 'list_post_attachments_with_sources_shortcode'));
add_shortcode('isc_list_all', array($this, 'list_all_post_attachments_sources_shortcode'));
// insert all backend functions below this check
if (!current_user_can('upload_files')) {
return false;
}
add_filter('attachment_fields_to_edit', array($this, 'add_isc_fields'), 10, 2);
add_filter('attachment_fields_to_save', array($this, 'isc_fields_save'), 10, 2);
add_action('admin_menu', array($this, 'create_menu'));
add_action('admin_enqueue_scripts', array($this, 'add_admin_scripts'));
// ajax function; 'add_meta_fields' is the action defined in isc.js as the action to be called via ajax
add_action('wp_ajax_add_meta_fields', array($this, 'add_meta_values_to_attachments'));
// save image information in meta field when a post is saved
add_action('save_post', array($this, 'save_image_information_on_post_save'));
}
/**
* create the menu pages for isc
*/
public function create_menu()
{
// this page should be accessable by editors and higher
$menuhook = add_submenu_page('upload.php', 'missing image sources by Image Source Control Plugin', __('Missing Sources', ISCTEXTDOMAIN), 'edit_others_posts', ISCPATH . '/templates/missing_sources.php', '');
}
/**
* add scripts to admin pages
* @since 1.0
* @update 1.1.1
*/
public function add_admin_scripts($hook)
{
if ($hook != 'image-source-control-isc/templates/missing_sources.php') {
return;
}
wp_enqueue_script('isc_script', plugins_url('/js/isc.js', __FILE__), false, ISCVERSION);
// this is to define ajaxurl to be able to use this in its own js script
// wp_localize_script( 'isc_script', 'IscAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
}
/**
* add custom field to attachment
* @param arr $form_fields
* @param object $post
* @return arr
* @since 1.0
* @updated 1.1
*/
public function add_isc_fields($form_fields, $post)
{
// add input field for source
$form_fields['isc_image_source']['label'] = __('Image Source', ISCTEXTDOMAIN);
$form_fields['isc_image_source']['value'] = get_post_meta($post->ID, 'isc_image_source', true);
$form_fields['isc_image_source']['helps'] = __('Include the image source here.', ISCTEXTDOMAIN);
// add checkbox to mark as your own image
$form_fields['isc_image_source_own']['input'] = 'html';
$form_fields['isc_image_source_own']['label'] = '';
$form_fields['isc_image_source_own']['helps'] =
__('Check this box if this is your own image and doesn\'t need a source.', ISCTEXTDOMAIN);
$form_fields['isc_image_source_own']['html'] =
"ID, 'isc_image_source_own', true), 1, false )
. " style=\"width:14px\"/> "
. __('This is my image', ISCTEXTDOMAIN);
return $form_fields;
}
/**
* save image source to post_meta
* @param object $post
* @param $attachment
* @return object $post
*/
public function isc_fields_save($post, $attachment)
{
if (isset($attachment['isc_image_source'])) {
update_post_meta($post['ID'], 'isc_image_source', $attachment['isc_image_source']);
}
update_post_meta($post['ID'], 'isc_image_source_own', $attachment['isc_image_source_own']);
return $post;
}
/**
* create image sources list for all images of this post
* @since 1.0
* @update 1.1
* @param int $post_id id of the current post/page
* @return echo output
*/
public function list_post_attachments_with_sources($post_id = 0)
{
global $post;
if (empty($post_id)) {
if (!empty($post->ID)) {
$post_id = $post->ID;
} else {
return;
}
}
$attachments = get_post_meta($post_id, 'isc_post_images', true);
// if attachments is an empty string, search for images in it
if ($attachments == '') {
$this->save_image_information_on_load ($post_id, $_content);
$attachments = get_post_meta($post_id, 'isc_post_images', true);
}
$return = '';
if (!empty($attachments)) {
$atts = array();
foreach ($attachments as $attachment_id => $attachment_array) {
$atts[$attachment_id]['title'] = get_the_title($attachment_id);
$own = get_post_meta($attachment_id, 'isc_image_source_own', true);
$source = get_post_meta($attachment_id, 'isc_image_source', true);
if ( $own == '' && $source == '' ) {
// remove if no information set
unset($atts[$attachment_id]);
continue;
} elseif ($own != '') {
$atts[$attachment_id ]['source'] = __('by the author', ISCTEXTDOMAIN);
} else {
$atts[$attachment_id ]['source'] = $source;
}
}
$return = $this->_renderAttachments($atts);
}
return $return;
}
/**
* @param array $attachments
*/
protected function _renderAttachments($attachments)
{
// don't display anything, if no image sources displayed
if ($attachments == array()) {
return ;
}
ob_start();
// TODO this is almost trivial to replace with sprintf
?>
$atts_array) :
if (empty($atts_array['source'])) {
continue;
}
// TODO localise
?>
0), $atts));
// if $id not set, use the current ID from the post
if (empty($id)) {
$id = $post->ID;
}
if (empty($id)) {
return;
}
return $this->list_post_attachments_with_sources($id);
}
/**
* get all attachments without sources
* the downside of this function: is there is not even an empty metakey field, nothing is going to be retrieved
* @todo fix this in WP 3.5 with compare => 'NOT EXISTS'
*/
public function get_attachments_without_sources()
{
$args = array(
'post_type' => 'attachment',
'numberposts' => -1,
'post_status' => null,
'post_parent' => null,
'meta_query' => array(
// image source is empty
array(
'key' => 'isc_image_source',
'value' => '',
'compare' => '=',
),
// and image source is not set
array(
'key' => 'isc_image_source_own',
'value' => '1',
'compare' => '!=',
),
)
);
$attachments = get_posts($args);
if (!empty($attachments)) {
return $attachments;
}
}
/**
* add meta values to all attachments
* @todo probably need to fix this when more fields are added along the way
* @todo use compare => 'NOT EXISTS' when WP 3.5 is up to retrieve only values where it is not set
* @todo this currently updates all empty fields; empty in this context is empty string, 0, false or not existing; add check if meta field already existed before
*/
public function add_meta_values_to_attachments()
{
// retrieve all attachments
$args = array(
'post_type' => 'attachment',
'numberposts' => -1,
'post_status' => null,
'post_parent' => null,
);
$attachments = get_posts($args);
if (empty($attachments)) {
return;
}
$count = 0;
foreach ($attachments as $_attachment) {
$set = false;
setup_postdata($_attachment);
foreach ($this->_fields as $_field) {
$meta = get_post_meta($_attachment->ID, $_field['id'], true);
if (empty($meta)) {
update_post_meta($_attachment->ID, $_field['id'], $_field['default']);
$set = true;
}
}
if ($set) {
$count++;
}
}
echo sprintf(__('Added meta fields to %d images.', ISCTEXTDOMAIN), $count) .
' ';
die();
}
/**
* show the loading image from wp-admin/images/loading.gif
* @param bool $display should this be displayed directly or hidden? via inline css
*/
public function show_loading_image($display = true)
{
$img_path = admin_url("/images/loading.gif");
$file_path = ABSPATH . "wp-admin/images/loading.gif";
if (file_exists($file_path)) {
echo '';
}
}
/**
* this is an entry function to save image information to a post when it is saved
* @since 1.1
* @param type $post_id
*/
public function save_image_information_on_post_save($post_id)
{
// return, if save_post is called more than one time
if (did_action('save_post') !== 1) {
return;
}
if (isset($_POST['post_type']) && 'attachment' == $_POST['post_type']) {
return;
}
// check if this is a revision and if so, use parent post id
if ($_id = wp_is_post_revision($post_id)) {
$post_id = $_id;
}
$_content = stripslashes($_REQUEST['content']);
$this->save_image_information($post_id, $_content);
}
/**
* save image information for a post when it is viewed and the image source list is enabled
* (this is in case the plugin is new and the current post wasn't saved before)
*
* @since 1.1
*/
public function save_image_information_on_load()
{
global $post;
if (empty($post->ID)) {
return;
}
$post_id = $post->ID;
$_content = $post->post_content;
$this->save_image_information($post_id, $_content);
}
/**
* retrieve images added to a post or page and save all information as a meta value
* @since 1.1
* @todo check for more post types that maybe should not be parsed here
*/
public function save_image_information($post_id, $_content)
{
$_image_urls = $this->_filter_src_attributes($_content);
$_imgs = array();
foreach ($_image_urls as $_image_url) {
// get ID of images by url
$img_id = $this->get_image_by_url($_image_url);
$_imgs[$img_id] = array(
'src' => $_image_url
);
}
// add thumbnail information
$thumb_id = get_post_thumbnail_id($post_id);
$_imgs[$thumb_id] = array(
'src' => wp_get_attachment_url($thumb_id),
'thumbnail' => true
);
// TODO _imgs is an non-empty array by now
if (empty($_imgs)) {
$_imgs = false;
}
update_post_meta($post_id, 'isc_post_images', $_imgs);
}
/**
* filter image src attribute from text
* @since 1.1
* @updated 1.1.3
* @return array with image src uris
*/
public function _filter_src_attributes($content = '')
{
$srcs = array();
if (empty($content))
return $srcs;
// parse HTML with DOM
$dom = new DOMDocument;
$dom->loadHTML($content);
foreach ($dom->getElementsByTagName('img') as $node) {
$srcs[] = $node->getAttribute('src');
}
return $srcs;
}
/**
* get image by url accessing the database directly
* @since 1.1
* @updated 1.1.3
* @param string $url url of the image
* @return id of the image
*/
public function get_image_by_url($url = '')
{
if (empty($url)) {
return 0;
}
$types = implode('|', $this->_allowedExtensions);
// check for the format 'image-title-(e12452112-)300x200.jpg' and remove the image size and edit mark from it
$newurl = preg_replace("/(-e\d+){0,1}-(\d+)x(\d+)\.({$types})$/i", '.${4}', $url);
global $wpdb;
$query = $wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE guid = %s", $newurl);
$id = $wpdb->get_var($query);
return $id;
}
/**
* create shortcode to list all image sources in the frontend
* @param array $atts
* @since 1.1.3
* @todo link to the post
*/
public function list_all_post_attachments_sources_shortcode($atts = array())
{
/**
* @todo why not translate here with the code below?
*/
extract(shortcode_atts(array(
'per_page' => 99999,
'before_links' => '',
'after_links' => '',
'prev_text' => '« Previous',
'next_text' => 'Next »'
),
$atts));
/**
* @todo why not include this into the array above?
*/
if ('« Previous' == $prev_text)
$prev_text = __('« Previous', ISCTEXTDOMAIN);
if ('Next »' == $next_text)
$next_text = __('Next »', ISCTEXTDOMAIN);
// retrieve all attachments
$args = array(
'post_type' => 'attachment',
'numberposts' => -1,
'post_status' => null,
'post_parent' => null,
/** @todo maybe add offset to not retrieve the first results when not on first page */
/** @todo maybe add limit to not retrieve more results than on the current page */
);
$attachments = get_posts($args);
if (empty($attachments)) {
return;
}
$connected_atts = array();
//Keeps only those ones who have parent
foreach ($attachments as $_attachment) {
if ($_attachment->post_parent) {
$connected_atts[$_attachment->ID]['source'] = get_post_meta($_attachment->ID, 'isc_image_source', true);
$connected_atts[$_attachment->ID]['own'] = get_post_meta($_attachment->ID, 'isc_image_source_own', true);
$connected_atts[$_attachment->ID]['title'] = $_attachment->post_title;
$connected_atts[$_attachment->ID]['parent'] = get_the_title($_attachment->post_parent);
}
}
$total = count($connected_atts);
if (0 == $total)
return;
$page = isset($_GET['isc-page']) ? intval($_GET['isc-page']) : 1;
$down_limit = 1; // First page
$up_limit = 1;
if ($per_page < $total) {
$rem = $total % $per_page; // The Remainder of $total/$per_page
$up_limit = ($total - $rem) / $per_page;
if (0 < $rem) {
$up_limit++; //If rem is positive, add the last page that contains less than $per_page attachment;
}
}
ob_start();
if ( 2 > $up_limit ) {
$this->display_all_attachment_list($connected_atts);
} else {
$starting_atts = $per_page * ($page - 1); // for page 2 and 3 $per_page start display on $connected_atts[3*(2-1) = 3]
$paged_atts = array_slice($connected_atts, $starting_atts, $per_page, true);
$this->display_all_attachment_list($paged_atts);
$this->pagination_links($up_limit, $before_links, $after_links, $prev_text, $next_text);
}
$output = ob_get_clean();
return $output;
}
/**
* performs rendering of all attachments list
* @since 1.1.3
*/
public function display_all_attachment_list($atts)
{
if (! is_array($atts) || $atts == array())
return;
?>