Completed
Pull Request — master (#75)
by Collins
02:39
created

Dynamic_Featured_Image::execute_query()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
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.5
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 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.0.1
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.5';
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 1
        add_action('admin_notices', array($this, 'admin_notice'));
139 1
        add_action('network_admin_notices', array($this, 'admin_notice'));
140
141 1
        add_action('admin_init', array($this, 'dismiss_admin_notice'));
142
143
        // get the site protocol.
144 1
        $protocol = $this->get_protocol();
145
146 1
        $this->upload_dir = wp_upload_dir();
147 1
        $this->upload_url = preg_replace( '#^https?://#', '', $this->upload_dir['baseurl'] );
148
149
        // add protocol to the upload url.
150 1
        $this->upload_url = $protocol . $this->upload_url;
151
152
        // post type filter added by user.
153 1
        $this->user_filter = array();
154
155 1
        global $wpdb;
156 1
        $this->db = $wpdb;
157 1
    }
158
159
    public function dismiss_admin_notice()
160
    {
161
        if ( ! isset($_GET['mo-adaction']) || $_GET['mo-adaction'] != 'mo_dismiss_adnotice') {
162
            return;
163
        }
164
165
        $url = admin_url();
166
        update_option('mo_dismiss_adnotice', 'true');
167
168
        wp_redirect($url);
169
        exit;
170
    }
171
172
    public function admin_notice()
173
    {
174
        if (get_option('mo_dismiss_adnotice', 'false') == 'true') {
175
            return;
176
        }
177
178
        if ($this->is_plugin_installed() && $this->is_plugin_active()) {
179
            return;
180
        }
181
182
        $dismiss_url = esc_url_raw(
183
            add_query_arg(
184
                array(
185
                    'mo-adaction' => 'mo_dismiss_adnotice'
186
                ),
187
                admin_url()
188
            )
189
        );
190
        $this->notice_css();
0 ignored issues
show
Unused Code introduced by
The call to the method Dynamic_Featured_Image::notice_css() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
191
        $install_url = wp_nonce_url(
192
            admin_url('update.php?action=install-plugin&plugin=mailoptin'),
193
            'install-plugin_mailoptin'
194
        );
195
196
        $activate_url = wp_nonce_url(admin_url('plugins.php?action=activate&plugin=mailoptin%2Fmailoptin.php'), 'activate-plugin_mailoptin/mailoptin.php');
197
        ?>
198
        <div class="mo-admin-notice notice notice-success">
199
            <div class="mo-notice-first-half">
200
                <p>
201
                    <?php
202
                    printf(
203
                        __('Free optin form plugin that will %1$sincrease your email list subscribers%2$s and keep them engaged with %1$sautomated and schedule newsletters%2$s.'),
204
                        '<span class="mo-stylize"><strong>', '</strong></span>');
205
                    ?>
206
                </p>
207
                <p style="text-decoration: underline;font-size: 12px;">Recommended by Dynamic Featured Image plugin</p>
208
            </div>
209
            <div class="mo-notice-other-half">
210
                <?php if ( ! $this->is_plugin_installed()) : ?>
211
                    <a class="button button-primary button-hero" id="mo-install-mailoptin-plugin" href="<?php echo $install_url; ?>">
212
                        <?php _e('Install MailOptin Now for Free!'); ?>
213
                    </a>
214
                <?php endif; ?>
215
                <?php if ($this->is_plugin_installed() && ! $this->is_plugin_active()) : ?>
216
                    <a class="button button-primary button-hero" id="mo-activate-mailoptin-plugin" href="<?php echo $activate_url; ?>">
217
                        <?php _e('Activate MailOptin Now!'); ?>
218
                    </a>
219
                <?php endif; ?>
220
                <div class="mo-notice-learn-more">
221
                    <a target="_blank" href="https://mailoptin.io">Learn more</a>
222
                </div>
223
            </div>
224
            <a href="<?php echo $dismiss_url; ?>">
225
                <button type="button" class="notice-dismiss">
226
                    <span class="screen-reader-text"><?php _e('Dismiss this notice'); ?>.</span>
227
                </button>
228
            </a>
229
        </div>
230
        <?php
231
    }
232
233
    public function is_plugin_installed()
234
    {
235
        $installed_plugins = get_plugins();
236
237
        return isset($installed_plugins['mailoptin/mailoptin.php']);
238
    }
239
240
    public function is_plugin_active()
241
    {
242
        return is_plugin_active('mailoptin/mailoptin.php');
243
    }
244
245
    public function notice_css()
