Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
26.00% covered (danger)
26.00%
78 / 300
25.00% covered (danger)
25.00%
7 / 28
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_Likes_Settings
26.00% covered (danger)
26.00%
78 / 300
25.00% covered (danger)
25.00%
7 / 28
6662.86
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 add_likes_to_sharing_meta_box_title
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 add_meta_box
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 meta_box_content
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
42
 is_enabled_sitewide
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 meta_box_save
13.64% covered (danger)
13.64%
3 / 22
0.00% covered (danger)
0.00%
0 / 1
277.66
 sharing_meta_box_content
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 needs_own_sharing_menu
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 sharing_menu
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 sharing_page
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 updated_message
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
12
 sharing_block
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 is_post_likeable
78.57% covered (warning)
78.57%
11 / 14
0.00% covered (danger)
0.00%
0 / 1
9.80
 is_likes_button_visible
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
3.33
 is_likes_visible
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 is_likes_module_enabled
74.07% covered (warning)
74.07%
20 / 27
0.00% covered (danger)
0.00%
0 / 1
22.04
 is_single_post_enabled
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 get_options
71.05% covered (warning)
71.05%
27 / 38
0.00% covered (danger)
0.00%
0 / 1
12.43
 is_index_enabled
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 is_single_page_enabled
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 is_attachment_enabled
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 admin_settings_init
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 1
12
 reblogs_enabled_sitewide
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 is_comments_enabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 admin_settings_callback
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
272
 process_update_requests_if_sharedaddy_not_loaded
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
42
 admin_settings_showbuttonon_init
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 admin_settings_showbuttonon_callback
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
72
1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3use Automattic\Jetpack\Status\Host;
4use Automattic\Jetpack\Sync\Settings;
5
6/**
7 * Jetpack likes settings class.
8 */
9class Jetpack_Likes_Settings {
10
11    /**
12     * Determines whether the module runs in the Jetpack plugin, as opposed to WP.com Simple site environment
13     *
14     * @var bool
15     */
16    public $in_jetpack = true;
17
18    /**
19     * Constructor function.
20     */
21    public function __construct() {
22        $this->in_jetpack = ! ( new Host() )->is_wpcom_simple();
23    }
24
25    /**
26     * Replaces the "Sharing" title for the post screen metabox with "Likes and Shares"
27     */
28    public function add_likes_to_sharing_meta_box_title() {
29        return __( 'Likes and Shares', 'jetpack' );
30    }
31
32    /**
33     * Adds a metabox to the post screen if the sharing one doesn't currently exist.
34     */
35    public function add_meta_box() {
36        if (
37            /**
38             * Allow disabling of the Likes metabox on the post editor screen.
39             *
40             * @module likes
41             *
42             * @since 2.2.0
43             *
44             * @param bool false Should the Likes metabox be disabled? Default to false.
45             */
46        apply_filters( 'post_flair_disable', false )
47        ) {
48            return;
49        }
50
51        $post_types = get_post_types( array( 'public' => true ) );
52        /**
53         * Filters the Likes metabox title.
54         *
55         * @module likes
56         *
57         * @since 2.2.0
58         *
59         * @param string Likes metabox title. Default to "Likes".
60         */
61        $title = apply_filters( 'likes_meta_box_title', __( 'Likes', 'jetpack' ) );
62        foreach ( $post_types as $post_type ) {
63            add_meta_box( 'likes_meta', $title, array( $this, 'meta_box_content' ), $post_type, 'side', 'default', array( '__back_compat_meta_box' => true ) );
64        }
65    }
66
67    /**
68     * Shows the likes option in the post screen metabox.
69     *
70     * @param object $post - the post object.
71     */
72    public function meta_box_content( $post ) {
73        $post_id         = ! empty( $post->ID ) ? (int) $post->ID : get_the_ID();
74        $checked         = true;
75        $disabled        = ! $this->is_enabled_sitewide();
76        $switched_status = get_post_meta( $post_id, 'switch_like_status', true );
77
78        if ( $disabled && empty( $switched_status ) || ! $disabled && $switched_status === '0' ) {
79            $checked = false;
80        }
81
82        /**
83         * Fires before the Likes meta box content in the post editor.
84         *
85         * @module likes
86         *
87         * @since 2.2.0
88         *
89         * @param WP_Post|array|null $post Post data.
90         */
91        do_action( 'start_likes_meta_box_content', $post );
92        ?>
93
94        <p>
95            <label for="wpl_enable_post_likes">
96                <input type="checkbox" name="wpl_enable_post_likes" id="wpl_enable_post_likes" value="1" <?php checked( $checked ); ?>>
97                <?php esc_html_e( 'Show likes.', 'jetpack' ); ?>
98            </label>
99            <input type="hidden" name="wpl_like_status_hidden" value="1" />
100            <?php wp_nonce_field( 'likes-and-shares', '_likesharenonce' ); ?>
101        </p>
102        <?php
103        /**
104         * Fires after the Likes meta box content in the post editor.
105         *
106         * @module likes
107         *
108         * @since 2.2.0
109         *
110         * @param WP_Post|array|null $post Post data.
111         */
112        do_action( 'end_likes_meta_box_content', $post );
113    }
114
115    /**
116     * Returns the current state of the "WordPress.com Likes are" option.
117     *
118     * @return boolean true if enabled sitewide, false if not
119     */
120    public function is_enabled_sitewide() {
121        /**
122         * Filters whether Likes are enabled by default on all posts.
123         * true if enabled sitewide, false if not.
124         *
125         * @module likes
126         *
127         * @since 2.2.0
128         *
129         * @param bool $option Are Likes enabled sitewide.
130         */
131        return (bool) apply_filters( 'wpl_is_enabled_sitewide', ! Jetpack_Options::get_option_and_ensure_autoload( 'disabled_likes', 0 ) );
132    }
133
134    /**
135     * Handle meta box saving.
136     *
137     * @param int $post_id - the post ID.
138     */
139    public function meta_box_save( $post_id ) {
140        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
141            return $post_id;
142        }
143
144        if ( empty( $_POST['wpl_like_status_hidden'] ) ) {
145            return $post_id;
146        }
147
148        if ( ! isset( $_POST['_likesharenonce'] ) || ! wp_verify_nonce( $_POST['_likesharenonce'], 'likes-and-shares' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- WordPress core doesn't unslash or verify nonces either.
149            return $post_id;
150        }
151
152        // Record sharing disable. Only needs to be done for WPCOM.
153        if ( ! $this->in_jetpack ) {
154            if ( isset( $_POST['post_type'] ) && in_array( $_POST['post_type'], get_post_types( array( 'public' => true ) ), true ) ) {
155                if ( ! isset( $_POST['wpl_enable_post_sharing'] ) ) {
156                    update_post_meta( $post_id, 'sharing_disabled', 1 );
157                } else {
158                    delete_post_meta( $post_id, 'sharing_disabled' );
159                }
160            }
161        }
162
163        if ( 'post' === $_POST['post_type'] ) {
164            if ( ! current_user_can( 'edit_post', $post_id ) ) {
165                return $post_id;
166            }
167        }
168
169        // Record a change in like status for this post - only if it contradicts the
170        // site like setting. If it doesn't contradict, then we delete the new individual status.
171        if ( ! $this->is_enabled_sitewide() && ! empty( $_POST['wpl_enable_post_likes'] ) ) {
172            // Likes turned on for individual posts. User wants to add the button to a single post.
173            update_post_meta( $post_id, 'switch_like_status', 1 );
174        } elseif ( $this->is_enabled_sitewide() && empty( $_POST['wpl_enable_post_likes'] ) ) {
175            // Likes turned on for all posts. User wants to remove the button from a single post.
176            update_post_meta( $post_id, 'switch_like_status', 0 );
177        } elseif (
178        ( ! $this->is_enabled_sitewide() && empty( $_POST['wpl_enable_post_likes'] ) ) ||
179        ( $this->is_enabled_sitewide() && ! empty( $_POST['wpl_enable_post_likes'] ) )
180        ) {
181            // User wants to update the likes button status for an individual post, but the new status
182            // is the same as if they're asking for the default behavior according to the current Likes setting.
183            // So we delete the meta.
184            delete_post_meta( $post_id, 'switch_like_status' );
185        }
186
187        return $post_id;
188    }
189
190    /**
191     * WordPress.com: Metabox option for sharing (sharedaddy will handle this on the JP blog).
192     *
193     * @param object $post - the post object.
194     */
195    public function sharing_meta_box_content( $post ) {
196        $post_id  = ! empty( $post->ID ) ? (int) $post->ID : get_the_ID();
197        $disabled = get_post_meta( $post_id, 'sharing_disabled', true );
198        ?>
199        <p>
200            <label for="wpl_enable_post_sharing">
201                <input type="checkbox" name="wpl_enable_post_sharing" id="wpl_enable_post_sharing" value="1" <?php checked( ! $disabled ); ?>>
202                <?php esc_html_e( 'Show sharing buttons.', 'jetpack' ); ?>
203            </label>
204            <input type="hidden" name="wpl_sharing_status_hidden" value="1" />
205        </p>
206        <?php
207    }
208
209    /**
210     * Should we register the Settings > Sharing screen ourselves?
211     *
212     * Our settings are displayed on Settings > Sharing, but that screen is registered by
213     * the Sharing (sharedaddy) module. When that module is off, nothing registers the
214     * screen and our settings become unreachable.
215     *
216     * WordPress.com Simple sites are excluded: the screen is registered elsewhere there.
217     *
218     * @since 16.2
219     *
220     * @param bool $sharedaddy_active Whether the Sharing (sharedaddy) module is active.
221     * @return bool
222     */
223    public function needs_own_sharing_menu( $sharedaddy_active ) {
224        return ! $sharedaddy_active && $this->in_jetpack;
225    }
226
227    /**
228     * Adds the 'sharing' menu to the settings menu.
229     * Only ran when the Sharing (sharedaddy) module is inactive on a Jetpack site,
230     * since Settings > Sharing is where our settings live. See needs_own_sharing_menu().
231     */
232    public function sharing_menu() {
233        add_submenu_page( 'options-general.php', esc_html__( 'Sharing Settings', 'jetpack' ), esc_html__( 'Sharing', 'jetpack' ), 'manage_options', 'sharing', array( $this, 'sharing_page' ) );
234    }
235
236    /**
237     * Provides a sharing page with the sharing_global_options hook
238     * so we can display the setting.
239     * Only ran when the Sharing (sharedaddy) module is inactive on a Jetpack site,
240     * since Settings > Sharing is where our settings live. See needs_own_sharing_menu().
241     */
242    public function sharing_page() {
243        $this->updated_message();
244        ?>
245        <div class="wrap">
246            <div class="icon32" id="icon-options-general"><br /></div>
247            <h1><?php esc_html_e( 'Sharing Settings', 'jetpack' ); ?></h1>
248            <?php
249            /** This action is documented in modules/sharedaddy/sharing.php */
250            do_action( 'pre_admin_screen_sharing' );
251            ?>
252            <?php $this->sharing_block(); ?>
253        </div>
254        <?php
255    }
256
257    /**
258     * Returns the settings have been saved message.
259     */
260    public function updated_message() {
261        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- ignoring since we are just displaying that the settings have been saved and not making  any other changes to the site.
262        if ( isset( $_GET['update'] ) && 'saved' === $_GET['update'] ) {
263            echo '<div class="updated"><p>' . esc_html__( 'Settings have been saved', 'jetpack' ) . '</p></div>';
264        }
265    }
266
267    /**
268     * Returns the Likes options block, so it can be inserted into different sharing page contexts.
269     *
270     * Only rendered when the Sharing (sharedaddy) module is off, which is why the heading
271     * does not mention sharing buttons: what lands under it is the Likes settings, the
272     * "Show buttons on" setting that governs where Likes appear, and the Twitter Site Tag.
273     */
274    public function sharing_block() {
275        ?>
276        <h2><?php esc_html_e( 'Likes and Sharing', 'jetpack' ); ?></h2>
277        <form method="post" action="">
278            <table class="form-table">
279                <tbody>
280                <?php
281                /** This action is documented in modules/sharedaddy/sharing.php */
282                do_action( 'sharing_global_options' );
283                ?>
284                </tbody>
285            </table>
286
287            <p class="submit">
288            <input type="submit" name="submit" class="button-primary" value="<?php esc_attr_e( 'Save Changes', 'jetpack' ); ?>" />
289            <?php wp_nonce_field( 'sharing-options' ); ?>
290        </form>
291        <?php
292    }
293
294    /**
295     * Are likes enabled for this post?
296     *
297     * @param int $post_id - the post ID.
298     * @return bool
299     */
300    public function is_post_likeable( $post_id = 0 ) {
301        $post = get_post( $post_id );
302        if ( ! $post || is_wp_error( $post ) ) {
303            return false;
304        }
305
306        if ( ! empty( $post->post_password ) ) {
307            return false;
308        }
309
310        $sitewide_likes_enabled = (bool) $this->is_enabled_sitewide();
311        $post_likes_switched    = get_post_meta( $post->ID, 'switch_like_status', true );
312
313        /*
314         * On WPCOM, headstart was inserting bad data for post_likes_switched.
315         * it was wrapping the boolean value in an array. The array is always truthy regardless of its contents.
316         * There was another bug where truthy values were ignored if the global like setting was false.
317         * So in effect, the values for headstart never had an inpact.
318         * Delete the $post_likes_switched flag in this case in order to keep the behaviour as it was.
319         */
320        if ( is_array( $post_likes_switched ) ) {
321            $post_likes_switched = null;
322        }
323
324        /*
325         * on WPCOM, we need to look at post edit date so we don't break old posts
326         * if post edit date predates this code, stick with the former (buggy) behavior
327         * see: p7DVsv-64H-p2
328         */
329        $last_modified_time = strtotime( $post->post_modified_gmt );
330
331        $behavior_was_changed_at = strtotime( '2019-02-22 00:40:42' );
332
333        if ( $this->in_jetpack || $last_modified_time > $behavior_was_changed_at ) {
334            /*
335             * the new and improved behavior on Jetpack and recent WPCOM posts:
336             * $post_likes_switched is empty to follow site setting,
337             * 0 if we want likes disabled, 1 if we want likes enabled.
338             */
339            return $post_likes_switched || ( $sitewide_likes_enabled && $post_likes_switched !== '0' );
340        }
341
342        // implicit else (old behavior): $post_likes_switched simply inverts the global setting.
343        return ( (bool) $post_likes_switched ) xor $sitewide_likes_enabled;
344    }
345
346    /**
347     * Is the like button itself visible (as opposed to the reblog button)
348     *
349     * If called from within The Loop or if called with a $post_id set, then the post will be checked.
350     * Otherwise the sitewide setting will be used.
351     *
352     * @param int $post_id The ID of the post being rendered. Defaults to the current post if called from within The Loop.
353     * @return bool
354     */
355    public function is_likes_button_visible( $post_id = 0 ) {
356        if ( in_the_loop() || $post_id ) {
357            // If in The Loop, is_post_likeable will check the current post.
358            return $this->is_post_likeable( $post_id );
359        } else {
360            // Otherwise, check and see if likes are enabled sitewide.
361            return $this->is_enabled_sitewide();
362        }
363    }
364
365    /**
366     * Are likes visible in this context?
367     *
368     * Some of this code was taken and modified from sharing_display() to ensure
369     * similar logic and filters apply here, too.
370     */
371    public function is_likes_visible() {
372        if ( Settings::is_syncing() ) {
373            return false;
374        }
375
376        return $this->is_likes_button_visible() && $this->is_likes_module_enabled();
377    }
378
379    /**
380     * Apply filters to determine if the likes module itself is enabled
381     *
382     * @return bool
383     */
384    public function is_likes_module_enabled() {
385        global $wp_current_filter; // Used to apply 'sharing_show' filter.
386
387        $post    = get_post();
388        $enabled = true;
389
390        // Never show on feeds or previews.
391        if ( is_feed() || is_preview() ) {
392            $enabled = false;
393            // Not a feed or preview, so what is it?
394        } else {
395            if ( post_password_required() ) {
396                $enabled = false;
397            }
398
399            if ( in_array( 'get_the_excerpt', (array) $wp_current_filter, true ) ) {
400                $enabled = false;
401            }
402            // Sharing Setting Overrides ****************************************
403            // Single post including custom post types.
404            if ( is_single() ) {
405                if ( ! $this->is_single_post_enabled( ( $post instanceof WP_Post ) ? $post->post_type : 'post' ) ) {
406                    $enabled = false;
407                }
408
409                // Single page.
410            } elseif ( is_page() && ! is_front_page() ) {
411                if ( ! $this->is_single_page_enabled() ) {
412                    $enabled = false;
413                }
414
415                // Attachment.
416            } elseif ( is_attachment() ) {
417                if ( ! $this->is_attachment_enabled() ) {
418                    $enabled = false;
419                }
420
421                // All other loops.
422            } elseif ( ! $this->is_index_enabled() ) {
423                $enabled = false;
424            }
425        }
426
427        if ( $post instanceof WP_Post ) {
428            // Check that the post is a public, published post.
429            if ( 'attachment' === $post->post_type ) {
430                $post_status = get_post_status( $post->post_parent );
431            } else {
432                $post_status = $post->post_status;
433            }
434            if ( 'publish' !== $post_status ) {
435                $enabled = false;
436            }
437        }
438
439        // Run through the sharing filters.
440        /** This filter is documented in modules/sharedaddy/sharing-service.php */
441        $enabled = apply_filters( 'sharing_show', $enabled, $post );
442
443        /**
444         * Filters whether the Likes should be visible or not.
445         * Allows overwriting the options set in Settings > Sharing.
446         *
447         * @module likes
448         *
449         * @since 2.2.0
450         *
451         * @param bool $enabled Should the Likes be visible?
452         */
453        return (bool) apply_filters( 'wpl_is_likes_visible', $enabled );
454    }
455
456    /**
457     * Are Post Likes enabled on single posts?
458     *
459     * @param string $post_type custom post type identifier.
460     * @return bool
461     */
462    public function is_single_post_enabled( $post_type = 'post' ) {
463        $options = $this->get_options();
464
465        /**
466         * Filters whether Likes should be enabled on single posts.
467         *
468         * The dynamic part of the filter, {$post_type}, allows you to specific the post type where Likes should be enabled.
469         *
470         * @module likes
471         *
472         * @since 2.2.0
473         *
474         * @param bool $enabled Are Post Likes enabled on single posts?
475         */
476        $post_likes_enabled = apply_filters(
477            "wpl_is_single_{$post_type}_disabled",
478            in_array( $post_type, $options['show'], true )
479        );
480
481        return (bool) $post_likes_enabled;
482    }
483
484    /**
485     * Get the 'disabled_likes' option from the DB of the current blog.
486     *
487     * @return array
488     */
489    public function get_options() {
490        $setting             = array();
491        $setting['disabled'] = get_option( 'disabled_likes' );
492        $sharing             = get_option( 'sharing-options', array() );
493
494        if ( ! is_array( $sharing ) ) {
495            $sharing = array();
496        }
497        if ( ! isset( $sharing['global'] ) || ! is_array( $sharing['global'] ) ) {
498            $sharing['global'] = array();
499        }
500
501        // Default visibility settings
502        if ( ! isset( $sharing['global']['show'] ) ) {
503            $public_commentable_cpts = array_filter(
504                get_post_types(
505                    array(
506                        'public'   => true,
507                        '_builtin' => false,
508                    )
509                ),
510                function ( $post_type ) {
511                    return post_type_supports( $post_type, 'comments' );
512                }
513            );
514            $public_commentable_cpts = array_values( $public_commentable_cpts );
515
516            /**
517             * Filters the default post types that show Likes when no sharing settings have been saved.
518             *
519             * Only applies when the site has never explicitly configured Likes visibility.
520             * Once a site owner saves sharing settings, those are used instead.
521             *
522             * @since 16.2
523             *
524             * @param string[] $post_types Array of post type slugs that will show Likes by default.
525             */
526            $sharing['global']['show'] = apply_filters(
527                'jetpack_likes_default_post_types',
528                array_merge( array( 'post', 'page' ), $public_commentable_cpts )
529            );
530
531            // Scalar check
532        } elseif ( is_scalar( $sharing['global']['show'] ) ) {
533            switch ( $sharing['global']['show'] ) {
534                case 'posts':
535                    $sharing['global']['show'] = array( 'post', 'page' );
536                    break;
537                case 'index':
538                    $sharing['global']['show'] = array( 'index' );
539                    break;
540                case 'posts-index':
541                    $sharing['global']['show'] = array( 'post', 'page', 'index' );
542                    break;
543            }
544        }
545
546        // Ensure it's always an array (even if not previously empty or scalar).
547        $show            = $sharing['global']['show'] ?? array();
548        $setting['show'] = ! empty( $show ) ? (array) $show : array();
549
550        /**
551         * Filters where the Likes are displayed.
552         *
553         * @module likes
554         *
555         * @since 2.2.0
556         *
557         * @param array $setting Array of Likes display settings.
558         */
559        return apply_filters( 'wpl_get_options', $setting );
560    }
561
562    /**
563     * Are Post Likes enabled on archive/front/search pages?
564     *
565     * @return bool
566     */
567    public function is_index_enabled() {
568        $options = $this->get_options();
569        /**
570         * Filters whether Likes should be enabled on archive/front/search pages.
571         *
572         * @module likes
573         *
574         * @since 2.2.0
575         *
576         * @param bool $enabled Are Post Likes enabled on archive/front/search pages?
577         */
578        return (bool) apply_filters( 'wpl_is_index_disabled', in_array( 'index', $options['show'], true ) );
579    }
580
581    /**
582     * Are Post Likes enabled on single pages?
583     *
584     * @return bool
585     */
586    public function is_single_page_enabled() {
587        $options = $this->get_options();
588        /**
589         * Filters whether Likes should be enabled on single pages.
590         *
591         * @module likes
592         *
593         * @since 2.2.0
594         *
595         * @param bool $enabled Are Post Likes enabled on single pages?
596         */
597        return (bool) apply_filters( 'wpl_is_single_page_disabled', in_array( 'page', $options['show'], true ) );
598    }
599
600    /**
601     * Are Media Likes enabled on single pages?
602     *
603     * @return bool
604     */
605    public function is_attachment_enabled() {
606        $options = $this->get_options();
607        /**
608         * Filters whether Likes should be enabled on attachment pages.
609         *
610         * @module likes
611         *
612         * @since 2.2.0
613         *
614         * @param bool $enabled Are Post Likes enabled on attachment pages?
615         */
616        return (bool) apply_filters( 'wpl_is_attachment_disabled', in_array( 'attachment', $options['show'], true ) );
617    }
618
619    /**
620     * The actual options block to be inserted into the sharing page.
621     */
622    public function admin_settings_init() {
623        ?>
624        <tr>
625            <th scope="row">
626                <label><?php esc_html_e( 'WordPress.com Likes are', 'jetpack' ); ?></label>
627            </th>
628            <td>
629                <div>
630                    <label>
631                        <input type="radio" class="code" name="wpl_default" value="on" <?php checked( $this->is_enabled_sitewide(), true ); ?> />
632                        <?php esc_html_e( 'On for all posts', 'jetpack' ); ?>
633                    </label>
634                </div>
635                <div>
636                    <label>
637                        <input type="radio" class="code" name="wpl_default" value="off" <?php checked( $this->is_enabled_sitewide(), false ); ?> />
638                        <?php esc_html_e( 'Turned on per post', 'jetpack' ); ?>
639                    </label>
640                    <div>
641            </td>
642        </tr>
643        <?php if ( ! $this->in_jetpack ) : ?>
644            <tr>
645                <th scope="row">
646                    <label><?php esc_html_e( 'WordPress.com Reblog Button', 'jetpack' ); ?></label>
647                </th>
648                <td>
649                    <div>
650                        <label>
651                            <input type="radio" class="code" name="jetpack_reblogs_enabled" value="on" <?php checked( $this->reblogs_enabled_sitewide(), true ); ?> />
652                            <?php esc_html_e( 'Show the Reblog button on posts', 'jetpack' ); ?>
653                        </label>
654                    </div>
655                    <div>
656                        <label>
657                            <input type="radio" class="code" name="jetpack_reblogs_enabled" value="off" <?php checked( $this->reblogs_enabled_sitewide(), false ); ?> />
658                            <?php esc_html_e( 'Don\'t show the Reblog button on posts', 'jetpack' ); ?>
659                        </label>
660                    </div>
661                </td>
662            </tr>
663            <!-- WPCOM only: Comment Likes -->
664            <?php if ( ! $this->in_jetpack ) : ?>
665                <tr>
666                    <th scope="row">
667                        <label><?php esc_html_e( 'Comment Likes are', 'jetpack' ); ?></label>
668                    </th>
669                    <td>
670                        <div>
671                            <label>
672                                <input type="checkbox" class="code" name="jetpack_comment_likes_enabled" value="1" <?php checked( $this->is_comments_enabled(), true ); ?> />
673                                <?php esc_html_e( 'On for all comments', 'jetpack' ); ?>
674                            </label>
675                        </div>
676                    </td>
677                </tr>
678            <?php endif; ?>
679        <?php endif; ?>
680        </tbody> <?php // closes the tbody attached to sharing_show_buttons_on_row_start... ?>
681        <?php
682    }
683
684    /**
685     * Returns the current state of the "WordPress.com Reblogs are" option.
686     *
687     * @return bool true if enabled sitewide, false if not
688     */
689    public function reblogs_enabled_sitewide() {
690        /**
691         * Filters whether Reblogs are enabled by default on all posts.
692         * true if enabled sitewide, false if not.
693         *
694         * @module likes
695         *
696         * @since 3.0.0
697         *
698         * @param bool $option Are Reblogs enabled sitewide.
699         */
700        return (bool) apply_filters( 'wpl_reblogging_enabled_sitewide', ! get_option( 'disabled_reblogs' ) );
701    }
702
703    /**
704     * Used for WPCOM ONLY. Comment likes are in their own module in Jetpack.
705     * Returns if comment likes are enabled. Defaults to 'off'
706     *
707     * @return boolean true if we should show comment likes, false if not
708     */
709    public function is_comments_enabled() {
710        /**
711         * Filters whether Comment Likes are enabled.
712         * true if enabled, false if not.
713         *
714         * @module comment-likes
715         *
716         * @since 2.2.0
717         *
718         * @param bool $option Are Comment Likes enabled sitewide.
719         */
720        return (bool) apply_filters( 'jetpack_comment_likes_enabled', get_option( 'jetpack_comment_likes_enabled', false ) );
721    }
722
723    /**
724     * Saves the setting in the database.
725     */
726    public function admin_settings_callback() {
727        if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'sharing-options' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- WordPress core doesn't unslash or verify nonces either.
728            return;
729        }
730
731        // We're looking for these, and doing a dance to set some stats and save
732        // them together in array option.
733        if ( ! empty( $_POST['wpl_default'] ) ) {
734            $new_state = sanitize_text_field( wp_unslash( $_POST['wpl_default'] ) );
735        } else {
736            $new_state = 'on';
737        }
738
739        if ( ! empty( $_POST['jetpack_reblogs_enabled'] ) ) {
740            $reblogs_new_state = sanitize_text_field( wp_unslash( $_POST['jetpack_reblogs_enabled'] ) );
741        } else {
742            $reblogs_new_state = 'on';
743        }
744
745        // Checked (enabled)
746        switch ( $new_state ) {
747            case 'off':
748                update_option( 'disabled_likes', 1 );
749                break;
750            case 'on':
751            default:
752                delete_option( 'disabled_likes' );
753                break;
754        }
755
756        switch ( $reblogs_new_state ) {
757            case 'off':
758                update_option( 'disabled_reblogs', 1 );
759                break;
760            case 'on':
761            default:
762                delete_option( 'disabled_reblogs' );
763                break;
764        }
765
766        // WPCOM only: Comment Likes
767        if ( ! $this->in_jetpack ) {
768            if ( ! empty( $_POST['jetpack_comment_likes_enabled'] ) ) {
769                $new_comments_state = sanitize_text_field( wp_unslash( $_POST['jetpack_comment_likes_enabled'] ) );
770            } else {
771                $new_comments_state = false;
772            }
773            switch ( (bool) $new_comments_state ) {
774                case true:
775                    update_option( 'jetpack_comment_likes_enabled', 1 );
776                    break;
777                case false:
778                default:
779                    update_option( 'jetpack_comment_likes_enabled', 0 );
780                    break;
781            }
782        }
783    }
784
785    /**
786     * Adds the admin update hook so we can save settings even if Sharedaddy is not enabled.
787     */
788    public function process_update_requests_if_sharedaddy_not_loaded() {
789        if ( isset( $_GET['page'] ) && ( $_GET['page'] === 'sharing.php' || $_GET['page'] === 'sharing' ) ) {
790            if ( isset( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'sharing-options' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- WordPress core doesn't unslash or verify nonces either.
791                /** This action is documented in modules/sharedaddy/sharing.php */
792                do_action( 'sharing_admin_update' );
793                wp_safe_redirect( admin_url( 'options-general.php?page=sharing&update=saved' ) );
794                die( 0 );
795            }
796        }
797    }
798
799    /**
800     * If sharedaddy is not loaded, we don't have the "Show buttons on" yet, so we need to add that since it affects likes too.
801     */
802    public function admin_settings_showbuttonon_init() {
803        /** This action is documented in modules/sharedaddy/sharing.php */
804        echo apply_filters( 'sharing_show_buttons_on_row_start', '<tr valign="top">' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
805        ?>
806        <th scope="row"><label><?php esc_html_e( 'Show buttons on', 'jetpack' ); ?></label></th>
807        <td>
808            <?php
809            $br    = false;
810            $shows = array_values( get_post_types( array( 'public' => true ) ) );
811            array_unshift( $shows, 'index' );
812            $global = $this->get_options();
813            foreach ( $shows as $show ) :
814                if ( 'index' === $show ) {
815                    $label = __( 'Front Page, Archive Pages, and Search Results', 'jetpack' );
816                } else {
817                    $post_type_object = get_post_type_object( $show );
818                    $label            = $post_type_object->labels->name;
819                }
820
821                if ( $br ) {
822                    echo '<br />';
823                }
824                ?>
825                <label><input type="checkbox"<?php checked( in_array( $show, $global['show'], true ) ); ?> name="show[]" value="<?php echo esc_attr( $show ); ?>" /> <?php echo esc_html( $label ); ?></label>
826                <?php
827                $br = true;
828                endforeach;
829            ?>
830        </td>
831        <?php
832        /** This action is documented in modules/sharedaddy/sharing.php */
833        echo apply_filters( 'sharing_show_buttons_on_row_end', '</tr>' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
834    }
835
836    /**
837     * If sharedaddy is not loaded, we still need to save the the settings of the "Show buttons on" option.
838     */
839    public function admin_settings_showbuttonon_callback() {
840        $options = get_option( 'sharing-options' );
841        if ( ! is_array( $options ) ) {
842            $options = array();
843        }
844
845        $shows   = array_values( get_post_types( array( 'public' => true ) ) );
846        $shows[] = 'index';
847        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- triggered due to the 'sharing_admin_update' action, but the code in sharing.php checks for the nonce before firing the action.
848        $data = $_POST;
849
850        if ( isset( $data['show'] ) ) {
851            if ( is_scalar( $data['show'] ) ) {
852                switch ( $data['show'] ) {
853                    case 'posts':
854                        $data['show'] = array( 'post', 'page' );
855                        break;
856                    case 'index':
857                        $data['show'] = array( 'index' );
858                        break;
859                    case 'posts-index':
860                        $data['show'] = array( 'post', 'page', 'index' );
861                        break;
862                }
863            }
864
865            $data['show'] = array_intersect( $data['show'], $shows );
866            if ( $data['show'] ) {
867                $options['global']['show'] = $data['show'];
868            }
869        } else {
870            $options['global']['show'] = array();
871        }
872
873        update_option( 'sharing-options', $options );
874    }
875}