Completed
Push — master ( a944c7...8da42b )
by Ankit
04:52 queued 01:34
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
     * Documentation Link.
64
     *
65
     * @since 3.6.0
66
     */
67
    const WIKI_LINK = 'https://github.com/ankitpokhrel/Dynamic-Featured-Image/wiki/';
68
69
    /**
70
     * Upgrade Link.
71
     *
72
     * @since 3.6.0
73
     */
74
    const UPGRADE_LINK = 'https://ankitpokhrel.com/explore/dynamic-featured-image-pro/';
75
76
    /**
77
     * Image upload directory.
78
     *
79
     * @var $upload_dir string
80
     */
81
    private $upload_dir;
82
83
    /**
84
     * Image upload URL.
85
     *
86
     * @var $upload_url string
87
     */
88
    private $upload_url;
89
90
    /**
91
     * Database object.
92
     *
93
     * @var $db wpdb
94
     */
95
    private $db;
96
97
    /**
98
     * Title for dfi metabox.
99
     *
100
     * @var $metabox_title string
101
     */
102
    protected $metabox_title;
103
104
    /**
105
     * Users post type filter for dfi metabox.
106
     *
107
     * @var $user_filter array
108
     */
109
    protected $user_filter;
110
111
    /**
112
     * Constructor. Hooks all interactions to initialize the class.
113
     *
114
     * @since 1.0.0
115
     * @access public
116
     * @global object $wpdb
117
     *
118
     * @see     add_action()
119
     */
120
    public function __construct() {
121
        // plugin update warning.
122
        add_action( 'in_plugin_update_message-' . plugin_basename( __FILE__ ), array( $this, 'update_notice' ) );
123
124
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
125
        add_action( 'add_meta_boxes', array( $this, 'initialize_featured_box' ) );
126
        add_action( 'save_post', array( $this, 'save_meta' ) );
127
        add_action( 'plugins_loaded', array( $this, 'load_plugin_textdomain' ) );
128
129
        // handle ajax request.
130
        add_action( 'wp_ajax_dfiMetaBox_callback', array( $this, 'ajax_callback' ) );
131
132
        // add action links.
133
        add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'dfi_action_links' ) );
134
135
        // media uploader custom fields.
136
        add_filter( 'attachment_fields_to_edit', array( $this, 'media_attachment_custom_fields' ), 10, 2 );
137
        add_filter( 'attachment_fields_to_save', array( $this, 'media_attachment_custom_fields_save' ), 10, 2 );
138
139
        // get the site protocol.
140
        $protocol = $this->get_protocol();
141
142
        $this->upload_dir = wp_upload_dir();
143
        $this->upload_url = preg_replace( '#^https?://#', '', $this->upload_dir['baseurl'] );
144
145
        // add protocol to the upload url.
146
        $this->upload_url = $protocol . $this->upload_url;
147
148
        // post type filter added by user.
149
        $this->user_filter = array();
150
151
        global $wpdb;
152
        $this->db = $wpdb;
153
    }
154
155
    /**
156
     * Return site protocol.
157
     *
158
     * @since 3.5.1
159
     * @access public
160
     *
161
     * @return string
162
     */
163
    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...
164
        return ( ( ! empty( $_SERVER['HTTPS'] ) && 'off' !== $_SERVER['HTTPS'] ) ||
165
                 ( ! empty( $_SERVER['SERVER_PORT'] ) && 443 === $_SERVER['SERVER_PORT'] ) ) ? 'https://' : 'http://';
166
    }
167
168
    /**
169
     * Add required admin scripts.
170
     *
171
     * @since 1.0.0
172
     * @access public
173
     *
174
     * @see  wp_enque_style()
175
     * @see  wp_register_script()
176
     * @see  wp_enqueue_script()
177
     *
178
     * @return void
179
     */