246
    {
247
        ?>
248
        <style type="text/css">
249
            .mo-admin-notice {
250
                background: #fff;
251
                color: #000;
252
                border-left-color: #46b450;
253
                position: relative;
254
            }
255
256
            .mo-admin-notice .notice-dismiss:before {
257
                color: #72777c;
258
            }
259
260
            .mo-admin-notice .mo-stylize {
261
                line-height: 2;
262
            }
263
264
            .mo-admin-notice .button-primary {
265
                background: #006799;
266
                text-shadow: none;
267
                border: 0;
268
                box-shadow: none;
269
            }
270
271
            .mo-notice-first-half {
272
                width: 66%;
273
                display: inline-block;
274
                margin: 10px 0;
275
            }
276
277
            .mo-notice-other-half {
278
                width: 33%;
279
                display: inline-block;
280
                padding: 20px 0;
281
                position: absolute;
282
                text-align: center;
283
            }
284
285
            .mo-notice-first-half p {
286
                font-size: 14px;
287
            }
288
289
            .mo-notice-learn-more a {
290
                margin: 10px;
291
            }
292
293
            .mo-notice-learn-more {
294
                margin-top: 10px;
295
            }
296
        </style>
297
        <?php
298
    }
299
300
    /**
301
     * Return site protocol.
302
     *
303
     * @since 3.5.1
304
     * @access public
305
     *
306
     * @return string
307
     */
308
    private function get_protocol() {
309
        return is_ssl() ? 'https://' : 'http://';
310
    }
311
312
    /**
313
     * Add required admin scripts.
314
     *
315
     * @since 1.0.0
316
     * @access public
317
     *
318
     * @see  wp_enqueue_style()
319
     * @see  wp_register_script()
320
     * @see  wp_enqueue_script()
321
     *
322
     * @return void
323
     */
324 1
    public function enqueue_admin_scripts() {
325
        // enqueue styles.
326 1
        wp_enqueue_style( 'style-dfi', plugins_url( '/css/style-dfi.css', __FILE__ ), array(), self::VERSION );
327
328
        // register script.
329 1
        wp_register_script( 'scripts-dfi', plugins_url( '/js/script-dfi.js', __FILE__ ), array( 'jquery' ), self::VERSION );
330
331
        // localize the script with required data.
332 1
        wp_localize_script(
333 1
            'scripts-dfi',
334 1
            'DFI_SPECIFIC',
335
            array(
336 1
                'upload_url'               => $this->upload_url,
337 1
                'metabox_title'            => __( $this->metabox_title, self::TEXT_DOMAIN ),
338 1
                'mediaSelector_title'      => __( 'Dynamic Featured Image - Media Selector', self::TEXT_DOMAIN ),
339 1
                'mediaSelector_buttonText' => __( 'Set Featured Image', self::TEXT_DOMAIN ),
340 1
                'ajax_nonce'               => wp_create_nonce( plugin_basename( __FILE__ ) ),
341
            )
342 1
        );
343
344
        // enqueue scripts.
345 1
        wp_enqueue_script( 'scripts-dfi' );
346 1
    }
347
348
    /**
349
     * Add upgrade link.
350
     *
351
     * @access public
352
     * @since  3.5.1
353
     * @action plugin_action_links
354
     *
355
     * @codeCoverageIgnore
356
     *
357
     * @param  array $links Action links.
358
     *
359
     * @return array
360
     */
361
    public function dfi_action_links( $links ) {
362
        $upgrade_link = array(
363
            '<a href="' . self::UPGRADE_LINK . '" target="_blank">Upgrade to Premium</a>'
364
        );
365
366
        return array_merge( $links, $upgrade_link );
367
    }
368
369
    /**
370
     * Add featured meta boxes dynamically.
371
     *
372
     * @since 1.0.0
373
     * @access public
374
     * @global object $post
375
     *
376
     * @see  get_post_meta()
377
     * @see  get_post_types()
378
     * @see  add_meta_box()
379
     * @see  add_filter()
380
     *
381
     * @return void
382
     */
383
    public function initialize_featured_box() {
384
        global $post;
385
386
        // make metabox title dynamic.
387
        $this->metabox_title = apply_filters( 'dfi_set_metabox_title', __( 'Featured Image', self::TEXT_DOMAIN ) );
388
389
        $featured_data  = get_post_meta( $post->ID, 'dfiFeatured', true );
390
        $total_featured = is_array( $featured_data ) ? count( $featured_data ) : 0;
391
392
        $default_filter    = array( 'attachment', 'revision', 'nav_menu_item' );
393
        $this->user_filter = apply_filters( 'dfi_post_type_user_filter', $this->user_filter );
394
395
        $post_types = array_diff( get_post_types(), array_merge( $default_filter, $this->user_filter ) );
396
        $post_types = apply_filters( 'dfi_post_types', $post_types );
397
398
        if ( ! empty( $featured_data ) && $total_featured >= 1 ) {
399
            $i = 2;
400
            foreach ( $featured_data as $featured ) {
401
                $this->dfi_add_meta_box( $post_types, $featured, $i++ );
402
            }
403
        } else {
404
            $this->dfi_add_meta_box( $post_types );
405
        }
406
    }
