Completed
Push — master ( 0cbbca...639b41 )
by Ankit
01:42
created

dynamic-featured-image.php (2 issues)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 *
4
 * Plugin Name: Dynamic Featured Image
5
 * Plugin URI: http://wordpress.org/plugins/dynamic-featured-image/
6
 * Description: Dynamically adds multiple featured image or post thumbnail functionality to your posts, pages and custom post types.
7
 * Version: 3.5.2
8
 * Author: Ankit Pokhrel
9
 * Author URI: https://ankitpokhrel.com
10
 * License: GPL2 or later
11
 * License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 * Text Domain: dynamic-featured-image
13
 * Domain Path: /languages
14
 * GitHub Plugin URI: https://github.com/ankitpokhrel/Dynamic-Featured-Image
15
 *
16
 * @package dynamic-featured-image
17
 *
18
 * Copyright (C) 2013 Ankit Pokhrel <[email protected], https://ankitpokhrel.com>
19
 *
20
 * This program is free software; you can redistribute it and/or modify
21
 * it under the terms of the GNU General Public License as published by
22
 * the Free Software Foundation; either version 3 of the License, or
23
 * (at your option) any later version.
24
 *
25
 * This program is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28
 * GNU General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU General Public License
31
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
32
 */
33
34
// Avoid direct calls to this file.
35
if ( ! defined( 'ABSPATH' ) ) {
36
    header( 'Status: 403 Forbidden' );
37
    header( 'HTTP/1.1 403 Forbidden' );
38
    exit();
39
}
40
41
/**
42
 * Dynamic Featured Image plugin main class.
43
 *
44
 * @author Ankit Pokhrel <[email protected]>
45
 * @version 3.0.1
46
 */
47
class Dynamic_Featured_Image {
48
    /**
49
     * Current version of the plugin.
50
     *
51
     * @since 3.0.0
52
     */
53
    const VERSION = '3.5.2';
54
55
    /**
56
     * Text domain.
57
     *
58
     * @since 3.6.0
59
     */
60
    const TEXT_DOMAIN = 'dynamic-featured-image';
61
62
    /**
63
     * Image upload directory.
64
     *
65
     * @var $upload_dir string
66
     */
67
    private $upload_dir;
68
69
    /**
70
     * Image upload URL.
71
     *
72
     * @var $upload_url string
73
     */
74
    private $upload_url;
75
76
    /**
77
     * Database object.
78
     *
79
     * @var $db wpdb
80
     */
81
    private $db;
82
83
    /**
84
     * Title for dfi metabox.
85
     *
86
     * @var $metabox_title string
87
     */
88
    protected $metabox_title;
89
90
    /**
91
     * Users post type filter for dfi metabox.
92
     *
93
     * @var $user_filter array
94
     */
95
    protected $user_filter;
96
97
    /**
98
     * Constructor. Hooks all interactions to initialize the class.
99
     *
100
     * @since 1.0.0
101
     * @access public
102
     * @global object $wpdb
103
     *
104
     * @see     add_action()
105
     */
106
    public function __construct() {
107
        // plugin update warning.
108
        add_action( 'in_plugin_update_message-' . plugin_basename( __FILE__ ), array( $this, 'update_notice' ) );
109
110
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
111
        add_action( 'add_meta_boxes', array( $this, 'initialize_featured_box' ) );
112
        add_action( 'save_post', array( $this, 'save_meta' ) );
113
        add_action( 'plugins_loaded', array( $this, 'load_plugin_textdomain' ) );
114
115
        // handle ajax request.
116
        add_action( 'wp_ajax_dfiMetaBox_callback', array( $this, 'ajax_callback' ) );
117
118
        // add action links.
119
        add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'dfi_action_links' ) );
120
121
        // media uploader custom fields.
122
        add_filter( 'attachment_fields_to_edit', array( $this, 'media_attachment_custom_fields' ), 10, 2 );
123
        add_filter( 'attachment_fields_to_save', array( $this, 'media_attachment_custom_fields_save' ), 10, 2 );
124
125
        // get the site protocol.
126
        $protocol = $this->get_protocol();
127
128
        $this->upload_dir = wp_upload_dir();
129
        $this->upload_url = preg_replace( '#^https?://#', '', $this->upload_dir['baseurl'] );
130
131
        // add protocol to the upload url.
132
        $this->upload_url = $protocol . $this->upload_url;