180
    public function enqueue_admin_scripts() {
181
        // enqueue styles.
182
        wp_enqueue_style( 'style-dfi', plugins_url( '/css/style-dfi.css', __FILE__ ), array(), self::VERSION );
183
184
        // register script.
185
        wp_register_script( 'scripts-dfi', plugins_url( '/js/script-dfi.js', __FILE__ ), array( 'jquery' ), self::VERSION );
186
187
        // localize the script with required data.
188
        wp_localize_script(
189
            'scripts-dfi',
190
            'DFI_SPECIFIC',
191
            array(
192
                'upload_url'               => $this->upload_url,
193
                'metabox_title'            => __( $this->metabox_title, self::TEXT_DOMAIN ),
194
                'mediaSelector_title'      => __( 'Dynamic Featured Image - Media Selector', self::TEXT_DOMAIN ),
195
                'mediaSelector_buttonText' => __( 'Set Featured Image', self::TEXT_DOMAIN ),
196
                'ajax_nonce'               => wp_create_nonce( plugin_basename( __FILE__ ) ),
197
            )
198
        );
199
200
        // enqueue scripts.
201
        wp_enqueue_script( 'scripts-dfi' );
202
    }
203
204
    /**
205
     * Add upgrade link.
206
     *
207
     * @access public
208
     * @since  3.5.1
209
     * @action plugin_action_links
210
     *
211
     * @codeCoverageIgnore
212
     *
213
     * @param  array $links Action links.
214
     *
215
     * @return array
216
     */
217
    public function dfi_action_links( $links ) {
218
        $upgrade_link = array(
219
            '<a href="' . self::UPGRADE_LINK . '" target="_blank">Upgrade to Premium</a>'
220
        );
221
222
        return array_merge( $links, $upgrade_link );
223
    }
224
225
    /**
226
     * Add featured meta boxes dynamically.
227
     *
228
     * @since 1.0.0
229
     * @access public
230
     * @global object $post
231
     *
232
     * @see  get_post_meta()
233
     * @see  get_post_types()
234
     * @see  add_meta_box()
235
     * @see  add_filter()
236
     *
237
     * @return void
238
     */
239
    public function initialize_featured_box() {
240
        global $post;
241
242
        // make metabox title dynamic.
243
        $this->metabox_title = apply_filters( 'dfi_set_metabox_title', __( 'Featured Image', self::TEXT_DOMAIN ) );
244
245
        $featured_data  = get_post_meta( $post->ID, 'dfiFeatured', true );
246
        $total_featured = count( $featured_data );
247
248
        $default_filter    = array( 'attachment', 'revision', 'nav_menu_item' );
249
        $this->user_filter = apply_filters( 'dfi_post_type_user_filter', $this->user_filter );
250
        $filter            = array_merge( $default_filter, $this->user_filter );
251
252
        $post_types = get_post_types();
253
        $post_types = array_diff( $post_types, $filter );
254
255
        $post_types = apply_filters( 'dfi_post_types', $post_types );
256
257
        if ( ! empty( $featured_data ) && $total_featured >= 1 ) {
258
            $i = 2;
259
            foreach ( $featured_data as $featured ) {
260
                $this->dfi_add_meta_box( $post_types, $featured, $i );
261
                $i ++;
262
            }
263
        } else {
264
            $this->dfi_add_meta_box( $post_types );
265
        }
266
    }
267
268
    /**
269
     * Translates more than one digit number digit by digit.
270
     *
271
     * @param  int $number Integer to be translated.
272
     *
273
     * @return string Translated number
274
     */
275
    protected function get_number_translation( $number ) {
276
        if ( $number <= 9 ) {
277
            return __( $number, self::TEXT_DOMAIN );
278
        } else {
279
            $pieces = str_split( $number, 1 );
280
            $buffer = '';
281
            foreach ( $pieces as $piece ) {
282
                $buffer .= __( $piece, self::TEXT_DOMAIN );
283
            }
284
285
            return $buffer;
286
        }
287
    }
288
289
    /**
290
     * Adds meta boxes.
291
     *
292
     * @param  array  $post_types Post types to show featured image box.
293
     * @param  object $featured Callback arguments.
294
     * @param  int    $i Index of the featured image.
295
     *
296
     * @return void
297
     */