407
408
    /**
409
     * Translates more than one digit number digit by digit.
410
     *
411
     * @param  int $number Integer to be translated.
412
     *
413
     * @return string Translated number
414
     */
415 2
    protected function get_number_translation( $number ) {
416 2
        if ( $number <= 9 ) {
417 1
            return __( $number, self::TEXT_DOMAIN );
418
        } else {
419 1
            $pieces = str_split( $number, 1 );
420 1
            $buffer = '';
421 1
            foreach ( $pieces as $piece ) {
422 1
                $buffer .= __( $piece, self::TEXT_DOMAIN );
423 1
            }
424
425 1
            return $buffer;
426
        }
427
    }
428
429
    /**
430
     * Adds meta boxes.
431
     *
432
     * @param  array  $post_types Post types to show featured image box.
433
     * @param  object $featured Callback arguments.
434
     * @param  int    $i Index of the featured image.
435
     *
436
     * @return void
437
     */
438
    private function dfi_add_meta_box( $post_types, $featured = null, $i = null ) {
439
        if ( ! is_null( $i ) ) {
440
            foreach ( $post_types as $type ) {
441
                add_meta_box(
442
                    'dfiFeaturedMetaBox-' . $i,
443
                    __( $this->metabox_title, self::TEXT_DOMAIN ) . ' ' . $this->get_number_translation( $i ),
444
                    array( $this, 'featured_meta_box' ),
445
                    $type,
446
                    apply_filters( 'dfi_metabox_context', 'side' ),
447
                    apply_filters( 'dfi_metabox_priority', 'low' ),
448
                    array( $featured, $i + 1 )
449
                );
450
451
                add_filter( "postbox_classes_{$type}_dfiFeaturedMetaBox-" . $i, array( $this, 'add_metabox_classes' ) );
452
            }
453
        } else {
454
            foreach ( $post_types as $type ) {
455
                add_meta_box(
456
                    'dfiFeaturedMetaBox',
457
                    __( $this->metabox_title, self::TEXT_DOMAIN ) . ' ' . __( 2, self::TEXT_DOMAIN ),
458
                    array( $this, 'featured_meta_box' ),
459
                    $type,
460
                    apply_filters( 'dfi_metabox_context', 'side' ),
461
                    apply_filters( 'dfi_metabox_priority', 'low' ),
462
                    array( null, null )
463
                );
464
465
                add_filter( "postbox_classes_{$type}_dfiFeaturedMetaBox", array( $this, 'add_metabox_classes' ) );
466
            }
467
        }
468
    }
469
470
    /**
471
     * Separate thumb and full image url from given URL string.
472
     *
473
     * @since  3.3.1
474
     *
475
     * @param  string $url_string Url string.
476
     * @param  string $state Thumb or full.
477
     *
478
     * @return string|null
479
     */
480 3
    private function separate( $url_string, $state = 'thumb' ) {
481 3
        $image_piece = explode( ',', $url_string );
482
483 3
        if ( 'thumb' === $state ) {
484 2
            return isset( $image_piece[0] ) ? $image_piece[0] : null;
485
        }
486
487 3
        return isset( $image_piece[1] ) ? $image_piece[1] : null;
488
    }
489
490
    /**
491
     * Create a nonce field.
492
     *
493
     * @since  3.5.0
494
     *
495
     * @see  wp_nonce_field()
496
     * @see  plugin_basename()
497
     *
498
     * @codeCoverageIgnore
499
     *
500
     * @param  string $key Nonce key.
501
     *
502
     * @return string
503
     */
504
    protected function nonce_field( $key ) {
505
        return wp_nonce_field( plugin_basename( __FILE__ ), $key, true, false );
506
    }
507
508
    /**
509
     * Featured meta box as seen in the admin.
510
     *
511
     * @since 1.0.0
512
     * @access public
513
     *
514
     * @param  object $post Global post object.
515
     * @param  array  $featured Array containing featured image count.
516
     *
517
     * @throws Exception Medium size image not found.
518
     * @return void
519
     */