133
134
        // post type filter added by user.
135
        $this->user_filter = array();
136
137
        global $wpdb;
138
        $this->db = $wpdb;
139
    }
140
141
    /**
142
     * Return site protocol.
143
     *
144
     * @since 3.5.1
145
     * @access public
146
     *
147
     * @return string
148
     */
149
    private function get_protocol() {
0 ignored issues
show
get_protocol uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
150
        return ( ( ! empty( $_SERVER['HTTPS'] ) && 'off' !== $_SERVER['HTTPS'] ) ||
151
                 ( ! empty( $_SERVER['SERVER_PORT'] ) && 443 === $_SERVER['SERVER_PORT'] ) ) ? 'https://' : 'http://';
152
    }
153
154
    /**
155
     * Add required admin scripts.
156
     *
157
     * @since 1.0.0
158
     * @access public
159
     *
160
     * @see  wp_enque_style()
161
     * @see  wp_register_script()
162
     * @see  wp_enqueue_script()
163
     *
164
     * @return void
165
     */
166
    public function enqueue_admin_scripts() {
167
        // enqueue styles.
168
        wp_enqueue_style( 'style-dfi', plugins_url( '/css/style-dfi.css', __FILE__ ), array(), self::VERSION );
169
        wp_enqueue_style( 'dashicons', plugins_url( '/css/dashicons.css', __FILE__ ), array(), self::VERSION );
170
171
        // register script.
172
        wp_register_script( 'scripts-dfi', plugins_url( '/js/script-dfi.js', __FILE__ ), array( 'jquery' ), self::VERSION );
173
174
        // localize the script with required data.
175
        wp_localize_script(
176
            'scripts-dfi',
177
            'WP_SPECIFIC',
178
            array(
179
                'upload_url'               => $this->upload_url,
180
                'metabox_title'            => __( $this->metabox_title, self::TEXT_DOMAIN ),
181
                'mediaSelector_title'      => __( 'Dynamic Featured Image - Media Selector', self::TEXT_DOMAIN ),
182
                'mediaSelector_buttonText' => __( 'Set Featured Image', self::TEXT_DOMAIN ),
183
            )
184
        );
185
186
        // enqueue scripts.
187
        wp_enqueue_script( 'scripts-dfi' );
188
    }
189
190
    /**
191
     * Add upgrade link.
192
     *
193
     * @access public
194
     * @since  3.5.1
195
     * @action plugin_action_links
196
     *
197
     * @codeCoverageIgnore
198
     *
199
     * @param  array $links Action links.
200
     *
201
     * @return array
202
     */
203
    public function dfi_action_links( $links ) {
204
        $upgrade_link = array(
205
            '<a href="https://ankitpokhrel.com/explore/downloads/dynamic-featured-image-pro/" target="_blank">Upgrade to Premium</a>'
206
        );
207
208
        return array_merge( $links, $upgrade_link );
209
    }
210
211
    /**
212
     * Add featured meta boxes dynamically.
213
     *
214
     * @since 1.0.0
215
     * @access public
216
     * @global object $post
217
     *
218
     * @see  get_post_meta()
219
     * @see  get_post_types()
220
     * @see  add_meta_box()
221
     * @see  add_filter()
222
     *
223
     * @return void
224
     */
225
    public function initialize_featured_box() {
226
        global $post;
227
228
        // make metabox title dynamic.
229
        $this->metabox_title = apply_filters( 'dfi_set_metabox_title', __( 'Featured Image', self::TEXT_DOMAIN ) );
230
231
        $featured_data  = get_post_meta( $post->ID, 'dfiFeatured', true );
232
        $total_featured = count( $featured_data );
233
234
        $default_filter    = array( 'attachment', 'revision', 'nav_menu_item' );
235
        $this->user_filter = apply_filters( 'dfi_post_type_user_filter', $this->user_filter );
236
        $filter            = array_merge( $default_filter, $this->user_filter );
237
238
        $post_types = get_post_types();
239
        $post_types = array_diff( $post_types, $filter );
240
241
        $post_types = apply_filters( 'dfi_post_types', $post_types );
242
243
        if ( ! empty( $featured_data ) && $total_featured >= 1 ) {
244
            $i = 2;
245
            foreach ( $featured_data as $featured ) {
246
                $this->dfi_add_meta_box( $post_types, $featured, $i );
247
                $i ++;
248
            }
249
        } else {
250
            $this->dfi_add_meta_box( $post_types );
251
        }
252
    }