298
    private function dfi_add_meta_box( $post_types, $featured = null, $i = null ) {
299
        if ( ! is_null( $i ) ) {
300
            foreach ( $post_types as $type ) {
301
                add_meta_box(
302
                    'dfiFeaturedMetaBox-' . $i,
303
                    __( $this->metabox_title, self::TEXT_DOMAIN ) . ' ' . $this->get_number_translation( $i ),
304
                    array( $this, 'featured_meta_box' ),
305
                    $type,
306
                    'side',
307
                    'low',
308
                    array( $featured, $i + 1 )
309
                );
310
311
                add_filter( "postbox_classes_{$type}_dfiFeaturedMetaBox-" . $i, array( $this, 'add_metabox_classes' ) );
312
            }
313
        } else {
314
            foreach ( $post_types as $type ) {
315
                add_meta_box(
316
                    'dfiFeaturedMetaBox',
317
                    __( $this->metabox_title, self::TEXT_DOMAIN ) . ' ' . __( 2, self::TEXT_DOMAIN ),
318
                    array( $this, 'featured_meta_box' ),
319
                    $type,
320
                    'side',
321
                    'low',
322
                    array( null, null )
323
                );
324
325
                add_filter( "postbox_classes_{$type}_dfiFeaturedMetaBox", array( $this, 'add_metabox_classes' ) );
326
            }
327
        }
328
    }
329
330
    /**
331
     * Separate thumb and full image url from given URL string.
332
     *
333
     * @since  3.3.1
334
     *
335
     * @param  string $url_string Url string.
336
     * @param  string $state Thumb or full.
337
     *
338
     * @return string|null
339
     */
340
    private function separate( $url_string, $state = 'thumb' ) {
341
        $image_piece = explode( ',', $url_string );
342
343
        if ( 'thumb' === $state ) {
344
            return isset( $image_piece[0] ) ? $image_piece[0] : null;
345
        }
346
347
        return isset( $image_piece[1] ) ? $image_piece[1] : null;
348
    }
349
350
    /**
351
     * Create a nonce field.
352
     *
353
     * @since  3.5.0
354
     *
355
     * @see  wp_nonce_field()
356
     * @see  plugin_basename()
357
     *
358
     * @codeCoverageIgnore
359
     *
360
     * @param  string $key Nonce key.
361
     *
362
     * @return string
363
     */
364
    protected function nonce_field( $key ) {
365
        return wp_nonce_field( plugin_basename( __FILE__ ), $key, true, false );
366
    }
367
368
    /**
369
     * Featured meta box as seen in the admin.
370
     *
371
     * @since 1.0.0
372
     * @access public
373
     *
374
     * @param  object $post Global post object.
375
     * @param  array  $featured Array containing featured image count.
376
     *
377
     * @throws Exception Medium size image not found.
378
     * @return void
379
     */
380
    public function featured_meta_box( $post, $featured ) {
381
        $featured_img         = $featured['args'][0];
382
        $featured_id          = is_null( $featured['args'][1] ) ? 2 : --$featured['args'][1];
383
        $featured_img_full    = $featured_img;
384
        $featured_img_trimmed = $featured_img;
385
386
        if ( ! is_null( $featured_img ) ) {
387
            $featured_img_trimmed = $this->separate( $featured_img );
388
            $featured_img_full    = $this->separate( $featured_img, 'full' );
389
        }
390
391
        try {
392
            $thumbnail = $this->get_image_thumb( $this->upload_url . $featured_img_full, 'medium' );
393
            if ( is_null( $thumbnail ) ) {
394
                // medium sized thumbnail image is missing.
395
                throw new Exception( 'Medium size image not found', 1 );
396
            }
397
        } catch ( Exception $e ) {
398
            // since medium sized thumbnail image was not found,
399
            // let's set full image url as thumbnail.
400
            $thumbnail = $featured_img_full;
401
        }
402
403
        // Add a nonce field.
404
        echo $this->nonce_field( 'dfi_fimageplug-' . $featured_id ); // WPCS: XSS ok.
405
        echo $this->get_featured_box( $featured_img_trimmed, $featured_img, $featured_id, $thumbnail, $post->ID ); // WPCS: XSS ok.
406
    }
407
408
    /**
409
     * Returns featured box html content.
410
     *
411
     * @since  3.1.0
412
     * @access private
413
     *
414
     * @param string $featured_img_trimmed Medium sized image.
415
     * @param string $featured_img Full sized image.
416
     * @param string $featured_id Attachment Id.
417
     * @param string $thumbnail Thumb sized image.
418
     * @param int    $post_id Post id.
419
     *
420
     * @return string Html content
421
     */