520 2
    public function featured_meta_box( $post, $featured ) {
521 2
        $featured_img         = $featured['args'][0];
522 2
        $featured_id          = is_null( $featured['args'][1] ) ? 2 : --$featured['args'][1];
523 2
        $featured_img_full    = $featured_img;
524 2
        $featured_img_trimmed = $featured_img;
525
526 2
        if ( ! is_null( $featured_img ) ) {
527 2
            $featured_img_trimmed = $this->separate( $featured_img );
528 2
            $featured_img_full    = $this->separate( $featured_img, 'full' );
529 2
        }
530
531 2
        $thumbnail = $this->get_image_thumb( $this->upload_url . $featured_img_full, 'medium' );
532 2
        if ( empty( $thumbnail ) ) {
533
            // since medium sized thumbnail image is missing,
534
            // let's set full image url as thumbnail.
535 2
            $thumbnail = $featured_img_full;
536 2
        }
537
538
        // Add a nonce field.
539 2
        echo $this->nonce_field( 'dfi_fimageplug-' . $featured_id ); // WPCS: XSS ok.
540 2
        echo $this->get_featured_box( $featured_img_trimmed, $featured_img, $featured_id, $thumbnail, $post->ID ); // WPCS: XSS ok.
541 2
    }
542
543
    /**
544
     * Returns featured box html content.
545
     *
546
     * @since  3.1.0
547
     * @access private
548
     *
549
     * @param string $featured_img_trimmed Medium sized image.
550
     * @param string $featured_img Full sized image.
551
     * @param string $featured_id Attachment Id.
552
     * @param string $thumbnail Thumb sized image.
553
     * @param int    $post_id Post id.
554
     *
555
     * @return string Html content
556
     */
557 2
    private function get_featured_box( $featured_img_trimmed, $featured_img, $featured_id, $thumbnail, $post_id ) {
558 2
        $has_featured_image = ! empty( $featured_img_trimmed ) ? 'hasFeaturedImage' : '';
559 2
        $thumbnail          = ! is_null( $thumbnail ) ? $thumbnail : '';
560 2
        $dfi_empty          = is_null( $featured_img_trimmed ) ? 'dfiImgEmpty' : '';
561
562 2
        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/>
563 2
            <img src='" . $thumbnail . "' class='dfiImg {$dfi_empty}'/>
564
            <div class='dfiLinks'>
565 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>
566 2
                <a href='javascript:void(0)' class='dfiRemove dashicons dashicons-minus' title='" . __( 'Remove', self::TEXT_DOMAIN ) . "'></a>
567
            </div>
568
            <div class='dfiClearFloat'></div>
569 2
            <input type='hidden' name='dfiFeatured[]' value='{$featured_img}'  class='dfiImageHolder' />";
570
    }
571
572
    /**
573
     * Load new featured meta box via ajax.
574
     *
575
     * @since 1.0.0
576
     * @access public
577
     *
578
     * @return void
579
     */
580 2
    public function ajax_callback() {
581 2
        check_ajax_referer( plugin_basename( __FILE__ ), 'security' );
582
583 1
        $featured_id = isset( $_POST['id'] ) ? intval( wp_unslash( $_POST['id'] ) ) : null;
584
585 1
        if ( ! is_numeric( $featured_id ) ) {
586
            return;
587
        }
588
589
        // @codingStandardsIgnoreStart
590 1
        echo $this->nonce_field( 'dfi_fimageplug-' . $featured_id );
591
        ?>
592
        <a href="javascript:void(0)" class="dfiFeaturedImage"
593
           title="<?php echo __( 'Set Featured Image', self::TEXT_DOMAIN ) ?>"><span
594
                    class="dashicons dashicons-camera"></span></a><br/>
595
        <img src="" class="dfiImg dfiImgEmpty"/>
596
        <div class="dfiLinks">
597
            <a href="javascript:void(0)" data-id="<?php echo $featured_id ?>"
598
               data-id-local="<?php echo $this->get_number_translation( $featured_id + 1 ) ?>"
599
               class="dfiAddNew dashicons dashicons-plus" title="<?php echo __( 'Add New', self::TEXT_DOMAIN ) ?>"></a>
600
            <a href="javascript:void(0)" class="dfiRemove dashicons dashicons-minus"
601
               title="<?php echo __( 'Remove', self::TEXT_DOMAIN ) ?>"></a>
602
        </div>
603
        <div class="dfiClearFloat"></div>
604
        <input type="hidden" name="dfiFeatured[]" value="" class="dfiImageHolder"/>
605
        <?php
606
        // @codingStandardsIgnoreEnd
607 1
        wp_die( '' );
608
    }
609
610
    /**
611
     * Add custom class 'featured-meta-box' to meta box.
612
     *
613
     * @since 1.0.0
614
     * @access public
615
     *
616
     * @see  add_metabox_classes
617
     *
618
     * @param array $classes Classes to add in the meta box.
619
     *
620
     * @return array
621
     */
622 1
    public function add_metabox_classes( $classes ) {
623 1
        array_push( $classes, 'featured-meta-box' );
624
625 1
        return $classes;
626
    }
627
628
    /**
629
     * Add custom fields in media uploader.
630
     *
631
     * @since  3.4.0
632
     *
633
     * @param array $form_fields Fields to include in media attachment form.
634
     * @param array $post Post data.
635
     *
636
     * @return array
637
     */