253
254
    /**
255
     * Translates more than one digit number digit by digit.
256
     *
257
     * @param  int $number Integer to be translated.
258
     *
259
     * @return string Translated number
260
     */
261
    protected function get_number_translation( $number ) {
262
        if ( $number <= 9 ) {
263
            return __( $number, self::TEXT_DOMAIN );
264
        } else {
265
            $pieces = str_split( $number, 1 );
266
            $buffer = '';
267
            foreach ( $pieces as $piece ) {
268
                $buffer .= __( $piece, self::TEXT_DOMAIN );
269
            }
270
271
            return $buffer;
272
        }
273
    }
274
275
    /**
276
     * Adds meta boxes.
277
     *
278
     * @param  array  $post_types Post types to show featured image box.
279
     * @param  object $featured Callback arguments.
280
     * @param  int    $i Index of the featured image.
281
     *
282
     * @return void
283
     */
284
    private function dfi_add_meta_box( $post_types, $featured = null, $i = null ) {
285
        if ( ! is_null( $i ) ) {
286
            foreach ( $post_types as $type ) {
287
                add_meta_box(
288
                    'dfiFeaturedMetaBox-' . $i,
289
                    __( $this->metabox_title, self::TEXT_DOMAIN ) . ' ' . $this->get_number_translation( $i ),
290
                    array( $this, 'featured_meta_box' ),
291
                    $type,
292
                    'side',
293
                    'low',
294
                    array( $featured, $i + 1 )
295
                );
296
297
                add_filter( "postbox_classes_{$type}_dfiFeaturedMetaBox-" . $i, array( $this, 'add_metabox_classes' ) );
298
            }
299
        } else {
300
            foreach ( $post_types as $type ) {
301
                add_meta_box(
302
                    'dfiFeaturedMetaBox',
303
                    __( $this->metabox_title, self::TEXT_DOMAIN ) . ' ' . __( 2, self::TEXT_DOMAIN ),
304
                    array( $this, 'featured_meta_box' ),
305
                    $type,
306
                    'side',
307
                    'low',
308
                    array( null, null )
309
                );
310
311
                add_filter( "postbox_classes_{$type}_dfiFeaturedMetaBox", array( $this, 'add_metabox_classes' ) );
312
            }
313
        }
314
    }
315
316
    /**
317
     * Separate thumb and full image url from given URL string.
318
     *
319
     * @since  3.3.1
320
     *
321
     * @param  string $url_string Url string.
322
     * @param  string $state Thumb or full.
323
     *
324
     * @return string|null
325
     */
326
    private function separate( $url_string, $state = 'thumb' ) {
327
        $image_piece = explode( ',', $url_string );
328
329
        if ( 'thumb' === $state ) {
330
            return isset( $image_piece[0] ) ? $image_piece[0] : null;
331
        }
332
333
        return isset( $image_piece[1] ) ? $image_piece[1] : null;
334
    }
335
336
    /**
337
     * Create a nonce field
338
     *
339
     * @since  3.5.0
340
     *
341
     * @see  wp_nonce_field()
342
     * @see  plugin_basename()
343
     *
344
     * @codeCoverageIgnore
345
     *
346
     * @param  string $key Nonce key.
347
     *
348
     * @return string
349
     */
350
    protected function nonce_field( $key ) {
351
        return wp_nonce_field( plugin_basename( __FILE__ ), $key, true, false );
352
    }
353
354
    /**
355
     * Featured meta box as seen in the admin
356
     *
357
     * @since 1.0.0
358
     * @access public
359
     *
360
     * @param  object $post Global post object.
361
     * @param  array  $featured Array containing featured image count.
362
     *
363
     * @throws Exception Medium size image not found.
364
     * @return void
365
     */