422
    private function get_featured_box( $featured_img_trimmed, $featured_img, $featured_id, $thumbnail, $post_id ) {
423
        $has_featured_image = ! empty( $featured_img_trimmed ) ? 'hasFeaturedImage' : '';
424
        $thumbnail          = ! is_null( $thumbnail ) ? $thumbnail : '';
425
        $dfi_empty          = is_null( $featured_img_trimmed ) ? 'dfiImgEmpty' : '';
426
427
        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/>
428
            <img src='" . $thumbnail . "' class='dfiImg {$dfi_empty}'/>
429
            <div class='dfiLinks'>
430
                <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>
431
                <a href='javascript:void(0)' class='dfiRemove dashicons dashicons-minus' title='" . __( 'Remove', self::TEXT_DOMAIN ) . "'></a>
432
            </div>
433
            <div class='dfiClearFloat'></div>
434
            <input type='hidden' name='dfiFeatured[]' value='{$featured_img}'  class='dfiImageHolder' />";
435
    }
436
437
    /**
438
     * Load new featured meta box via ajax.
439
     *
440
     * @since 1.0.0
441
     * @access public
442
     *
443
     * @return void
444
     */
445
    public function ajax_callback() {
446
        check_ajax_referer( plugin_basename( __FILE__ ), 'security' );
447
448
        $featured_id = isset( $_POST['id'] ) ? intval( wp_unslash( $_POST['id'] ) ) : null;
449
450
        if ( ! is_numeric( $featured_id ) ) {
451
            return;
452
        }
453
454
        // @codingStandardsIgnoreStart
455
        echo $this->nonce_field( 'dfi_fimageplug-' . $featured_id );
456
        ?>
457
        <a href="javascript:void(0)" class="dfiFeaturedImage"
458
           title="<?php echo __( 'Set Featured Image', self::TEXT_DOMAIN ) ?>"><span
459
                    class="dashicons dashicons-camera"></span></a><br/>
460
        <img src="" class="dfiImg dfiImgEmpty"/>
461
        <div class="dfiLinks">
462
            <a href="javascript:void(0)" data-id="<?php echo $featured_id ?>"
463
               data-id-local="<?php echo $this->get_number_translation( $featured_id + 1 ) ?>"
464
               class="dfiAddNew dashicons dashicons-plus" title="<?php echo __( 'Add New', self::TEXT_DOMAIN ) ?>"></a>
465
            <a href="javascript:void(0)" class="dfiRemove dashicons dashicons-minus"
466
               title="<?php echo __( 'Remove', self::TEXT_DOMAIN ) ?>"></a>
467
        </div>
468
        <div class="dfiClearFloat"></div>
469
        <input type="hidden" name="dfiFeatured[]" value="" class="dfiImageHolder"/>
470
        <?php
471
        // @codingStandardsIgnoreEnd
472
        wp_die( '' );
473
    }
474
475
    /**
476
     * Add custom class 'featured-meta-box' to meta box.
477
     *
478
     * @since 1.0.0
479
     * @access public
480
     *
481
     * @see  add_metabox_classes
482
     *
483
     * @param array $classes Classes to add in the meta box.
484
     *
485
     * @return array
486
     */
487
    public function add_metabox_classes( $classes ) {
488
        array_push( $classes, 'featured-meta-box' );
489
490
        return $classes;
491
    }
492
493
    /**
494
     * Add custom fields in media uploader.
495
     *
496
     * @since  3.4.0
497
     *
498
     * @param array $form_fields Fields to include in media attachment form.
499
     * @param array $post Post data.
500
     *
501
     * @return array
502
     */
503
    public function media_attachment_custom_fields( $form_fields, $post ) {
504
        $form_fields['dfi-link-to-image'] = array(
505
            'label' => __( 'Link to Image', self::TEXT_DOMAIN ),
506
            'input' => 'text',
507
            'value' => get_post_meta( $post->ID, '_dfi_link_to_image', true ),
508
        );
509
510
        return $form_fields;
511
    }
512
513
    /**
514
     * Save values of media uploader custom fields.
515
     *
516
     * @since 3.4.0
517
     *
518
     * @param array $post Post data for database.
519
     * @param array $attachment Attachment fields from $_POST form.
520
     *
521
     * @return array
522
     */