638 1
    public function media_attachment_custom_fields( $form_fields, $post ) {
639 1
        $form_fields['dfi-link-to-image'] = array(
640 1
            'label' => __( 'Link to Image', self::TEXT_DOMAIN ),
641 1
            'input' => 'text',
642 1
            'value' => get_post_meta( $post->ID, '_dfi_link_to_image', true ),
643
        );
644
645 1
        return $form_fields;
646
    }
647
648
    /**
649
     * Save values of media uploader custom fields.
650
     *
651
     * @since 3.4.0
652
     *
653
     * @param array $post Post data for database.
654
     * @param array $attachment Attachment fields from $_POST form.
655
     *
656
     * @return array
657
     */
658 1
    public function media_attachment_custom_fields_save( $post, $attachment ) {
659 1
        if ( isset( $attachment['dfi-link-to-image'] ) ) {
660 1
            update_post_meta( $post['ID'], '_dfi_link_to_image', $attachment['dfi-link-to-image'] );
661 1
        }
662
663 1
        return $post;
664
    }
665
666
    /**
667
     * Update featured images in the database.
668
     *
669
     * @since 1.0.0
670
     * @access public
671
     *
672
     * @see  plugin_basename()
673
     * @see  update_post_meta()
674
     * @see  current_user_can()
675
     *
676
     * @param  int $post_id Current post id.
677
     *
678
     * @return bool|null
679
     */
680 2
    public function save_meta( $post_id ) {
681
        // Check auto save.
682 2
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
683 1
            return false;
684
        }
685
686 2
        if ( ! $this->verify_nonces() ) {
687 2
            return false;
688
        }
689
690
        // Check permission before saving data.
691 1
        if ( current_user_can( 'edit_posts', $post_id ) && isset( $_POST['dfiFeatured'] ) ) { // WPCS: CSRF ok.
692 1
            $featured_images = is_array( $_POST['dfiFeatured'] ) ? $_POST['dfiFeatured'] : array(); // WPCS: sanitization ok, CSRF ok.
693
694 1
            update_post_meta( $post_id, 'dfiFeatured', $this->sanitize_array( $featured_images ) );
695 1
        }
696 1
    }
697
698
    /**
699
     * Sanitize array.
700
     *
701
     * @since 3.6.0
702
     * @access protected
703
     *
704
     * @param array $input_array Input array.
705
     *
706
     * @return array
707
     */
708 1
    protected function sanitize_array( $input_array ) {
709 1
        $sanitized = array();
710
711 1
        foreach ( $input_array as $value ) {
712 1
            $sanitized[] = sanitize_text_field( wp_unslash( $value ) );
713 1
        }
714
715 1
        return $sanitized;
716
    }
717
718
    /**
719
     * Verify metabox nonces.
720
     *
721
     * @access protected
722
     * @see  wp_verify_nonce()
723
     *
724
     * @return bool
725
     */
726
    protected function verify_nonces() {
727
        $keys = preg_grep( '/dfi_fimageplug-\d+$/', array_keys( $_POST ) ); // WPCS: CSRF ok.
728
729
        if ( empty( $keys ) ) {
730
            return false;
731
        }
732
733
        foreach ( $keys as $key ) {
734
            // Verify nonce.
735
            if ( ! isset( $_POST[ $key ] ) ||
736
                 ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ $key ] ) ), plugin_basename( __FILE__ ) )
737
            ) {
738
                return false;
739
            }
740
        }
741
742
        return true;
743
    }
744
745
    /**
746
     * Add update notice. Displayed in plugin update page.
747
     *
748
     * @since 2.0.0
749
     * @access public
750
     *
751
     * @return void
752
     */
753 1
    public function update_notice() {
754 1
        $info = __( 'ATTENTION! Please read the <a href="' . self::WIKI_LINK . '" target="_blank">DOCUMENTATION</a> properly before update.',
755 1
        self::TEXT_DOMAIN );
756
757 1
        echo '<span style="color: red; padding: 7px 0; display: block">' . strip_tags( $info, '<a><b><i><span>' ) . '</span>'; // WPCS: XSS ok.
758 1
    }
759
760
    /**
761
     * Execute query.
762
     *
763
     * @param string $query Query to execute.
764
     *
765
     * @return null|string
766
     */
767 6
    private function execute_query( $query ) {
768 6
        return $this->db->get_var( $query );
769
    }
770
771
    /**
772
     * Get attachment id of the image by image url.
773
     *
774
     * @since 3.1.7
775
     * @access protected
776
     * @global object $wpdb
777
     *
778
     * @param  string $image_url URL of an image.
779
     *
780
     * @return string
781
     */