366
    public function featured_meta_box( $post, $featured ) {
367
        $featured_img         = $featured['args'][0];
368
        $featured_id          = is_null( $featured['args'][1] ) ? 2 : --$featured['args'][1];
369
        $featured_img_full    = $featured_img;
370
        $featured_img_trimmed = $featured_img;
371
372
        if ( ! is_null( $featured_img ) ) {
373
            $featured_img_trimmed = $this->separate( $featured_img );
374
            $featured_img_full    = $this->separate( $featured_img, 'full' );
375
        }
376
377
        try {
378
            $thumbnail = $this->get_image_thumb( $this->upload_url . $featured_img_full, 'medium' );
379
            if ( is_null( $thumbnail ) ) {
380
                // medium sized thumbnail image is missing.
381
                throw new Exception( 'Medium size image not found', 1 );
382
            }
383
        } catch ( Exception $e ) {
384
            // since medium sized thumbnail image was not found,
385
            // let's set full image url as thumbnail.
386
            $thumbnail = $featured_img_full;
387
        }
388
389
        // Add a nonce field.
390
        echo $this->nonce_field( 'dfi_fimageplug-' . $featured_id );
391
        echo $this->get_featured_box( $featured_img_trimmed, $featured_img, $featured_id, $thumbnail, $post->ID );
392
    }
393
394
    /**
395
     * Returns featured box html content.
396
     *
397
     * @since  3.1.0
398
     * @access private
399
     *
400
     * @param string $featured_img_trimmed Medium sized image.
401
     * @param string $featured_img Full sized image.
402
     * @param string $featured_id Attachment Id.
403
     * @param string $thumbnail Thumb sized image.
404
     * @param int    $post_id Post id.
405
     *
406
     * @return string Html content
407
     */
408
    private function get_featured_box( $featured_img_trimmed, $featured_img, $featured_id, $thumbnail, $post_id ) {
409
        $has_featured_image = ! empty( $featured_img_trimmed ) ? 'hasFeaturedImage' : '';
410
        $thumbnail          = ! is_null( $thumbnail ) ? $thumbnail : '';
411
        $dfi_empty          = is_null( $featured_img_trimmed ) ? 'dfiImgEmpty' : '';
412
413
        return "<a href='javascript:void(0)' class='dfiFeaturedImage {$has_featured_image}' title='" . __( 'Set Featured Image', self::TEXT_DOMAIN ) . "' data-post-id='" . $post_id . "'><span class='dashicons dashicons-camera'></span></a><br/>
414
            <img src='" . $thumbnail . "' class='dfiImg {$dfi_empty}'/>
415
            <div class='dfiLinks'>
416
                <a href='javascript:void(0)' data-id='{$featured_id}' data-id-local='" . $this->get_number_translation( $featured_id + 1 ) . "' class='dfiAddNew dashicons dashicons-plus' title='" . __( 'Add New', self::TEXT_DOMAIN ) . "'></a>
417
                <a href='javascript:void(0)' class='dfiRemove dashicons dashicons-minus' title='" . __( 'Remove', self::TEXT_DOMAIN ) . "'></a>
418
            </div>
419
            <div class='dfiClearFloat'></div>
420
            <input type='hidden' name='dfiFeatured[]' value='{$featured_img}'  class='dfiImageHolder' />";
421
    }
422
423
    /**
424
     * Load new featured meta box via ajax
425
     *
426
     * @since 1.0.0
427
     * @access public
428
     *
429
     * @return void
430
     */
431
    public function ajax_callback() {
432
        $featured_id = isset( $_POST['id'] ) ? (int) strip_tags( trim( $_POST['id'] ) ) : null;
433
434
        if ( is_null( $featured_id ) ) {
435
            return;
436
        }
437
438
        echo $this->nonce_field( 'dfi_fimageplug-' . $featured_id );
439
        ?>
440
        <a href="javascript:void(0)" class="dfiFeaturedImage"
441
           title="<?php echo __( 'Set Featured Image', self::TEXT_DOMAIN ) ?>"><span
442
                    class="dashicons dashicons-camera"></span></a><br/>
443
        <img src="" class="dfiImg dfiImgEmpty"/>
444
        <div class="dfiLinks">
445
            <a href="javascript:void(0)" data-id="<?php echo $featured_id ?>"
446
               data-id-local="<?php echo $this->get_number_translation( $featured_id + 1 ) ?>"
447
               class="dfiAddNew dashicons dashicons-plus" title="<?php echo __( 'Add New', self::TEXT_DOMAIN ) ?>"></a>
448
            <a href="javascript:void(0)" class="dfiRemove dashicons dashicons-minus"
449
               title="<?php echo __( 'Remove', self::TEXT_DOMAIN ) ?>"></a>
450
        </div>
451
        <div class="dfiClearFloat"></div>
452
        <input type="hidden" name="dfiFeatured[]" value="" class="dfiImageHolder"/>
453
        <?php
454
        wp_die( '' );
455
    }