523
    public function media_attachment_custom_fields_save( $post, $attachment ) {
524
        if ( isset( $attachment['dfi-link-to-image'] ) ) {
525
            update_post_meta( $post['ID'], '_dfi_link_to_image', $attachment['dfi-link-to-image'] );
526
        }
527
528
        return $post;
529
    }
530
531
    /**
532
     * Update featured images in the database.
533
     *
534
     * @since 1.0.0
535
     * @access public
536
     *
537
     * @see  plugin_basename()
538
     * @see  update_post_meta()
539
     * @see  current_user_can()
540
     *
541
     * @param  int $post_id Current post id.
542
     *
543
     * @return bool|null
544
     */
545
    public function save_meta( $post_id ) {
546
        // Check auto save.
547
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
548
            return false;
549
        }
550
551
        if ( ! $this->verify_nonces() ) {
552
            return false;
553
        }
554
555
        // Check permission before saving data.
556
        if ( current_user_can( 'edit_posts', $post_id ) && isset( $_POST['dfiFeatured'] ) ) { // WPCS: CSRF ok.
557
            $featured_images = is_array( $_POST['dfiFeatured'] ) ? $_POST['dfiFeatured'] : []; // WPCS: sanitization ok, CSRF ok.
558
559
            $sanitized = [];
560
            foreach ( $featured_images as $image ) {
561
                $sanitized[] = sanitize_text_field( wp_unslash( $image ) );
562
            }
563
564
            update_post_meta( $post_id, 'dfiFeatured', $sanitized );
565
        }
566
    }
567
568
    /**
569
     * Verify metabox nonces.
570
     *
571
     * @access protected
572
     * @see  wp_verify_nonce()
573
     *
574
     * @return bool
575
     */
576
    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...
577
        $keys = preg_grep( '/dfi_fimageplug-\d+$/', array_keys( $_POST ) ); // WPCS: CSRF ok.
578
579
        if ( empty( $keys ) ) {
580
            return false;
581
        }
582
583
        foreach ( $keys as $key ) {
584
            // Verify nonce.
585
            if ( ! isset( $_POST[ $key ] ) ||
586
                 ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ $key ] ) ), plugin_basename( __FILE__ ) )
587
            ) {
588
                return false;
589
            }
590
        }
591
592
        return true;
593
    }
594
595
    /**
596
     * Add update notice. Displayed in plugin update page.
597
     *
598
     * @since 2.0.0
599
     * @access public
600
     *
601
     * @return void
602
     */
603
    public function update_notice() {
604
        $info = __( 'ATTENTION! Please read the <a href="' . self::WIKI_LINK . '" target="_blank">DOCUMENTATION</a> properly before update.',
605
        self::TEXT_DOMAIN );
606
607
        echo '<span style="color:red; padding:7px 0; display: block">' . strip_tags( $info, '<a><b><i><span>' ) . '</span>'; // WPCS: XSS ok.
608
    }
609
610
    /**
611
     * Execute query.
612
     *
613
     * @param string $query Query to execute.
614
     *
615
     * @return null|string
616
     */
617
    private function execute_query( $query ) {
618
        return $this->db->get_var( $query );
619
    }
620
621
    /**
622
     * Get attachment id of the image by image url.
623
     *
624
     * @since 3.1.7
625
     * @access protected
626
     * @global object $wpdb
627
     *
628
     * @param  string $image_url URL of an image.
629
     *
630
     * @return string
631
     */