782 1
    protected function get_attachment_id( $image_url ) {
783 1
        return $this->execute_query( $this->db->prepare( 'SELECT ID FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
784
    }
785
786
    /**
787
     * Get image url of the image by attachment id.
788
     *
789
     * @since 2.0.0
790
     * @access public
791
     *
792
     * @see  wp_get_attachment_image_src()
793
     *
794
     * @param  int    $attachment_id attachment id of an image.
795
     * @param  string $size size of the image to fetch (thumbnail, medium, full).
796
     *
797
     * @return string
798
     */
799 1
    public function get_image_url( $attachment_id, $size = 'full' ) {
800 1
        $image_thumb = wp_get_attachment_image_src( $attachment_id, $size );
801
802 1
        return empty( $image_thumb ) ? null : $image_thumb[0];
803
    }
804
805
    /**
806
     * Get image thumbnail url of specific size by image url.
807
     *
808
     * @since 2.0.0
809
     * @access public
810
     *
811
     * @see  get_image_id()
812
     * @see  wp_get_attachment_image_src()
813
     *
814
     * @param  string $image_url url of an image.
815
     * @param  string $size size of the image to fetch (thumbnail, medium, full).
816
     *
817
     * @return string
818
     */
819 3
    public function get_image_thumb( $image_url, $size = 'thumbnail' ) {
820 3
        $attachment_id = $this->get_image_id( $image_url );
821 3
        $image_thumb   = wp_get_attachment_image_src( $attachment_id, $size );
822
823 3
        return empty( $image_thumb ) ? null : $image_thumb[0];
824
    }
825
826
    /**
827
     * Gets attachment id from given image url.
828
     *
829
     * @param  string $image_url url of an image.
830
     *
831
     * @since  2.0.0
832
     * @access public
833
     *
834
     * @return int|null attachment id of an image
835
     */
836 5
    public function get_image_id( $image_url ) {
837 5
        $attachment_id = $this->get_attachment_id( $image_url );
838
839 5
        if ( is_null( $attachment_id ) ) {
840
            // check if the image is edited image.
841
            // and try to get the attachment id.
842 4
            $image_url = str_replace( $this->upload_url . '/', '', $image_url );
843 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 ) );
844
845 4
            if ( ! is_null( $row ) ) {
846 1
                $attachment_id = $row;
847 1
            }
848 4
        }
849
850 5
        return $attachment_id;
851
    }
852
853
    /**
854
     * Get image title.
855
     *
856
     * @since 2.0.0
857
     * @access public
858
     *
859
     * @param string $image_url URL of an image.
860
     *
861
     * @return string
862
     */
