Completed
Pull Request — master (#78)
by Ankit
01:34
created

Dynamic_Featured_Image   F

Complexity

Total Complexity 99

Size/Duplication

Total Lines 1027
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 77.86%

Importance

Changes 0
Metric Value
wmc 99
lcom 1
cbo 1
dl 0
loc 1027
ccs 218
cts 280
cp 0.7786
rs 1.492
c 0
b 0
f 0

42 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 37 1
A get_protocol() 0 3 2
A enqueue_admin_scripts() 0 23 1
A dfi_action_links() 0 7 1
A initialize_featured_box() 0 24 5
A get_number_translation() 0 13 3
A dfi_add_meta_box() 0 31 4
A separate() 0 9 4
A nonce_field() 0 3 1
A get_featured_box() 0 14 4
A ajax_callback() 0 29 3
A add_metabox_classes() 0 5 1
A media_attachment_custom_fields() 0 9 1
A media_attachment_custom_fields_save() 0 7 2
B save_meta() 0 17 7
A sanitize_array() 0 9 2
A verify_nonces() 0 18 5
A update_notice() 0 6 1
A execute_query() 0 3 1
A get_attachment_id() 0 3 1
A get_image_url() 0 5 2
A get_image_thumb_by_attachment_id() 0 5 2
A get_image_thumb() 0 6 2
A get_image_id() 0 16 3
A get_image_title() 0 3 1
A get_image_title_by_id() 0 3 1
A get_image_caption() 0 3 1
A get_image_caption_by_id() 0 3 1
A get_image_alt() 0 10 4
A get_image_alt_by_id() 0 5 2
A get_image_description() 0 3 1
A get_image_description_by_id() 0 3 1
A get_link_to_image() 0 3 1
A get_post_attachment_ids() 0 13 4
A get_real_post_id() 0 9 3
A get_nth_featured_image() 0 7 2
A is_attached() 0 9 3
A get_featured_images() 0 27 5
A get_real_upload_path() 0 8 3
A get_all_featured_images() 0 17 2
A load_plugin_textdomain() 0 7 1
A featured_meta_box() 0 24 4

How to fix   Complexity   

Complex Class

Complex classes like Dynamic_Featured_Image often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Dynamic_Featured_Image, and based on these observations, apply Extract Interface, too.

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