456
457
    /**
458
     * Add custom class 'featured-meta-box' to meta box.
459
     *
460
     * @since 1.0.0
461
     * @access public
462
     *
463
     * @see  add_metabox_classes
464
     *
465
     * @param array $classes Classes to add in the meta box.
466
     *
467
     * @return array
468
     */
469
    public function add_metabox_classes( $classes ) {
470
        array_push( $classes, 'featured-meta-box' );
471
472
        return $classes;
473
    }
474
475
    /**
476
     * Add custom fields in media uploader.
477
     *
478
     * @since  3.4.0
479
     *
480
     * @param array $form_fields Fields to include in media attachment form.
481
     * @param array $post Post data.
482
     *
483
     * @return array
484
     */
485
    public function media_attachment_custom_fields( $form_fields, $post ) {
486
        $form_fields['dfi-link-to-image'] = array(
487
            'label' => __( 'Link to Image', self::TEXT_DOMAIN ),
488
            'input' => 'text',
489
            'value' => get_post_meta( $post->ID, '_dfi_link_to_image', true ),
490
        );
491
492
        return $form_fields;
493
    }
494
495
    /**
496
     * Save values of media uploader custom fields.
497
     *
498
     * @since 3.4.0
499
     *
500
     * @param array $post Post data for database.
501
     * @param array $attachment Attachment fields from $_POST form.
502
     *
503
     * @return array
504
     */
505
    public function media_attachment_custom_fields_save( $post, $attachment ) {
506
        if ( isset( $attachment['dfi-link-to-image'] ) ) {
507
            update_post_meta( $post['ID'], '_dfi_link_to_image', $attachment['dfi-link-to-image'] );
508
        }
509
510
        return $post;
511
    }
512
513
    /**
514
     * Update featured images in the database.
515
     *
516
     * @since 1.0.0
517
     * @access public
518
     *
519
     * @see  plugin_basename()
520
     * @see  update_post_meta()
521
     * @see  current_user_can()
522
     *
523
     * @param  int $post_id Current post id.
524
     *
525
     * @return bool
526
     */
527
    public function save_meta( $post_id ) {
528
        // Check auto save.
529
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
530
            return false;
531
        }
532
533
        if ( $this->verify_nonces() ) {
534
            // Check permission before saving data.
535
            if ( current_user_can( 'edit_posts', $post_id ) && isset( $_POST['dfiFeatured'] ) ) {
536
                update_post_meta( $post_id, 'dfiFeatured', $_POST['dfiFeatured'] );
537
            }
538
        }
539
540
        return false;
541
    }
542
543
    /**
544
     * Verify metabox nonces.
545
     *
546
     * @access protected
547
     * @see  wp_verify_nonce()
548
     *
549
     * @return bool
550
     */
551
    protected function verify_nonces() {
0 ignored issues
show
verify_nonces uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
552
        $keys = array_keys( $_POST );
553
        foreach ( $keys as $key ) {
554
            if ( preg_match( '/dfi_fimageplug-\d+$/', $key ) ) {
555
                // Verify nonce.
556
                if ( ! wp_verify_nonce( $_POST[ $key ], plugin_basename( __FILE__ ) ) ) {
557
                    return false;
558
                }
559
            }
560
        }
561
562
        return true;
563
    }
564
565
    /**
566
     * Add update notice. Displayed in plugin update page.
567
     *
568
     * @since 2.0.0
569
     * @access public
570
     *
571
     * @return void
572
     */
573
    public function update_notice() {
574
        $info = __( 'ATTENTION! Please read the <a href="https://github.com/ankitpokhrel/Dynamic-Featured-Image/wiki" target="_blank">DOCUMENTATION</a> properly before update.', self::TEXT_DOMAIN );
575
        echo '<div style="color:red; padding:7px 0;">' . strip_tags( $info, '<a><b><i><span>' ) . '</div>';
576
    }
577
578
    /**
579
     * Execute query.
580
     *
581
     * @param string $query Query to execute.
582
     *
583
     * @return null|string
584
     */
585
    private function execute_query( $query ) {
586
        return $this->db->get_var( $query );
587
    }
588
589
    /**
590
     * Get attachment id of the image by image url.
591
     *
592
     * @since 3.1.7
593
     * @access protected
594
     * @global object $wpdb
595
     *
596
     * @param  string $image_url URL of an image.
597
     *
598
     * @return string
599
     */