632
    protected function get_attachment_id( $image_url ) {
633
        return $this->execute_query( $this->db->prepare( 'SELECT ID FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
634
    }
635
636
    /**
637
     * Get image url of the image by attachment id.
638
     *
639
     * @since 2.0.0
640
     * @access public
641
     *
642
     * @see  wp_get_attachment_image_src()
643
     *
644
     * @param  int    $attachment_id attachment id of an image.
645
     * @param  string $size size of the image to fetch (thumbnail, medium, full).
646
     *
647
     * @return string
648
     */
649
    public function get_image_url( $attachment_id, $size = 'full' ) {
650
        $image_thumb = wp_get_attachment_image_src( $attachment_id, $size );
651
652
        return empty( $image_thumb ) ? null : $image_thumb[0];
653
    }
654
655
    /**
656
     * Get image thumbnail url of specific size by image url.
657
     *
658
     * @since 2.0.0
659
     * @access public
660
     *
661
     * @see  get_image_id()
662
     * @see  wp_get_attachment_image_src()
663
     *
664
     * @param  string $image_url url of an image.
665
     * @param  string $size size of the image to fetch (thumbnail, medium, full).
666
     *
667
     * @return string
668
     */
669
    public function get_image_thumb( $image_url, $size = 'thumbnail' ) {
670
        $attachment_id = $this->get_image_id( $image_url );
671
        $image_thumb   = wp_get_attachment_image_src( $attachment_id, $size );
672
673
        return empty( $image_thumb ) ? null : $image_thumb[0];
674
    }
675
676
    /**
677
     * Gets attachment id from given image url.
678
     *
679
     * @param  string $image_url url of an image.
680
     *
681
     * @since  2.0.0
682
     * @access public
683
     *
684
     * @return int|null attachment id of an image
685
     */
686
    public function get_image_id( $image_url ) {
687
        $attachment_id = $this->get_attachment_id( $image_url );
688
689
        if ( is_null( $attachment_id ) ) {
690
            // check if the image is edited image.
691
            // and try to get the attachment id.
692
            $image_url = str_replace( $this->upload_url . '/', '', $image_url );
693
            $row       = $this->execute_query( $this->db->prepare( 'SELECT post_id FROM ' . $this->db->postmeta . ' WHERE meta_value = %s', $image_url ) );
694
            if ( ! is_null( $row ) ) {
695
                $attachment_id = $row;
696
            }
697
        }
698
699
        return $attachment_id;
700
    }
701
702
    /**
703
     * Get image title.
704
     *
705
     * @since 2.0.0
706
     * @access public
707
     *
708
     * @param string $image_url URL of an image.
709
     *
710
     * @return string
711
     */
712
    public function get_image_title( $image_url ) {
713
        return $this->execute_query( $this->db->prepare( 'SELECT post_title FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
714
    }
715
716
    /**
717
     * Get image title by id.
718
     *
719
     * @since 2.0.0
720
     * @access public
721
     *
722
     * @param  int $attachment_id Attachment id of an image.
723
     *
724
     * @return string
725
     */
726
    public function get_image_title_by_id( $attachment_id ) {
727
        return $this->execute_query( $this->db->prepare( 'SELECT post_title FROM ' . $this->db->posts . ' WHERE ID = %d', $attachment_id ) );
728
    }
729
730
    /**
731
     * Get image caption.
732
     *
733
     * @since 2.0.0
734
     * @access public
735
     *
736
     * @param  string $image_url URL of an image.
737
     *
738
     * @return string
739
     */
740
    public function get_image_caption( $image_url ) {
741
        return $this->execute_query( $this->db->prepare( 'SELECT post_excerpt FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
742
    }
743
744
    /**
745
     * Get image caption by id.
746
     *
747
     * @since 2.0.0
748
     * @access public
749
     *
750
     * @param  int $attachment_id Attachment id of an image.
751
     *
752
     * @return string
753
     */
754
    public function get_image_caption_by_id( $attachment_id ) {
755
        return $this->execute_query( $this->db->prepare( 'SELECT post_excerpt FROM ' . $this->db->posts . ' WHERE ID = %d', $attachment_id ) );
756
    }
757
758
    /**
759
     * Get image alternate text.
760
     *
761
     * @since 2.0.0
762
     * @access public
763
     *
764
     * @see  get_post_meta()
765
     *
766
     * @param  string $image_url URL of an image.
767
     *
768
     * @return string
769
     */
770
    public function get_image_alt( $image_url ) {
771
        $attachment = $this->db->get_col( $this->db->prepare( 'SELECT ID FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
772
773
        $alt = null;
774
        if ( ! empty( $attachment ) ) {
775
            $alt = get_post_meta( $attachment[0], '_wp_attachment_image_alt' );
776
        }
777
778
        return ( is_null( $alt ) || empty( $alt ) ) ? null : $alt[0];
779
    }
780
781
    /**
782
     * Get image alternate text by attachment id.
783
     *
784
     * @since 2.0.0
785
     * @access public
786
     *
787
     * @see  get_post_meta()
788
     *
789
     * @param  int $attachment_id Attachment id of an image.
790
     *
791
     * @return string
792
     */
793
    public function get_image_alt_by_id( $attachment_id ) {
794
        $alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt' );
795
796
        return empty( $alt ) ? null : $alt[0];
797
    }
798
799
    /**
800
     * Get image description.
801
     *
802
     * @since 3.0.0
803
     * @access public
804
     *
805
     * @param  string $image_url URL of an image.
806
     *
807
     * @return string
808
     */
809
    public function get_image_description( $image_url ) {
810
        return $this->execute_query( $this->db->prepare( 'SELECT post_content FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
811
    }
812
813
    /**
814
     * Get image description by id.
815
     *
816
     * @since 3.0.0
817
     * @access public
818
     *
819
     * @param  int $attachment_id attachment id of an image.
820
     *
821
     * @return string
822
     */
823
    public function get_image_description_by_id( $attachment_id ) {
824
        return $this->execute_query( $this->db->prepare( 'SELECT post_content FROM ' . $this->db->posts . ' WHERE ID = %d', $attachment_id ) );
825
    }
826
827
    /**
828
     * Get link to image.
829
     *
830
     * @since 3.4.0
831
     * @access public
832
     *
833
     * @param  int $attachment_id Attachment id of an image.
834
     *
835
     * @return string|null
836
     */
837
    public function get_link_to_image( $attachment_id ) {
838
        return get_post_meta( $attachment_id, '_dfi_link_to_image', true );
839
    }
840
841
    /**
842
     * Get all attachment ids of the post.
843
     *
844
     * @since 2.0.0
845
     * @access public
846
     *
847
     * @see  get_post_meta()
848
     *
849
     * @param  int $post_id id of the current post.
850
     *
851
     * @return array
852
     */
853
    public function get_post_attachment_ids( $post_id ) {
854
        $dfi_images = get_post_meta( $post_id, 'dfiFeatured', true );
855
        $ret_val    = array();
856
857
        if ( ! empty( $dfi_images ) && is_array( $dfi_images ) ) {
858
            foreach ( $dfi_images as $dfi_image ) {
859
                $dfi_image_full = $this->separate( $dfi_image, 'full' );
860
                $ret_val[]     = $this->get_image_id( $this->upload_url . $dfi_image_full );
861
            }
862
        }
863
864
        return $ret_val;
865
    }
866
867
    /**
868
     * Fetches featured image data of nth position.
869
     *
870
     * @since  3.0.0
871
     * @access  public
872
     *
873
     * @see  get_featured_images()
874
     *
875
     * @param  int $position Position of the featured image.
876
     * @param  int $post_id Current post id.
877
     *
878
     * @return array if found, null otherwise.
879
     */
880
    public function get_nth_featured_image( $position, $post_id = null ) {
881
        if ( is_null( $post_id ) ) {
882
            global $post;
883
            $post_id = $post->ID;
884
        }
885
886
        $featured_images = $this->get_featured_images( $post_id );
887
888
        return isset( $featured_images[ $position - 2 ] ) ? $featured_images[ $position - 2 ] : null;
889
    }
890
891
    /**
892
     * Check if the image is attached with the particular post.
893
     *
894
     * @since 2.0.0
895
     * @access public
896
     *
897
     * @see  get_post_attachment_ids()
898
     *
899
     * @param  int $attachment_id Attachment id of an image.
900
     * @param  int $post_id Current post id.
901
     *
902
     * @return bool
903
     */
904
    public function is_attached( $attachment_id, $post_id ) {
905
        if ( empty( $attachment_id ) ) {
906
            return false;
907
        }
908
909
        $attachment_ids = $this->get_post_attachment_ids( $post_id );
910
911
        return in_array( $attachment_id, $attachment_ids, true ) ? true : false;
912
    }
913
914
    /**
915
     * Retrieve featured images for specific post(s).
916
     *
917
     * @since 2.0.0
918
     * @access public
919
     *
920
     * @see get_post_meta()
921
     *
922
     * @param  integer $post_id id of the current post.
923
     *
924
     * @return array
925
     */
926
    public function get_featured_images( $post_id = null ) {
927
        if ( is_null( $post_id ) ) {
928
            global $post;
929
930
            $post_id = $post->ID;
931
        }
932
933
        $dfi_images = get_post_meta( $post_id, 'dfiFeatured', true );
934
        $ret_images = array();
935
936
        if ( ! empty( $dfi_images ) && is_array( $dfi_images ) ) {
937
            $dfi_images = array_filter( $dfi_images );
938
939
            $count = 0;
940
            foreach ( $dfi_images as $dfi_image ) {
941
                $dfi_image_trimmed = $this->separate( $dfi_image );
942
                $dfi_image_full    = $this->separate( $dfi_image, 'full' );
943
944
                try {
945
                    $ret_images[ $count ]['thumb']         = $this->get_real_upload_path( $dfi_image_trimmed );
946
                    $ret_images[ $count ]['full']          = $this->get_real_upload_path( $dfi_image_full );
947
                    $ret_images[ $count ]['attachment_id'] = $this->get_image_id( $ret_images[ $count ]['full'] );
948
949
                } catch ( Exception $e ) {
950
                    /* Ignore the exception and continue with other featured images */
951
                }
952
953
                $count ++;
954
            }
955
        }
956
957
        return $ret_images;
958
    }
959
960
    /**
961
     * Check to see if the upload url is already available in path.
962
     *
963
     * @since  3.1.14
964
     * @access protected
965
     *
966
     * @param  string $img Uploaded image.
967
     *
968
     * @return string
969
     */
970
    protected function get_real_upload_path( $img ) {
971
        // check if upload path is already attached.
972
        if ( false !== strpos( $img, $this->upload_url ) || preg_match( '/https?:\/\//', $img ) ) {
973
            return $img;
974
        }
975
976
        return $this->upload_url . $img;
977
    }
978
979
    /**
980
     * Retrieve featured images for specific post(s) including the default Featured Image.
981
     *
982
     * @since 3.1.7
983
     * @access public
984
     *
985
     * @see  $this->get_featured_images()
986
     *
987
     * @param int $post_id Current post id.
988
     *
989
     * @return array An array of images or an empty array on failure
990
     */
991
    public function get_all_featured_images( $post_id = null ) {
992
        if ( is_null( $post_id ) ) {
993
            global $post;
994
995
            $post_id = $post->ID;
996
        }
997
998
        $thumbnail_id         = get_post_thumbnail_id( $post_id );
999
        $featured_image_array = array();
1000
1001
        if ( ! empty( $thumbnail_id ) ) {
1002
            $featured_image         = array(
1003
                'thumb'         => wp_get_attachment_thumb_url( $thumbnail_id ),
1004
                'full'          => wp_get_attachment_url( $thumbnail_id ),
1005
                'attachment_id' => $thumbnail_id,
1006
            );
1007
1008
            $featured_image_array[] = $featured_image;
1009
        }
1010
1011
        return array_merge( $featured_image_array, $this->get_featured_images( $post_id ) );
1012
    }
1013
1014
    /**
1015
     * Load the plugin's textdomain hooked to 'plugins_loaded'.
1016
     *
1017
     * @since 1.0.0
1018
     * @access public
1019
     *
1020
     * @see    load_plugin_textdomain()
1021
     * @see    plugin_basename()
1022
     * @action plugins_loaded
1023
     *
1024
     * @codeCoverageIgnore
1025
     *
1026
     * @return void
1027
     */
1028
    public function load_plugin_textdomain() {
1029
        load_plugin_textdomain(
1030
            self::TEXT_DOMAIN,
1031
            false,
1032
            dirname( plugin_basename( __FILE__ ) ) . '/languages/'
1033
        );
1034
    }
1035
}
1036
1037
/**
1038
 * Instantiate the main class.
1039
 *
1040
 * @since 1.0.0
1041
 * @access public
1042
 *
1043
 * @var object $dynamic_featured_image holds the instantiated class {@uses Dynamic_Featured_Image}
1044
 */
1045
global $dynamic_featured_image;
1046
$dynamic_featured_image = new Dynamic_Featured_Image();
1047