PluginProbe
Image Source Control Lite – Show Image Credits and Captions / 1.2
Image Source Control Lite – Show Image Credits and Captions v1.2
3.12.0 3.11.0 trunk 1.1 1.1.1 1.1.2 1.1.2.1 1.1.3 1.10 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.2 1.2.0.1 1.2.0.2 1.2.0.3 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.4.1 1.3.5 All 110 releases
image-source-control-isc / isc.php

isc.php in Image Source Control Lite – Show Image Credits and Captions 1.2, at isc.php

1,249 lines 51.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Image Source Control
4 Version: 1.2
5 Plugin URI: http://webgilde.com/en/image-source-control/
6 Description: The Image Source Control saves the source of an image, lists them and warns if it is missing.
7 Author: Thomas Maier
8 Author URI: http://www.webgilde.com/
9 License: GPL v3
10
11 Image Source Control Plugin for WordPress
12 Copyright (C) 2012, Thomas Maier - thomas.maier@webgilde.com
13
14 This program is free software: you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * Followed the following tutorials
28 * http://wpengineer.com/2076/add-custom-field-attachment-in-wordpress/
29 * http://bueltge.de/eigene-felder-dateiverwaltung-wordpress/1226/ (same like above, but in German)
30 *
31 *
32 */
33
34 //avoid direct calls to this file
35 if (!function_exists('add_action')) {
36 header('Status: 403 Forbidden');
37 header('HTTP/1.1 403 Forbidden');
38 exit();
39 }
40
41 define('ISCVERSION', '1.2');
42 define('ISCNAME', 'Image Source Control');
43 define('ISCTEXTDOMAIN', 'isc');
44 define('ISCDIR', basename(dirname(__FILE__)));
45 define('ISCPATH', plugin_dir_path(__FILE__));
46 define('WEBGILDE', 'http://webgilde.com/en/image-source-control');
47
48 load_plugin_textdomain(ISCTEXTDOMAIN, false, dirname(plugin_basename(__FILE__)) . '/languages/');
49
50 if (!class_exists('ISC_CLASS')) {
51
52 class ISC_CLASS
53 {
54 /**
55 * define default meta fields
56 */
57 protected $_fields = array(
58 'image_source' => array(
59 'id' => 'isc_image_source',
60 'default' => '',
61 ),
62 'image_source_own' => array(
63 'id' => 'isc_image_source_own',
64 'default' => '',
65 ),
66 'image_posts' => array(
67 'id' => 'isc_image_posts',
68 'default' => array()
69 )
70 );
71
72 /**
73 * allowed image file types/extensions
74 * @since 1.1
75 */
76 protected $_allowedExtensions = array(
77 'jpg', 'png', 'gif'
78 );
79
80 protected $_upgrade_step = array(
81 '1.2'
82 );
83
84 /**
85 * Thumbnail size in list of all images.
86 */
87 protected $_thumbnail_size = array('thumbnail', 'medium', 'large', 'custom');
88
89 /**
90 * options saved in the db
91 * @since 1.2
92 */
93 protected $_options = array();
94
95 /**
96 * Setup registers filterts and actions.
97 */
98 public function __construct()
99 {
100
101 // load all plugin options
102 $this->_options = get_option('isc_options');
103
104 // insert all function for the frontend here
105
106 add_shortcode('isc_list', array($this, 'list_post_attachments_with_sources_shortcode'));
107 add_shortcode('isc_list_all', array($this, 'list_all_post_attachments_sources_shortcode'));
108
109 // insert all backend functions below this check
110 if (!current_user_can('upload_files')) {
111 return false;
112 }
113
114 register_activation_hook(ISCPATH . '/isc.php', array($this, 'activation'));
115
116 add_filter('attachment_fields_to_edit', array($this, 'add_isc_fields'), 10, 2);
117 add_filter('attachment_fields_to_save', array($this, 'isc_fields_save'), 10, 2);
118
119 add_action('admin_menu', array($this, 'create_menu'));
120 add_action('admin_init', array($this, 'SAPI_init'));
121
122 add_action('admin_enqueue_scripts', array($this, 'add_admin_scripts'));
123
124 // ajax function; 'add_meta_fields' is the action defined in isc.js as the action to be called via ajax
125 add_action('wp_ajax_add_meta_fields', array($this, 'add_meta_values_to_attachments'));
126
127 // save image information in meta field when a post is saved
128 add_action('save_post', array($this, 'save_image_information_on_post_save'));
129 }
130
131 /**
132 * create the menu pages for isc
133 */
134 public function create_menu()
135 {
136 global $isc_missing;
137 global $isc_setting;
138
139 /**
140 * Check if the page is already created.
141 */
142 if (empty($isc_missing)) {
143 // these pages should be accessible by editors and higher
144 $isc_missing = add_submenu_page('upload.php', 'missing image sources by Image Source Control Plugin', __('Missing Sources', ISCTEXTDOMAIN), 'edit_others_posts', ISCPATH . '/templates/missing_sources.php', '');
145 $isc_setting = add_options_page(__('Image control - ISC plugin', ISCTEXTDOMAIN), __('Image Control', ISCTEXTDOMAIN), 'edit_others_posts', 'isc_settings_page', array($this, 'render_isc_settings_page'));
146 }
147 }
148
149 /**
150 * add scripts to admin pages
151 * @since 1.0
152 * @update 1.1.1
153 */
154 public function add_admin_scripts($hook)
155 {
156 global $isc_setting;
157 if ($hook != $isc_setting) {
158 return;
159 }
160 wp_enqueue_script('isc_script', plugins_url('/js/isc.js', __FILE__), false, ISCVERSION);
161 // this is to define ajaxurl to be able to use this in its own js script
162 // wp_localize_script( 'isc_script', 'IscAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
163 }
164
165 /**
166 * add custom field to attachment
167 * @param arr $form_fields
168 * @param object $post
169 * @return arr
170 * @since 1.0
171 * @updated 1.1
172 */
173 public function add_isc_fields($form_fields, $post)
174 {
175 // add input field for source
176 $form_fields['isc_image_source']['label'] = __('Image Source', ISCTEXTDOMAIN);
177 $form_fields['isc_image_source']['value'] = get_post_meta($post->ID, 'isc_image_source', true);
178 $form_fields['isc_image_source']['helps'] = __('Include the image source here.', ISCTEXTDOMAIN);
179
180 // add checkbox to mark as your own image
181 $form_fields['isc_image_source_own']['input'] = 'html';
182 $form_fields['isc_image_source_own']['label'] = '';
183 $form_fields['isc_image_source_own']['helps'] =
184 __('Check this box if this is your own image and doesn\'t need a source.', ISCTEXTDOMAIN);
185 $form_fields['isc_image_source_own']['html'] =
186 "<input type='checkbox' value='1' name='attachments[{$post->ID}][isc_image_source_own]' id='attachments[{$post->ID}][isc_image_source_own]' "
187 . checked(get_post_meta($post->ID, 'isc_image_source_own', true), 1, false )
188 . " style=\"width:14px\"/> "
189 . __('This is my image', ISCTEXTDOMAIN);
190
191 return $form_fields;
192 }
193
194 /**
195 * save image source to post_meta
196 * @param object $post
197 * @param $attachment
198 * @return object $post
199 */
200 public function isc_fields_save($post, $attachment)
201 {
202 if (isset($attachment['isc_image_source'])) {
203 update_post_meta($post['ID'], 'isc_image_source', $attachment['isc_image_source']);
204 }
205
206 update_post_meta($post['ID'], 'isc_image_source_own', $attachment['isc_image_source_own']);
207 return $post;
208 }
209
210 /**
211 * create image sources list for all images of this post
212 * @since 1.0
213 * @update 1.1
214 * @param int $post_id id of the current post/page
215 * @return echo output
216 */
217 public function list_post_attachments_with_sources($post_id = 0)
218 {
219 global $post;
220
221 if (empty($post_id)) {
222 if (!empty($post->ID)) {
223 $post_id = $post->ID;
224 } else {
225 return;
226 }
227 }
228
229 $attachments = get_post_meta($post_id, 'isc_post_images', true);
230 // if attachments is an empty string, search for images in it
231 if ($attachments == '') {
232 $this->save_image_information_on_load();
233 $this->update_image_posts_meta($post_id, $post->post_content);
234
235 $attachments = get_post_meta($post_id, 'isc_post_images', true);
236 }
237
238 $authorname = '';
239 if (!empty($post->post_author))
240 $authorname = get_the_author_meta('display_name', $post->post_author);
241
242 $return = '';
243 if (!empty($attachments)) {
244 $atts = array();
245 foreach ($attachments as $attachment_id => $attachment_array) {
246 $atts[$attachment_id]['title'] = get_the_title($attachment_id);
247 $own = get_post_meta($attachment_id, 'isc_image_source_own', true);
248 $source = get_post_meta($attachment_id, 'isc_image_source', true);
249
250 if ( $own == '' && $source == '' ) {
251 // remove if no information set
252 unset($atts[$attachment_id]);
253 continue;
254 } elseif ($own != '') {
255 if ($this->_options['use_authorname'] && !empty($authorname)) {
256 $atts[$attachment_id ]['source'] = $authorname;
257 } else {
258 $atts[$attachment_id ]['source'] = $this->_options['by_author_text'];
259 }
260 } else {
261 $atts[$attachment_id ]['source'] = $source;
262 }
263 }
264
265 $return = $this->_renderAttachments($atts);
266 }
267
268 return $return;
269 }
270
271 /**
272 * @param array $attachments
273 */
274 protected function _renderAttachments($attachments)
275 {
276 // don't display anything, if no image sources displayed
277 if ($attachments == array()) {
278 return ;
279 }
280 ob_start();
281
282 $headline = $this->_options['image_list_headline'];
283 printf('<p class="isc_image_list_title">%s</p>', $headline); ?>
284 <ul class="isc_image_list"><?php
285
286 foreach ($attachments as $atts_id => $atts_array) {
287 if (empty($atts_array['source'])) {
288 continue;
289 }
290 printf('<li>%1$s: %2$s</li>', $atts_array['title'], $atts_array['source']);
291 }
292 ?></ul><?php
293 return ob_get_clean();
294 }
295
296 /**
297 * shortcode function to list all image sources
298 * @param arr $atts
299 */
300 public function list_post_attachments_with_sources_shortcode($atts = array())
301 {
302 global $post;
303 extract(shortcode_atts(array('id' => 0), $atts));
304
305 // if $id not set, use the current ID from the post
306 if (empty($id)) {
307 $id = $post->ID;
308 }
309
310 if (empty($id)) {
311 return;
312 }
313 return $this->list_post_attachments_with_sources($id);
314 }
315
316 /**
317 * get all attachments without sources
318 * the downside of this function: is there is not even an empty metakey field, nothing is going to be retrieved
319 * @todo fix this in WP 3.5 with compare => 'NOT EXISTS'
320 */
321 public function get_attachments_without_sources()
322 {
323 $args = array(
324 'post_type' => 'attachment',
325 'numberposts' => -1,
326 'post_status' => null,
327 'post_parent' => null,
328 'meta_query' => array(
329 // image source is empty
330 array(
331 'key' => 'isc_image_source',
332 'value' => '',
333 'compare' => '=',
334 ),
335 // and image source is not set
336 array(
337 'key' => 'isc_image_source_own',
338 'value' => '1',
339 'compare' => '!=',
340 ),
341 )
342 );
343
344 $attachments = get_posts($args);
345 if (!empty($attachments)) {
346 return $attachments;
347 }
348 }
349
350 /**
351 * add meta values to all attachments
352 * @todo probably need to fix this when more fields are added along the way
353 * @todo use compare => 'NOT EXISTS' when WP 3.5 is up to retrieve only values where it is not set
354 * @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
355 */
356 public function add_meta_values_to_attachments()
357 {
358 // retrieve all attachments
359 $args = array(
360 'post_type' => 'attachment',
361 'numberposts' => -1,
362 'post_status' => null,
363 'post_parent' => null,
364 );
365
366 $attachments = get_posts($args);
367 if (empty($attachments)) {
368 return;
369 }
370
371 $count = 0;
372 foreach ($attachments as $_attachment) {
373 $set = false;
374 setup_postdata($_attachment);
375 foreach ($this->_fields as $_field) {
376 $meta = get_post_meta($_attachment->ID, $_field['id'], true);
377 if (empty($meta)) {
378 update_post_meta($_attachment->ID, $_field['id'], $_field['default']);
379 $set = true;
380 }
381 }
382 if ($set) {
383 $count++;
384 }
385 }
386 }
387
388 /**
389 * show the loading image from wp-admin/images/loading.gif
390 * @param bool $display should this be displayed directly or hidden? via inline css
391 */
392 public function show_loading_image($display = true)
393 {
394 $img_path = admin_url("/images/loading.gif");
395 $file_path = ABSPATH . "wp-admin/images/loading.gif";
396 if (file_exists($file_path)) {
397 echo '<span id="isc_loading_img" style="display: none;"><img src="' . $img_path . '" width="16" height="16" alt="loading"/></span>';
398 }
399 }
400
401 /**
402 * this is an entry function to save image information to a post when it is saved
403 * @since 1.1
404 * @param type $post_id
405 */
406 public function save_image_information_on_post_save($post_id)
407 {
408 // return, if save_post is called more than one time
409 if (did_action('save_post') !== 1) {
410 return;
411 }
412
413 if (isset($_POST['post_type']) && 'attachment' == $_POST['post_type']) {
414 return;
415 }
416
417 // check if this is a revision and if so, use parent post id
418 if ($_id = wp_is_post_revision($post_id)) {
419 $post_id = $_id;
420 }
421
422 $_content = '';
423 if ( !empty( $_REQUEST['content']) ) $_content = stripslashes($_REQUEST['content']);
424
425 // Needs to be called before the 'isc_post_images' field is updated.
426 $this->update_image_posts_meta($post_id, $_content);
427
428 $this->save_image_information($post_id, $_content);
429 }
430
431 /**
432 * save image information for a post when it is viewed and the image source list is enabled
433 * (this is in case the plugin is new and the current post wasn't saved before)
434 *
435 * @since 1.1
436 */
437 public function save_image_information_on_load()
438 {
439 global $post;
440 if (empty($post->ID)) {
441 return;
442 }
443
444 $post_id = $post->ID;
445 $_content = $post->post_content;
446
447 $this->save_image_information($post_id, $_content);
448 }
449
450 /**
451 * retrieve images added to a post or page and save all information as a meta value
452 * @since 1.1
453 * @todo check for more post types that maybe should not be parsed here
454 */
455 public function save_image_information($post_id, $_content)
456 {
457 $_image_urls = $this->_filter_src_attributes($_content);
458 $_imgs = array();
459
460 foreach ($_image_urls as $_image_url) {
461 // get ID of images by url
462 $img_id = $this->get_image_by_url($_image_url);
463 $_imgs[$img_id] = array(
464 'src' => $_image_url
465 );
466 }
467
468 // add thumbnail information
469 $thumb_id = get_post_thumbnail_id($post_id);
470
471 /**
472 * if an image is used both inside the post and as post thumbnail, the thumbnail entry overrides the regular image.
473 */
474 if ( !empty( $thumb_id )) {
475 $_imgs[$thumb_id] = array(
476 'src' => wp_get_attachment_url($thumb_id),
477 'thumbnail' => true
478 );
479 }
480
481 if (empty($_imgs)) {
482 $_imgs = false;
483 }
484 update_post_meta($post_id, 'isc_post_images', $_imgs);
485 }
486
487 /**
488 * filter image src attribute from text
489 * @since 1.1
490 * @updated 1.1.3
491 * @return array with image src uris
492 */
493 public function _filter_src_attributes($content = '')
494 {
495 $srcs = array();
496 if (empty($content))
497 return $srcs;
498
499 // parse HTML with DOM
500 $dom = new DOMDocument;
501
502 libxml_use_internal_errors(true);
503 $dom->loadHTML($content);
504
505 // Prevents from sending E_WARNINGs notice (Outputs are forbidden during activation)
506 libxml_clear_errors();
507
508 foreach ($dom->getElementsByTagName('img') as $node) {
509 $srcs[] = $node->getAttribute('src');
510 }
511
512 return $srcs;
513 }
514
515 /**
516 * get image by url accessing the database directly
517 * @since 1.1
518 * @updated 1.1.3
519 * @param string $url url of the image
520 * @return id of the image
521 */
522 public function get_image_by_url($url = '')
523 {
524 if (empty($url)) {
525 return 0;
526 }
527 $types = implode('|', $this->_allowedExtensions);
528 // check for the format 'image-title-(e12452112-)300x200.jpg' and remove the image size and edit mark from it
529 $newurl = preg_replace("/(-e\d+){0,1}-(\d+)x(\d+)\.({$types})$/i", '.${4}', $url);
530 global $wpdb;
531 $query = $wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE guid = %s", $newurl);
532 $id = $wpdb->get_var($query);
533 return $id;
534 }
535
536 /**
537 * Update isc_image_posts meta field for all images found in a post with a given ID.
538 * @param $post_id ID of the target post
539 * @param $content content of the target post
540 */
541 public function update_image_posts_meta($post_id, $content)
542 {
543 $image_urls = $this->_filter_src_attributes($content);
544 $image_ids = array();
545 $added_images = array();
546 $removed_images = array();
547
548 $isc_post_images = get_post_meta($post_id, 'isc_post_images', true);
549
550 foreach ($image_urls as $url) {
551 $id = intval($this->get_image_by_url($url));
552 array_push($image_ids, $id);
553 if (is_array($isc_post_images) && !array_key_exists($id, $isc_post_images)) {
554 array_push($added_images, $id);
555 }
556 }
557 if (is_array($isc_post_images)) {
558 foreach ($isc_post_images as $old_id => $value) {
559 if (!in_array($old_id, $image_ids)) {
560 array_push($removed_images, $old_id);
561 } else {
562 if (!empty($old_id)) {
563 $meta = get_post_meta($old_id, 'isc_image_posts', true);
564 if (empty($meta)) {
565 update_post_meta($old_id, 'isc_image_posts', array($post_id));
566 } else {
567 // In case the isc_image_posts is not up to date
568 if (is_array($meta) && !in_array($post_id, $meta)) {
569 array_push($meta, $post_id);
570 update_post_meta($old_id, 'isc_image_posts', $meta);
571 }
572 }
573 }
574 }
575 }
576 }
577
578 foreach ($added_images as $id) {
579 $meta = get_post_meta($id, 'isc_image_posts', true);
580 if (!is_array($meta) || array() == $meta) {
581 update_post_meta($id, 'isc_image_posts', array($post_id));
582 } else {
583 array_push($meta, $post_id);
584 update_post_meta($id, 'isc_image_posts', $meta);
585 }
586 }
587
588 foreach ($removed_images as $id) {
589 $image_meta = get_post_meta($id, 'isc_image_posts', true);
590 if (is_array($image_meta)) {
591 $offset = array_search($post_id, $image_meta);
592 if (false !== $offset) {
593 array_splice($image_meta, $offset, 1);
594 update_post_meta($id, 'isc_image_posts', $image_meta);
595 }
596 }
597 }
598 }
599
600 /**
601 * create shortcode to list all image sources in the frontend
602 * @param array $atts
603 * @since 1.1.3
604 * @todo link to the post
605 */
606 public function list_all_post_attachments_sources_shortcode($atts = array())
607 {
608
609 /**
610 * @todo why not translate here with the code below?
611 * > Because the two if statements below will need to call gettext (again) for comparing values.
612 */
613 extract(shortcode_atts(array(
614 'per_page' => 99999,
615 'before_links' => '',
616 'after_links' => '',
617 'prev_text' => '&#171; Previous',
618 'next_text' => 'Next &#187;'
619 ),
620 $atts));
621
622 /**
623 * @todo why not include this into the array above?
624 */
625 if ('&#171; Previous' == $prev_text)
626 $prev_text = __('&#171; Previous', ISCTEXTDOMAIN);
627 if ('Next &#187;' == $next_text)
628 $next_text = __('Next &#187;', ISCTEXTDOMAIN);
629
630 // retrieve all attachments
631 $args = array(
632 'post_type' => 'attachment',
633 'numberposts' => -1,
634 'post_status' => null,
635 'post_parent' => null,
636 'meta_query' => array(
637 array(
638 'key' => 'isc_image_posts',
639 'value' => 'a:0:{}',
640 'compare' => '!='
641 )
642 )
643 /** @todo maybe add offset to not retrieve the first results when not on first page */
644 /** @todo maybe add limit to not retrieve more results than on the current page */
645 /** >No, we need to get total count of attachment with parents for $max_page in the pagination link. */
646 );
647
648 $attachments = get_posts($args);
649 if (empty($attachments)) {
650 return;
651 }
652
653 $options = $this->get_isc_options();
654
655 $connected_atts = array();
656
657 //Keeps only those ones who have parent
658
659 foreach ($attachments as $_attachment) {
660 $connected_atts[$_attachment->ID]['source'] = get_post_meta($_attachment->ID, 'isc_image_source', true);
661 $connected_atts[$_attachment->ID]['own'] = get_post_meta($_attachment->ID, 'isc_image_source_own', true);
662 $connected_atts[$_attachment->ID]['title'] = $_attachment->post_title;
663 $connected_atts[$_attachment->ID]['author_name'] = '';
664 if ('' != $connected_atts[$_attachment->ID]['own']) {
665 $parent = get_post($_attachment->post_parent);
666 $connected_atts[$_attachment->ID]['author_name'] = get_the_author_meta('display_name', $parent->post_author);
667 }
668
669 $metadata = get_post_meta($_attachment->ID, 'isc_image_posts', true);
670 $parents_data = '';
671
672 if (is_array($metadata) && array() != $metadata) {
673 $parents_data .= "<ul style='margin: 0;'>";
674 foreach($metadata as $data) {
675 $parents_data .= sprintf(__('<li><a href="%1$s" title="View %2$s">%3$s</a></li>', ISCTEXTDOMAIN),
676 esc_url(get_permalink($data)),
677 esc_attr(get_the_title($data)),
678 esc_html(get_the_title($data))
679 );
680 }
681 $parents_data .= "</ul>";
682 }
683
684 $connected_atts[$_attachment->ID]['posts'] = $parents_data;
685 }
686
687 $total = count($connected_atts);
688
689 if (0 == $total)
690 return;
691
692 $page = isset($_GET['isc-page']) ? intval($_GET['isc-page']) : 1;
693 $down_limit = 1; // First page
694
695 $up_limit = 1;
696
697 if ($per_page < $total) {
698 $rem = $total % $per_page; // The Remainder of $total/$per_page
699 $up_limit = ($total - $rem) / $per_page;
700 if (0 < $rem) {
701 $up_limit++; //If rem is positive, add the last page that contains less than $per_page attachment;
702 }
703 }
704
705 ob_start();
706 if ( 2 > $up_limit ) {
707 $this->display_all_attachment_list($connected_atts);
708 } else {
709 $starting_atts = $per_page * ($page - 1); // for page 2 and 3 $per_page start display on $connected_atts[3*(2-1) = 3]
710 $paged_atts = array_slice($connected_atts, $starting_atts, $per_page, true);
711 $this->display_all_attachment_list($paged_atts);
712 $this->pagination_links($up_limit, $before_links, $after_links, $prev_text, $next_text);
713 }
714 if (isset($options['webgilde']) && true == $options['webgilde']) {
715 ?>
716 <p class="isc-backlink"><?php printf(__('Image list created by <a href="%s" title="Image Source Control">Image Source Control Plugin</a>', ISCTEXTDOMAIN), WEBGILDE); ?></p>
717 <?php
718 }
719
720 $output = ob_get_clean();
721 return $output;
722 }
723
724
725 /**
726 * performs rendering of all attachments list
727 * @since 1.1.3
728 */
729 public function display_all_attachment_list($atts)
730 {
731 if (!is_array($atts) || $atts == array())
732 return;
733 $options = $this->get_isc_options();
734 if (!isset($options['thumbnail_size'])) {
735 $options = $options + $this->default_options();
736 }
737 ?>
738 <table>
739 <thead>
740 <?php if ($options['thumbnail_in_list']) : ?>
741 <th><?php _e('Thumbnail', ISCTEXTDOMAIN); ?></th>
742 <?php endif; ?>
743 <th><?php _e("Attachment's ID", ISCTEXTDOMAIN); ?></th>
744 <th><?php _e('Title', ISCTEXTDOMAIN); ?></th>
745 <th><?php _e('Attached to', ISCTEXTDOMAIN); ?></th>
746 <th><?php _e('Source', ISCTEXTDOMAIN); ?></th>
747 </thead>
748 <tbody>
749 <?php foreach ($atts as $id => $data) : ?>
750 <?php
751 /** @todo ment for later: this text was used above already; find a place to but it so it is defined only once and used where needed */
752 $source = __('Not available', ISCTEXTDOMAIN);
753 if ('' != $data['own']) {
754 /** @todo ment for later: this text was used above already; find a place to but it so it is defined only once and used where needed */
755 if ($this->_options['use_authorname']) {
756 $source = $data['author_name'];
757 } else {
758 $source = $this->_options['by_author_text'];
759 }
760 } else {
761 if (!empty($data['source']))
762 $source = $data['source'];
763 }
764 ?>
765 <tr>
766 <?php
767 $v_align = '';
768 if ($options['thumbnail_in_list']) :
769 $v_align = 'style="vertical-align: top;"';
770 ?>
771 <?php if ('custom' != $options['thumbnail_size']) : ?>
772 <td><?php echo wp_get_attachment_image($id, $options['thumbnail_size']); ?></td>
773 <?php else : ?>
774 <td><?php echo wp_get_attachment_image($id, array($options['thumbnail_width'], $options['thumbnail_height'])); ?></td>
775 <?php endif; ?>
776 <?php endif; ?>
777 <td <?php echo $v_align;?>><?php echo $id; ?></td>
778 <td <?php echo $v_align;?>><?php echo $data['title']; ?></td>
779 <td <?php echo $v_align;?>><?php echo $data['posts']; ?></td>
780 <td <?php echo $v_align;?>><?php echo esc_html($source); ?></td>
781 </tr>
782 <?php endforeach; ?>
783 </tbody>
784 </table>
785 <?php
786 }
787
788 /**
789 * Render pagination links, use $before_links and after_links to wrap pagination links inside an additional block
790 * @param int $max_page total page count
791 * @param string $before_links optional html to display before pagination links
792 * @param string $after_links optional html to display after pagination links
793 * @param string $prev_text text for the previous page link
794 * @param string $next_text text for the next page link
795 * @since 1.1.3
796 *
797 */
798 public function pagination_links($max_page, $before_links, $after_links, $prev_text, $next_text)
799 {
800 if ((!isset($max_page)) || (!isset($before_links)) || (!isset($after_links)) || (!isset($prev_text)) || (!isset($next_text)))
801 return;
802 if (!empty($before_links))
803 echo $before_links;
804 ?>
805 <div class="isc-paginated-links">
806 <?php
807 $page = isset($_GET['isc-page']) ? intval($_GET['isc-page']) : 1;
808 if ($max_page < $page) {
809 $page = $max_page;
810 }
811 if ($page < 1) {
812 $page = 1;
813 }
814 $min_page = 1;
815 $backward_distance = $page - $min_page;
816 $forward_distance = $max_page - $page;
817
818 $page_link = get_page_link();
819
820 /**
821 * Remove the query_string of the page_link (?page_id=xyz for the standard permalink structure),
822 * which is already captured in $_SERVER['QUERY_STRING'].
823 * @todo replace regex with other value (does WP store the url path without attributes somewhere?
824 * >get_page_link() returns the permalink but for the default WP permalink structure, the permalink looks like "http://domain.tld/?p=52", while $_GET
825 * still has a field named 'page_id' with the same value of 52.
826 */
827
828 $pos = strpos($page_link, '?');
829 if (false !== $pos) {
830 $page_link = substr($page_link, 0, $pos);
831 }
832
833 /**
834 * Unset the actual "$_GET['isc-page']" variable (if is set). Pagination variable will be appended to the new query string with a different value for each
835 * pagination link.
836 */
837
838 if (isset($_GET['isc-page'])) {
839 unset($_GET['isc-page']);
840 }
841
842 $query_string = http_build_query($_GET);
843
844 $isc_query_tag = '';
845 if (empty($query_string)) {
846 $isc_query_tag = '?isc-page=';
847 } else {
848 $query_string = '?' . $query_string;
849 $isc_query_tag = '&isc-page=';
850 }
851
852 if ($min_page != $page) {
853 ?>
854 <a href="<?php echo $page_link . $query_string . $isc_query_tag . ($page-1); ?>" class="prev page-numbers"><?php echo $prev_text; ?></a>
855 <?php
856 }
857
858 if (5 < $max_page) {
859
860 if (3 < $backward_distance) {
861 ?>
862 <a href="<?php echo $page_link . $query_string . $isc_query_tag; ?>1" class="page-numbers">1</a>
863 <span class="page-numbers dots">...</span>
864 <a href="<?php echo $page_link . $query_string . $isc_query_tag . ($page-2);?>" class="page-numbers"><?php echo $page-2; ?></a>
865 <a href="<?php echo $page_link . $query_string . $isc_query_tag . ($page-1);?>" class="page-numbers"><?php echo $page-1; ?></a>
866 <span class="page-numbers current"><?php echo $page; ?></span>
867 <?php
868 } else {
869 for ($i = 1; $i <= $page; $i++) {
870 if ($i == $page) {
871 ?>
872 <span class="page-numbers current"><?php echo $i; ?></span>
873 <?php
874 } else {
875 ?>
876 <a href="<?php echo $page_link . $query_string . $isc_query_tag . $i;?>" class="page-numbers"><?php echo $i; ?></a>
877 <?php
878 }
879 }
880 }
881
882 if (3 < $forward_distance) {
883 ?>
884 <a href="<?php echo $page_link . $query_string . $isc_query_tag . ($page+1);?>" class="page-numbers"><?php echo $page+1; ?></a>
885 <a href="<?php echo $page_link . $query_string . $isc_query_tag . ($page+2);?>" class="page-numbers"><?php echo $page+2; ?></a>
886 <span class="page-numbers dots">...</span>
887 <a href="<?php echo $page_link . $query_string . $isc_query_tag . $max_page;?>" class="page-numbers"><?php echo $max_page; ?></a>
888 <?php
889 } else {
890 for ($i = $page+1; $i <= $max_page; $i++) {
891 ?>
892 <a href="<?php echo $page_link . $query_string . $isc_query_tag . $i;?>" class="page-numbers"><?php echo $i; ?></a>
893 <?php
894 }
895 }
896 } else {
897 for ($i = 1; $i <= $max_page; $i++) {
898 if ($i == $page) {
899 ?>
900 <span class="page-numbers current"><?php echo $i; ?></span>
901 <?php
902 } else {
903 ?>
904 <a href="<?php echo $page_link . $query_string . $isc_query_tag . $i;?>" class="page-numbers"><?php echo $i; ?></a>
905 <?php
906 }
907 }
908 }
909 if ($page != $max_page) {
910 ?>
911 <a href="<?php echo $page_link . $query_string . $isc_query_tag . ($page+1);?>" class="next page-numbers"><?php echo $next_text; ?></a>
912 <?php
913 }
914 ?>
915 </div>
916 <?php
917 echo $after_links;
918 }
919
920 /**
921 * The activation function
922 */
923 public function activation()
924 {
925 if (!is_array(get_option('isc_options'))) {
926 update_option( 'isc_options', $this->default_options() );
927 }
928 $options = $this->get_isc_options();
929 if (!$options['installed']) {
930 /**
931 * Here, all jobs to perform during first installation, especially options and custom fields.
932 * Important: No add_action('something', 'somefunction').
933 */
934
935 // adds meta fields for attachments
936 $this->add_meta_values_to_attachments();
937
938 // set all isc_image_posts meta fields.
939 $this->init_image_posts_metafield();
940
941 $options['installed'] = true;
942 update_option('isc_options', $options);
943 }
944 }
945
946 /**
947 * Returns default options
948 */
949 public function default_options()
950 {
951 $default['image_list_headline'] = __('image sources', ISCTEXTDOMAIN);
952 $default['use_authorname'] = true;
953 $default['by_author_text'] = __('Owned by the author', ISCTEXTDOMAIN);
954 $default['installed'] = false;
955 $default['version'] = '1.2';
956 $default['webgilde'] = false;
957 $default['thumbnail_in_list'] = false;
958 $default['thumbnail_size'] = 'thumbnail';
959 $default['thumbnail_width'] = 150;
960 $default['thumbnail_height'] = 150;
961 return $default;
962 }
963
964 /**
965 * Settings API initialization
966 */
967 public function SAPI_init()
968 {
969 $this->upgrade_management();
970 register_setting('isc_options_group', 'isc_options', array($this, 'settings_validation'));
971 add_settings_section('isc_settings_section', '', '__return_false', 'isc_settings_page');
972 add_settings_field('image_list_headline', __('Image list headline', ISCTEXTDOMAIN), array($this, 'renderfield_list_headline'), 'isc_settings_page', 'isc_settings_section');
973 add_settings_field('use_authorname', __('Use authors names', ISCTEXTDOMAIN), array($this, 'renderfield_use_authorname'), 'isc_settings_page', 'isc_settings_section');
974 add_settings_field('by_author_text', __('Custom text for owned images', ISCTEXTDOMAIN), array($this, 'renderfield_byauthor_text'), 'isc_settings_page', 'isc_settings_section');
975 add_settings_field('webgilde_backlink', __("Link to webgilde's website", ISCTEXTDOMAIN), array($this, 'renderfield_webgile'), 'isc_settings_page', 'isc_settings_section');
976 add_settings_field('use_thumbnail', __("Use thumbnails in images list", ISCTEXTDOMAIN), array($this, 'renderfield_use_thumbnail'), 'isc_settings_page', 'isc_settings_section');
977 add_settings_field('thumbnail_width', __("Thumbnails max-width", ISCTEXTDOMAIN), array($this, 'renderfield_thumbnail_width'), 'isc_settings_page', 'isc_settings_section');
978 add_settings_field('thumbnail_height', __("Thumbnails max-height", ISCTEXTDOMAIN), array($this, 'renderfield_thumbnail_height'), 'isc_settings_page', 'isc_settings_section');
979 }
980
981 /**
982 * manage data structure upgrading of outdated versions
983 */
984 public function upgrade_management() {
985 /**
986 * Since the activation hook is not executed on plugin upgrade, this function checks options in database
987 * during the admin_init hook to handle plugin's upgrade.
988 */
989
990 $options = get_option( 'isc_options' );
991
992 $max_step = count($this->_upgrade_step);
993 $step_count = 0;
994
995 if (!is_array($options) || !isset($options['version'])){ // versions prior to 1.2
996
997 $default = $this->default_options();
998 $options = $options + $default;
999 $this->init_image_posts_metafield();
1000 $options['installed'] = true;
1001
1002 update_option('isc_options', $options);
1003 $step_count++;
1004
1005 } elseif(ISCVERSION != $options['version']) {
1006
1007 while (ISCVERSION != $options['version'] && $step_count <= $max_step) {
1008 switch ($options['version']) {
1009 /**
1010 * Here, the incremental upgrade process depending on the currently installed version.
1011 */
1012 }
1013 }
1014
1015 }
1016 }
1017
1018 /**
1019 * Image_control's page callback
1020 */
1021 public function render_isc_settings_page()
1022 {
1023 ?>
1024 <div id="icon-options-general" class="icon32"><br></div>
1025 <h2><?php _e('Images control settings', ISCTEXTDOMAIN); ?></h2>
1026 <form id="image-control-form" method="post" action="options.php">
1027 <?php
1028 settings_fields( 'isc_options_group' );
1029 do_settings_sections( 'isc_settings_page' );
1030 submit_button();
1031 ?>
1032 </form>
1033 <?php
1034 }
1035
1036 /**
1037 * image_list field callbacks
1038 */
1039 public function renderfield_list_headline()
1040 {
1041 $options = $this->get_isc_options();
1042 $description = __('The headline of the image list added via shortcode or function in your theme.', ISCTEXTDOMAIN);
1043 ?>
1044 <div id="image-list-headline-block">
1045 <label for="list-head"><?php __('Image list headline', ISCTEXTDOMAIN); ?></label>
1046 <input type="text" name="isc_options[image_list_headline_field]" id="list-head" value="<?php echo $options['image_list_headline'] ?>" class="regular-text" />
1047 <p><em><?php echo $description; ?></em></p>
1048 </div>
1049 <?php
1050 }
1051
1052 public function renderfield_use_authorname()
1053 {
1054 $options = $this->get_isc_options();
1055 $description = __("Display the author's public name as source when the image is owned by the author. Uncheck to use a custom text instead.", ISCTEXTDOMAIN);
1056 ?>
1057 <div id="use-authorname-block">
1058 <label for="use_authorname"><?php _e('Use author name') ?></label>
1059 <input type="checkbox" name="isc_options[use_authorname_ckbox]" id="use_authorname" <?php checked($options['use_authorname']); ?> />
1060 <p><em><?php echo $description; ?></em></p>
1061 </div>
1062 <?php
1063 }
1064
1065 public function renderfield_byauthor_text()
1066 {
1067 $options = $this->get_isc_options();
1068 $description = __("Enter the custom text to display if you do not want to use the author's public name.", ISCTEXTDOMAIN);
1069 ?>
1070 <div id="by-author-text">
1071 <input type="text" id="byauthor" name="isc_options[by_author_text_field]" value="<?php echo $options['by_author_text']; ?>" <?php disabled($options['use_authorname']); ?> class="regular-text" />
1072 <p><em><?php echo $description; ?></em></p>
1073 </div>
1074 <?php
1075 }
1076
1077 public function renderfield_webgile()
1078 {
1079 $options = $this->get_isc_options();
1080 /**
1081 * Avoid warning notices because of the absence of webgilde field in isc_options throughout development steps.
1082 * This 'if' block can be removed for the next release.
1083 */
1084 if (!isset($options['webgilde'])) {
1085 $options = $options + $this->default_options();
1086 }
1087 $description = sprintf(__('Display a link to <a href="%s">Image Source Control plugin&#39;s website</a> below the list of all images in the blog?', ISCTEXTDOMAIN), WEBGILDE);
1088 ?>
1089 <div id="webgilde-block">
1090 <input type="checkbox" id="webgilde-link" name="isc_options[webgilde_field]" <?php checked($options['webgilde']); ?> />
1091 <p><em><?php echo $description; ?></em></p>
1092 </div>
1093 <?php
1094 }
1095
1096 public function renderfield_use_thumbnail()
1097 {
1098 $options = $this->get_isc_options();
1099 if (!isset($options['thumbnail_size'])) {
1100 $options = $options + $this->default_options();
1101 }
1102 $description = __('Display thumbnails on the list of all images in the blog.' ,ISCTEXTDOMAIN);
1103 ?>
1104 <div id="use-thumbnail-block">
1105 <input type="checkbox" id="use-thumbnail" name="isc_options[use_thumbnail]" <?php checked($options['thumbnail_in_list']); ?> />
1106 <select id="thumbnail-size-select" name="isc_options[size_select]" <?php disabled(!$options['thumbnail_in_list']) ?>>
1107 <?php foreach ($this->_thumbnail_size as $size) : ?>
1108 <option value="<?php echo $size; ?>" <?php selected($size, $options['thumbnail_size']);?>><?php echo $size; ?></option>
1109 <?php endforeach; ?>
1110 </select>
1111 <p><em><?php echo $description; ?></em></p>
1112 </div>
1113 <?php
1114 }
1115
1116 public function renderfield_thumbnail_width()
1117 {
1118 $options = $this->get_isc_options();
1119 if (!isset($options['thumbnail_size'])) {
1120 $options = $options + $this->default_options();
1121 }
1122 $description = __('Custom value of the maximum allowed width for thumbnail.' ,ISCTEXTDOMAIN);
1123 ?>
1124 <div id="thumbnail-custom-width">
1125 <input type="text" id="custom-width" name="isc_options[thumbnail_width]" class="small-text" value="<?php echo $options['thumbnail_width'] ?>" /> px
1126 <p><em><?php echo $description; ?></em></p>
1127 </div>
1128 <?php
1129 }
1130
1131 public function renderfield_thumbnail_height()
1132 {
1133 $options = $this->get_isc_options();
1134 if (!isset($options['thumbnail_size'])) {
1135 $options = $options + $this->default_options();
1136 }
1137 $description = __('Custom value of the maximum allowed height for thumbnail.' ,ISCTEXTDOMAIN);
1138 ?>
1139 <div id="thumbnail-custom-height">
1140 <input type="text" id="custom-height" name="isc_options[thumbnail_height]" class="small-text" value="<?php echo $options['thumbnail_height'] ?>"/> px
1141 <p><em><?php echo $description; ?></em></p>
1142 </div>
1143 <?php
1144 }
1145
1146 /**
1147 * Returns isc_options if it exists, returns the default options otherwise.
1148 */
1149 public function get_isc_options() {
1150 return get_option('isc_options', $this->default_options());
1151 }
1152
1153 /*
1154 * Input validation function.
1155 * @param array $input values from the admin panel
1156 */
1157 public function settings_validation($input)
1158 {
1159 $output = $this->get_isc_options();
1160 $output['image_list_headline'] = esc_html($input['image_list_headline_field']);
1161 if (isset($input['use_authorname_ckbox'])) {
1162 // Don't worry about the custom text if the author name is selected.
1163 $output['use_authorname'] = true;
1164 } else {
1165 $output['use_authorname'] = false;
1166 $output['by_author_text'] = esc_html($input['by_author_text_field']);
1167 }
1168 if (isset($input['webgilde_field'])) {
1169 $output['webgilde'] = true;
1170 } else {
1171 $output['webgilde'] = false;
1172 }
1173 if (isset($input['use_thumbnail'])) {
1174 $output['thumbnail_in_list'] = true;
1175 if (in_array($input['size_select'], $this->_thumbnail_size)) {
1176 $output['thumbnail_size'] = $input['size_select'];
1177 }
1178 if ('custom' == $input['size_select']) {
1179 if (is_numeric($input['thumbnail_width'])) {
1180 // Ensures that the value stored in database in a positive integer.
1181 $output['thumbnail_width'] = abs(intval(round($input['thumbnail_width'])));
1182 }
1183 if (is_numeric($input['thumbnail_height'])) {
1184 $output['thumbnail_height'] = abs(intval(round($input['thumbnail_height'])));
1185 }
1186 }
1187 } else {
1188 $output['thumbnail_in_list'] = false;
1189 }
1190 return $output;
1191 }
1192
1193 /**
1194 * Adds isc_image_posts on all attachments. Launched during first installation.
1195 */
1196 public function init_image_posts_metafield()
1197 {
1198 $args = array(
1199 'post_type' => 'any',
1200 'numberposts' => -1,
1201 'post_status' => null,
1202 'post_parent' => null,
1203 );
1204 $posts = get_posts($args);
1205 foreach ($posts as $post) {
1206 setup_postdata($post);
1207 $image_urls = $this->_filter_src_attributes($post->post_content);
1208 $image_ids = array();
1209 foreach ($image_urls as $url) {
1210 $image_id = intval($this->get_image_by_url($url));
1211 array_push($image_ids,$image_id);
1212 }
1213 foreach ($image_ids as $id) {
1214 $meta = get_post_meta($id, 'isc_image_posts', true);
1215 if (empty($meta)) {
1216 update_post_meta($id, 'isc_image_posts', array($post->ID));
1217 } else {
1218 if (!in_array($post->ID, $meta)) {
1219 array_push($meta, $post->ID);
1220 update_post_meta($id, 'isc_image_posts', $meta);
1221 }
1222 }
1223 }
1224 }
1225 }
1226
1227 }// end of class
1228
1229 $inc_path = ABSPATH . 'wp-includes/';
1230 /**
1231 * "pluggable.php" is not defined at this point. Not sure about the reason.
1232 */
1233 require_once($inc_path . 'pluggable.php');
1234
1235 /**
1236 * Need an instance of ISC_CLASS when the register_activation_hook is called (earlier than the "plugins_loaded" hook).
1237 */
1238 global $my_isc;
1239 $my_isc = new ISC_CLASS();
1240
1241 /**
1242 * the next functions are just to have an easier access from outside the class
1243 */
1244 function isc_list($post_id = 0) {
1245 $isc = new ISC_CLASS();
1246 echo $isc->list_post_attachments_with_sources($post_id);
1247 }
1248 }
1249