600
    protected function get_attachment_id( $image_url ) {
601
        return $this->execute_query( $this->db->prepare( 'SELECT ID FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
602
    }
603
604
    /**
605
     * Get image url of the image by attachment id.
606
     *
607
     * @since 2.0.0
608
     * @access public
609
     *
610
     * @see  wp_get_attachment_image_src()
611
     *
612
     * @param  int    $attachment_id attachment id of an image.
613
     * @param  string $size size of the image to fetch (thumbnail, medium, full).
614
     *
615
     * @return string
616
     */
617
    public function get_image_url( $attachment_id, $size = 'full' ) {
618
        $image_thumb = wp_get_attachment_image_src( $attachment_id, $size );
619
620
        return empty( $image_thumb ) ? null : $image_thumb[0];
621
    }
622
623
    /**
624
     * Get image thumbnail url of specific size by image url.
625
     *
626
     * @since 2.0.0
627
     * @access public
628
     *
629
     * @see  get_image_id()
630
     * @see  wp_get_attachment_image_src()
631
     *
632
     * @param  string $image_url url of an image.
633
     * @param  string $size size of the image to fetch (thumbnail, medium, full).
634
     *
635
     * @return string
636
     */
637
    public function get_image_thumb( $image_url, $size = 'thumbnail' ) {
638
        $attachment_id = $this->get_image_id( $image_url );
639
        $image_thumb   = wp_get_attachment_image_src( $attachment_id, $size );
640
641
        return empty( $image_thumb ) ? null : $image_thumb[0];
642
    }
643
644
    /**
645
     * Gets attachment id from given image url.
646
     *
647
     * @param  string $image_url url of an image.
648
     *
649
     * @since  2.0.0
650
     * @access public
651
     *
652
     * @return int|null attachment id of an image
653
     */
654
    public function get_image_id( $image_url ) {
655
        $attachment_id = $this->get_attachment_id( $image_url );
656
657
        if ( is_null( $attachment_id ) ) {
658
            // check if the image is edited image.
659
            // and try to get the attachment id.
660
            $image_url = str_replace( $this->upload_url . '/', '', $image_url );
661
            $row       = $this->execute_query( $this->db->prepare( 'SELECT post_id FROM ' . $this->db->postmeta . ' WHERE meta_value = %s', $image_url ) );
662
            if ( ! is_null( $row ) ) {
663
                $attachment_id = $row;
664
            }
665
        }
666
667
        return $attachment_id;
668
    }
669
670
    /**
671
     * Get image title.
672
     *
673
     * @since 2.0.0
674
     * @access public
675
     *
676
     * @param string $image_url URL of an image.
677
     *
678
     * @return string
679
     */
680
    public function get_image_title( $image_url ) {
681
        return $this->execute_query( $this->db->prepare( 'SELECT post_title FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
682
    }
683
684
    /**
685
     * Get image title by id.
686
     *
687
     * @since 2.0.0
688
     * @access public
689
     *
690
     * @param  int $attachment_id Attachment id of an image.
691
     *
692
     * @return string
693
     */
694
    public function get_image_title_by_id( $attachment_id ) {
695
        return $this->execute_query( $this->db->prepare( 'SELECT post_title FROM ' . $this->db->posts . ' WHERE ID = %d', $attachment_id ) );
696
    }
697
698
    /**
699
     * Get image caption.
700
     *
701
     * @since 2.0.0
702
     * @access public
703
     *
704
     * @param  string $image_url URL of an image.
705
     *
706
     * @return string
707
     */
708
    public function get_image_caption( $image_url ) {
709
        return $this->execute_query( $this->db->prepare( 'SELECT post_excerpt FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
710
    }
711
712
    /**
713
     * Get image caption by id.
714
     *
715
     * @since 2.0.0
716
     * @access public
717
     *
718
     * @param  int $attachment_id Attachment id of an image.
719
     *
720
     * @return string
721
     */
722
    public function get_image_caption_by_id( $attachment_id ) {
723
        return $this->execute_query( $this->db->prepare( 'SELECT post_excerpt FROM ' . $this->db->posts . ' WHERE ID = %d', $attachment_id ) );
724
    }
725
726
    /**
727
     * Get image alternate text.
728
     *
729
     * @since 2.0.0
730
     * @access public
731
     *
732
     * @see  get_post_meta()
733
     *
734
     * @param  string $image_url URL of an image.
735
     *
736
     * @return string
737
     */
738
    public function get_image_alt( $image_url ) {
739
        $attachment = $this->db->get_col( $this->db->prepare( 'SELECT ID FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
740
741
        $alt = null;
742
        if ( ! empty( $attachment ) ) {
743
            $alt = get_post_meta( $attachment[0], '_wp_attachment_image_alt' );
744
        }
745
746
        return ( is_null( $alt ) || empty( $alt ) ) ? null : $alt[0];
747
    }
748
749
    /**
750
     * Get image alternate text by attachment id.
751
     *
752
     * @since 2.0.0
753
     * @access public
754
     *
755
     * @see  get_post_meta()
756
     *
757
     * @param  int $attachment_id Attachment id of an image.
758
     *
759
     * @return string
760
     */
761
    public function get_image_alt_by_id( $attachment_id ) {
762
        $alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt' );
763
764
        return empty( $alt ) ? null : $alt[0];
765
    }
766
767
    /**
768
     * Get image description.
769
     *
770
     * @since 3.0.0
771
     * @access public
772
     *
773
     * @param  string $image_url URL of an image.
774
     *
775
     * @return string
776
     */
777
    public function get_image_description( $image_url ) {
778
        return $this->execute_query( $this->db->prepare( 'SELECT post_content FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
779
    }
780
781
    /**
782
     * Get image description by id.
783
     *
784
     * @since 3.0.0
785
     * @access public
786
     *
787
     * @param  int $attachment_id attachment id of an image.
788
     *
789
     * @return string
790
     */
791
    public function get_image_description_by_id( $attachment_id ) {
792
        return $this->execute_query( $this->db->prepare( 'SELECT post_content FROM ' . $this->db->posts . ' WHERE ID = %d', $attachment_id ) );
793
    }
794
795
    /**
796
     * Get link to image.
797
     *
798
     * @since 3.4.0
799
     * @access public
800
     *
801
     * @param  int $attachment_id Attachment id of an image.
802
     *
803
     * @return string|null
804
     */
805
    public function get_link_to_image( $attachment_id ) {
806
        return get_post_meta( $attachment_id, '_dfi_link_to_image', true );
807
    }
808
809
    /**
810
     * Get all attachment ids of the post.
811
     *
812
     * @since 2.0.0
813
     * @access public
814
     *
815
     * @see  get_post_meta()
816
     *
817
     * @param  int $post_id id of the current post.
818
     *
819
     * @return array
820
     */
821
    public function get_post_attachment_ids( $post_id ) {
822
        $dfi_images = get_post_meta( $post_id, 'dfiFeatured', true );
823
        $ret_val    = array();
824
825
        if ( ! empty( $dfi_images ) && is_array( $dfi_images ) ) {
826
            foreach ( $dfi_images as $dfi_image ) {
827
                $dfi_image_full = $this->separate( $dfi_image, 'full' );
828
                $ret_val[]     = $this->get_image_id( $this->upload_url . $dfi_image_full );
829
            }
830
        }
831
832
        return $ret_val;
833
    }
834
835
    /**
836
     * Fetches featured image data of nth position.
837
     *
838
     * @since  3.0.0
839
     * @access  public
840
     *
841
     * @see  get_featured_images()
842
     *
843
     * @param  int $position Position of the featured image.
844
     * @param  int $post_id Current post id.
845
     *
846
     * @return array if found, null otherwise.
847
     */
848
    public function get_nth_featured_image( $position, $post_id = null ) {
849
        if ( is_null( $post_id ) ) {
850
            global $post;
851
            $post_id = $post->ID;
852
        }
853
854
        $featured_images = $this->get_featured_images( $post_id );
855
856
        return isset( $featured_images[ $position - 2 ] ) ? $featured_images[ $position - 2 ] : null;
857
    }
858
859
    /**
860
     * Check if the image is attached with the particular post.
861
     *
862
     * @since 2.0.0
863
     * @access public
864
     *
865
     * @see  get_post_attachment_ids()
866
     *
867
     * @param  int $attachment_id Attachment id of an image.
868
     * @param  int $post_id Current post id.
869
     *
870
     * @return bool
871
     */
872
    public function is_attached( $attachment_id, $post_id ) {
873
        if ( empty( $attachment_id ) ) {
874
            return false;
875
        }
876
877
        $attachment_ids = $this->get_post_attachment_ids( $post_id );
878
879
        return in_array( $attachment_id, $attachment_ids, true ) ? true : false;
880
    }
881
882
    /**
883
     * Retrieve featured images for specific post(s).
884
     *
885
     * @since 2.0.0
886
     * @access public
887
     *
888
     * @see get_post_meta()
889
     *
890
     * @param  integer $post_id id of the current post.
891
     *
892
     * @return array
893
     */
894
    public function get_featured_images( $post_id = null ) {
895
        if ( is_null( $post_id ) ) {
896
            global $post;
897
898
            $post_id = $post->ID;
899
        }
900
901
        $dfi_images = get_post_meta( $post_id, 'dfiFeatured', true );
902
        $ret_images = array();
903
904
        if ( ! empty( $dfi_images ) && is_array( $dfi_images ) ) {
905
            $dfi_images = array_filter( $dfi_images );
906
907
            $count = 0;
908
            foreach ( $dfi_images as $dfi_image ) {
909
                $dfi_image_trimmed = $this->separate( $dfi_image );
910
                $dfi_image_full    = $this->separate( $dfi_image, 'full' );
911
912
                try {
913
                    $ret_images[ $count ]['thumb']         = $this->get_real_upload_path( $dfi_image_trimmed );
914
                    $ret_images[ $count ]['full']          = $this->get_real_upload_path( $dfi_image_full );
915
                    $ret_images[ $count ]['attachment_id'] = $this->get_image_id( $ret_images[ $count ]['full'] );
916
917
                } catch ( Exception $e ) {
918
                    /* Ignore the exception and continue with other featured images */
919
                }
920
921
                $count ++;
922
            }
923
        }
924
925
        return $ret_images;
926
    }
927
928
    /**
929
     * Check to see if the upload url is already available in path.
930
     *
931
     * @since  3.1.14
932
     * @access protected
933
     *
934
     * @param  string $img Uploaded image.
935
     *
936
     * @return string
937
     */
938
    protected function get_real_upload_path( $img ) {
939
        // check if upload path is already attached.
940
        if ( false !== strpos( $img, $this->upload_url ) || preg_match( '/https?:\/\//', $img ) ) {
941
            return $img;
942
        }
943
944
        return $this->upload_url . $img;
945
    }
946
947
    /**
948
     * Retrieve featured images for specific post(s) including the default Featured Image.
949
     *
950
     * @since 3.1.7
951
     * @access public
952
     *
953
     * @see  $this->get_featured_images()
954
     *
955
     * @param int $post_id Current post id.
956
     *
957
     * @return array An array of images or an empty array on failure
958
     */
959
    public function get_all_featured_images( $post_id = null ) {
960
        if ( is_null( $post_id ) ) {
961
            global $post;
962
963
            $post_id = $post->ID;
964
        }
965
966
        $thumbnail_id         = get_post_thumbnail_id( $post_id );
967
        $featured_image_array = array();
968
969
        if ( ! empty( $thumbnail_id ) ) {
970
            $featured_image         = array(
971
                'thumb'         => wp_get_attachment_thumb_url( $thumbnail_id ),
972
                'full'          => wp_get_attachment_url( $thumbnail_id ),
973
                'attachment_id' => $thumbnail_id,
974
            );
975
976
            $featured_image_array[] = $featured_image;
977
        }
978
979
        return array_merge( $featured_image_array, $this->get_featured_images( $post_id ) );
980
    }
981
982
    /**
983
     * Load the plugin's textdomain hooked to 'plugins_loaded'.
984
     *
985
     * @since 1.0.0
986
     * @access public
987
     *
988
     * @see    load_plugin_textdomain()
989
     * @see    plugin_basename()
990
     * @action plugins_loaded
991
     *
992
     * @codeCoverageIgnore
993
     *
994
     * @return void
995
     */
996
    public function load_plugin_textdomain() {
997
        load_plugin_textdomain(
998
            self::TEXT_DOMAIN,
999
            false,
1000
            dirname( plugin_basename( __FILE__ ) ) . '/languages/'
1001
        );
1002
    }
1003
}
1004
1005
/**
1006
 * Instantiate the main class.
1007
 *
1008
 * @since 1.0.0
1009
 * @access public
1010
 *
1011
 * @var object $dynamic_featured_image holds the instantiated class {@uses Dynamic_Featured_Image}
1012
 */
1013
global $dynamic_featured_image;
1014
$dynamic_featured_image = new Dynamic_Featured_Image();
1015