863 1
    public function get_image_title( $image_url ) {
864 1
        return $this->execute_query( $this->db->prepare( 'SELECT post_title FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
865
    }
866
867
    /**
868
     * Get image title by id.
869
     *
870
     * @since 2.0.0
871
     * @access public
872
     *
873
     * @param  int $attachment_id Attachment id of an image.
874
     *
875
     * @return string
876
     */
877 1
    public function get_image_title_by_id( $attachment_id ) {
878 1
        return $this->execute_query( $this->db->prepare( 'SELECT post_title FROM ' . $this->db->posts . ' WHERE ID = %d', $attachment_id ) );
879
    }
880
881
    /**
882
     * Get image caption.
883
     *
884
     * @since 2.0.0
885
     * @access public
886
     *
887
     * @param  string $image_url URL of an image.
888
     *
889
     * @return string
890
     */
891 1
    public function get_image_caption( $image_url ) {
892 1
        return $this->execute_query( $this->db->prepare( 'SELECT post_excerpt FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
893
    }
894
895
    /**
896
     * Get image caption by id.
897
     *
898
     * @since 2.0.0
899
     * @access public
900
     *
901
     * @param  int $attachment_id Attachment id of an image.
902
     *
903
     * @return string
904
     */
905 1
    public function get_image_caption_by_id( $attachment_id ) {
906 1
        return $this->execute_query( $this->db->prepare( 'SELECT post_excerpt FROM ' . $this->db->posts . ' WHERE ID = %d', $attachment_id ) );
907
    }
908
909
    /**
910
     * Get image alternate text.
911
     *
912
     * @since 2.0.0
913
     * @access public
914
     *
915
     * @see  get_post_meta()
916
     *
917
     * @param  string $image_url URL of an image.
918
     *
919
     * @return string
920
     */
921 1
    public function get_image_alt( $image_url ) {
922 1
        $attachment = $this->db->get_col( $this->db->prepare( 'SELECT ID FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
923
924 1
        $alt = null;
925 1
        if ( ! empty( $attachment ) ) {
926 1
            $alt = get_post_meta( $attachment[0], '_wp_attachment_image_alt' );
927 1
        }
928
929 1
        return ( is_null( $alt ) || empty( $alt ) ) ? null : $alt[0];
930
    }
931
932
    /**
933
     * Get image alternate text by attachment id.
934
     *
935
     * @since 2.0.0
936
     * @access public
937
     *
938
     * @see  get_post_meta()
939
     *
940
     * @param  int $attachment_id Attachment id of an image.
941
     *
942
     * @return string
943
     */
944 1
    public function get_image_alt_by_id( $attachment_id ) {
945 1
        $alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt' );
946
947 1
        return empty( $alt ) ? null : $alt[0];
948
    }
949
950
    /**
951
     * Get image description.
952
     *
953
     * @since 3.0.0
954
     * @access public
955
     *
956
     * @param  string $image_url URL of an image.
957
     *
958
     * @return string
959
     */
960 1
    public function get_image_description( $image_url ) {
961 1
        return $this->execute_query( $this->db->prepare( 'SELECT post_content FROM ' . $this->db->posts . ' WHERE guid = %s', $image_url ) );
962
    }
963
964
    /**
965
     * Get image description by id.
966
     *
967
     * @since 3.0.0
968
     * @access public
969
     *
970
     * @param  int $attachment_id attachment id of an image.
971
     *
972
     * @return string
973
     */
974 1
    public function get_image_description_by_id( $attachment_id ) {
975 1
        return $this->execute_query( $this->db->prepare( 'SELECT post_content FROM ' . $this->db->posts . ' WHERE ID = %d', $attachment_id ) );
976
    }
977
978
    /**
979
     * Get link to image.
980
     *
981
     * @since 3.4.0
982
     * @access public
983
     *
984
     * @param  int $attachment_id Attachment id of an image.
985
     *
986
     * @return string|null
987
     */
988 1
    public function get_link_to_image( $attachment_id ) {
989 1
        return get_post_meta( $attachment_id, '_dfi_link_to_image', true );
990
    }
991
992
    /**
993
     * Get all attachment ids of the post.
994
     *
995
     * @since 2.0.0
996
     * @access public
997
     *
998
     * @see  get_post_meta()
999
     *
1000
     * @param  int $post_id id of the current post.
1001
     *
1002
     * @return array
1003
     */
1004 2
    public function get_post_attachment_ids( $post_id ) {
1005 2
        $dfi_images = get_post_meta( $post_id, 'dfiFeatured', true );
1006 2
        $ret_val    = array();
1007
1008 2
        if ( ! empty( $dfi_images ) && is_array( $dfi_images ) ) {
1009 2
            foreach ( $dfi_images as $dfi_image ) {
1010 2
                $dfi_image_full = $this->separate( $dfi_image, 'full' );
1011 2
                $ret_val[]      = (int) $this->get_image_id( $this->upload_url . $dfi_image_full );
1012 2
            }
1013 2
        }
1014
1015 2
        return $ret_val;
1016
    }
1017
1018
    /**
1019
     * Get real post id.
1020
     *
1021
     * @since 3.6.0
1022
     * @access protected
1023
     *
1024
     * @param int|null $post_id Post id.
1025
     *
1026
     * @return int|null
1027
     */
1028 6
    protected function get_real_post_id( $post_id = null ) {
1029 6
        if ( ! is_null( $post_id ) && is_numeric( $post_id ) ) {
1030 5
            return $post_id;
1031
        }
1032
1033 3
        global $post;
1034
1035 3
        return $post->ID;
1036
    }
1037
1038
    /**
1039
     * Fetches featured image data of nth position.
1040
     *
1041
     * @since  3.0.0
1042
     * @access  public
1043
     *
1044
     * @see  get_featured_images()
1045
     *
1046
     * @param  int $position Position of the featured image.
1047
     * @param  int $post_id Current post id.
1048
     *
1049
     * @return array if found, null otherwise.
1050
     */
1051 2
    public function get_nth_featured_image( $position, $post_id = null ) {
1052 2
        $post_id = $this->get_real_post_id( ( $post_id ) );
1053
1054 2
        $featured_images = $this->get_featured_images( $post_id );
1055
1056 2
        return isset( $featured_images[ $position - 2 ] ) ? $featured_images[ $position - 2 ] : null;
1057
    }
1058
1059
    /**
1060
     * Check if the image is attached with the particular post.
1061
     *
1062
     * @since 2.0.0
1063
     * @access public
1064
     *
1065
     * @see  get_post_attachment_ids()
1066
     *
1067
     * @param  int $attachment_id Attachment id of an image.
1068
     * @param  int $post_id Current post id.
1069
     *
1070
     * @return bool
1071
     */
1072 1
    public function is_attached( $attachment_id, $post_id ) {
1073 1
        if ( empty( $attachment_id ) ) {
1074 1
            return false;
1075
        }
1076
1077 1
        $attachment_ids = $this->get_post_attachment_ids( $post_id );
1078
1079 1
        return in_array( $attachment_id, $attachment_ids, true ) ? true : false;
1080
    }
1081
1082
    /**
1083
     * Retrieve featured images for specific post(s).
1084
     *
1085
     * @since 2.0.0
1086
     * @access public
1087
     *
1088
     * @see get_post_meta()
1089
     *
1090
     * @param  int $post_id id of the current post.
1091
     *
1092
     * @return array
1093
     */
1094 7
    public function get_featured_images( $post_id = null ) {
1095 7
        $post_id    = $this->get_real_post_id( $post_id );
1096 7
        $dfi_images = get_post_meta( $post_id, 'dfiFeatured', true );
1097 7
        $ret_images = array();
1098
1099 7
        if ( ! empty( $dfi_images ) && is_array( $dfi_images ) ) {
1100 7
            $dfi_images = array_filter( $dfi_images );
1101
1102 7
            $count = 0;
1103 7
            foreach ( $dfi_images as $dfi_image ) {
1104 7
                $dfi_image_trimmed = $this->separate( $dfi_image );
1105 7
                $dfi_image_full    = $this->separate( $dfi_image, 'full' );
1106
1107
                try {
1108 7
                    $ret_images[ $count ]['thumb']         = $this->get_real_upload_path( $dfi_image_trimmed );
1109 7
                    $ret_images[ $count ]['full']          = $this->get_real_upload_path( $dfi_image_full );
1110 7
                    $ret_images[ $count ]['attachment_id'] = $this->get_image_id( $ret_images[ $count ]['full'] );
1111 7
                } catch ( Exception $e ) {
1112
                    /* Ignore the exception and continue with other featured images */
1113
                }
1114
1115 7
                $count ++;
1116 7
            }
1117 7
        }
1118
1119 7
        return $ret_images;
1120
    }
1121
1122
    /**
1123
     * Check to see if the upload url is already available in path.
1124
     *
1125
     * @since  3.1.14
1126
     * @access protected
1127
     *
1128
     * @param  string $img Uploaded image.
1129
     *
1130
     * @return string
1131
     */
1132 2
    protected function get_real_upload_path( $img ) {
1133
        // check if upload path is already attached.
1134 2
        if ( false !== strpos( $img, $this->upload_url ) || preg_match( '/https?:\/\//', $img ) ) {
1135 2
            return $img;
1136
        }
1137
1138 2
        return $this->upload_url . $img;
1139
    }
1140
1141
    /**
1142
     * Retrieve featured images for specific post(s) including the default Featured Image.
1143
     *
1144
     * @since 3.1.7
1145
     * @access public
1146
     *
1147
     * @see  $this->get_featured_images()
1148
     *
1149
     * @param int $post_id Current post id.
1150
     *
1151
     * @return array An array of images or an empty array on failure
1152
     */
1153 2
    public function get_all_featured_images( $post_id = null ) {
1154 2
        $post_id      = $this->get_real_post_id( $post_id );
1155 2
        $thumbnail_id = get_post_thumbnail_id( $post_id );
1156 2
        $all_images   = array();
1157
1158 2
        if ( ! empty( $thumbnail_id ) ) {
1159
            $featured_image         = array(
1160 2
                'thumb'         => wp_get_attachment_thumb_url( $thumbnail_id ),
1161 2
                'full'          => wp_get_attachment_url( $thumbnail_id ),
1162 2
                'attachment_id' => $thumbnail_id,
1163 2
            );
1164
1165 2
            $all_images[] = $featured_image;
1166 2
        }
1167
1168 2
        return array_merge( $all_images, $this->get_featured_images( $post_id ) );
1169
    }
1170
1171
    /**
1172
     * Load the plugin's textdomain hooked to 'plugins_loaded'.
1173
     *
1174
     * @since 1.0.0
1175
     * @access public
1176
     *
1177
     * @see    load_plugin_textdomain()
1178
     * @see    plugin_basename()
1179
     * @action plugins_loaded
1180
     *
1181
     * @codeCoverageIgnore
1182
     *
1183
     * @return void
1184
     */
1185
    public function load_plugin_textdomain() {
1186
        load_plugin_textdomain(
1187
            self::TEXT_DOMAIN,
1188
            false,
1189
            dirname( plugin_basename( __FILE__ ) ) . '/languages/'
1190
        );
1191
    }
1192
}
1193
1194
/**
1195
 * Instantiate the main class.
1196
 *
1197
 * @since 1.0.0
1198
 * @access public
1199
 *
1200
 * @var object $dynamic_featured_image holds the instantiated class {@uses Dynamic_Featured_Image}
1201
 */
1202
global $dynamic_featured_image;
1203
$dynamic_featured_image = new Dynamic_Featured_Image();
1204