Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 166
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
jetpack_rss_links_widget_init
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
Jetpack_RSS_Links_Widget
0.00% covered (danger)
0.00%
0 / 162
0.00% covered (danger)
0.00%
0 / 7
1332
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 widget
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
132
 defaults
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 update
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 form
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 1
156
 rss_link
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
90
 get_image_tag
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
2
1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2/**
3 * RSS Links Widget
4 *
5 * @package automattic/jetpack
6 */
7
8if ( ! defined( 'ABSPATH' ) ) {
9    exit( 0 );
10}
11
12// phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move classes to appropriately-named class files.
13
14/**
15 * Register the widget.
16 */
17function jetpack_rss_links_widget_init() {
18    register_widget( Jetpack_RSS_Links_Widget::class );
19}
20add_action( 'widgets_init', 'jetpack_rss_links_widget_init' );
21
22/**
23 * RSS Links Widget class.
24 */
25class Jetpack_RSS_Links_Widget extends WP_Widget {
26    /**
27     * Constructor
28     */
29    public function __construct() {
30        $widget_ops = array(
31            'classname'                   => 'widget_rss_links',
32            'description'                 => __( "Links to your blog's RSS feeds", 'jetpack' ),
33            'customize_selective_refresh' => true,
34        );
35        parent::__construct(
36            'rss_links',
37            /** This filter is documented in modules/widgets/facebook-likebox.php */
38            apply_filters( 'jetpack_widget_name', __( 'RSS Links', 'jetpack' ) ),
39            $widget_ops
40        );
41    }
42
43    /**
44     * Display the widget.
45     *
46     * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
47     * @param array $instance The settings for the particular instance of the widget.
48     */
49    public function widget( $args, $instance ) {
50        $instance = wp_parse_args( (array) $instance, $this->defaults() );
51
52        $before_widget = isset( $args['before_widget'] ) ? $args['before_widget'] : '';
53        $before_title  = isset( $args['before_title'] ) ? $args['before_title'] : '';
54        $after_title   = isset( $args['after_title'] ) ? $args['after_title'] : '';
55        $after_widget  = isset( $args['after_widget'] ) ? $args['after_widget'] : '';
56
57        /** This filter is documented in core/src/wp-includes/default-widgets.php */
58        $title = apply_filters( 'widget_title', $instance['title'] );
59        echo $before_widget; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
60
61        if ( $title ) {
62            echo $before_title . $title . $after_title; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
63        }
64
65        if ( 'text' === $instance['format'] ) {
66            echo '<ul>';
67        }
68
69        if ( 'posts' === $instance['display'] ) {
70            $this->rss_link( 'posts', $instance );
71        } elseif ( 'comments' === $instance['display'] ) {
72            $this->rss_link( 'comments', $instance );
73        } elseif ( 'posts-comments' === $instance['display'] ) {
74            $this->rss_link( 'posts', $instance );
75            $this->rss_link( 'comments', $instance );
76        }
77
78        if ( 'text' === $instance['format'] ) {
79            echo '</ul>';
80        }
81
82        echo "\n" . $after_widget; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
83
84        /** This action is documented in modules/widgets/gravatar-profile.php */
85        do_action( 'jetpack_stats_extra', 'widget_view', 'rss-links' );
86    }
87
88    /**
89     * Return an associative array of default values
90     * These values are used in new widgets as well as when sanitizing input.
91     *
92     * @return array Array of default values for the Widget's options
93     */
94    public function defaults() {
95        return array(
96            'title'   => '',
97            'display' => 'posts-comments',
98            'format'  => 'text',
99        );
100    }
101
102    /**
103     * Sanitize widget form values as they are saved.
104     *
105     * @see WP_Widget::update()
106     *
107     * @param array $new_instance Values just sent to be saved.
108     * @param array $old_instance Previously saved values from database.
109     *
110     * @return array Updated safe values to be saved.
111     */
112    public function update( $new_instance, $old_instance ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
113        $instance = $old_instance;
114
115        $instance['title']      = wp_filter_nohtml_kses( $new_instance['title'] );
116        $instance['display']    = $new_instance['display'];
117        $instance['format']     = $new_instance['format'];
118        $instance['imagesize']  = $new_instance['imagesize'];
119        $instance['imagecolor'] = $new_instance['imagecolor'];
120
121        return $instance;
122    }
123
124    /**
125     * Back end widget form.
126     *
127     * @see WP_Widget::form()
128     *
129     * @param array $instance Previously saved values from database.
130     *
131     * @return string|void
132     */
133    public function form( $instance ) {
134        $instance = wp_parse_args( (array) $instance, $this->defaults() );
135
136        $title       = stripslashes( $instance['title'] );
137        $display     = $instance['display'];
138        $format      = $instance['format'];
139        $image_size  = isset( $instance['imagesize'] ) ? $instance['imagesize'] : 0;
140        $image_color = isset( $instance['imagecolor'] ) ? $instance['imagecolor'] : 'red';
141
142        echo '<p><label for="' . esc_attr( $this->get_field_id( 'title' ) ) . '">' . esc_html__( 'Title:', 'jetpack' ) . '
143        <input class="widefat" id="' . esc_attr( $this->get_field_id( 'title' ) ) . '" name="' . esc_attr( $this->get_field_name( 'title' ) ) . '" type="text" value="' . esc_attr( $title ) . '" />
144        </label></p>';
145
146        $displays = array(
147            'posts'          => __( 'Posts', 'jetpack' ),
148            'comments'       => __( 'Comments', 'jetpack' ),
149            'posts-comments' => __( 'Posts & Comments', 'jetpack' ),
150        );
151        echo '<p><label for="' . esc_attr( $this->get_field_id( 'display' ) ) . '">' . esc_html__( 'Feed(s) to Display:', 'jetpack' ) . '
152        <select class="widefat" id="' . esc_attr( $this->get_field_id( 'display' ) ) . '" name="' . esc_attr( $this->get_field_name( 'display' ) ) . '">';
153        foreach ( $displays as $display_option => $label ) {
154            echo '<option value="' . esc_attr( $display_option ) . '"';
155            if ( $display_option === $display ) {
156                echo ' selected="selected"';
157            }
158            echo '>' . esc_html( $label ) . '</option>' . "\n";
159        }
160        echo '</select></label></p>';
161
162        $formats = array(
163            'text'       => __( 'Text Link', 'jetpack' ),
164            'image'      => __( 'Image Link', 'jetpack' ),
165            'text-image' => __( 'Text & Image Links', 'jetpack' ),
166        );
167        echo '<p><label for="' . esc_attr( $this->get_field_id( 'format' ) ) . '">' . esc_html_x( 'Format:', 'Noun', 'jetpack' ) . '
168        <select class="widefat" id="' . esc_attr( $this->get_field_id( 'format' ) ) . '" name="' . esc_attr( $this->get_field_name( 'format' ) ) . '" onchange="if ( this.value == \'text\' ) jQuery( ' . esc_attr( wp_json_encode( '#' . $this->get_field_id( 'image-settings' ), JSON_UNESCAPED_SLASHES | JSON_HEX_AMP ) ) . ' ).fadeOut(); else jQuery( ' . esc_attr( wp_json_encode( '#' . $this->get_field_id( 'image-settings' ), JSON_UNESCAPED_SLASHES | JSON_HEX_AMP ) ) . ' ).fadeIn();">';
169        foreach ( $formats as $format_option => $label ) {
170            echo '<option value="' . esc_attr( $format_option ) . '"';
171            if ( $format_option === $format ) {
172                echo ' selected="selected"';
173            }
174            echo '>' . esc_html( $label ) . '</option>' . "\n";
175        }
176        echo '</select></label></p>';
177
178        echo '<div id="' . esc_attr( $this->get_field_id( 'image-settings' ) ) . '"';
179        if ( 'text' === $format ) {
180            echo ' style="display: none;"';
181        }
182        echo '><h3>' . esc_html__( 'Image Settings:', 'jetpack' ) . '</h3>';
183
184        $sizes = array(
185            'small'  => __( 'Small', 'jetpack' ),
186            'medium' => __( 'Medium', 'jetpack' ),
187            'large'  => __( 'Large', 'jetpack' ),
188        );
189        echo '<p><label for="' . esc_attr( $this->get_field_id( 'imagesize' ) ) . '">' . esc_html__( 'Image Size:', 'jetpack' ) . '
190        <select class="widefat" id="' . esc_attr( $this->get_field_id( 'imagesize' ) ) . '" name="' . esc_attr( $this->get_field_name( 'imagesize' ) ) . '">';
191        foreach ( $sizes as $size => $label ) {
192            echo '<option value="' . esc_attr( $size ) . '"';
193            if ( $size === $image_size ) {
194                echo ' selected="selected"';
195            }
196            echo '>' . esc_html( $label ) . '</option>' . "\n";
197        }
198        echo '</select></label></p>';
199
200        $colors = array(
201            'red'    => __( 'Red', 'jetpack' ),
202            'orange' => __( 'Orange', 'jetpack' ),
203            'green'  => __( 'Green', 'jetpack' ),
204            'blue'   => __( 'Blue', 'jetpack' ),
205            'purple' => __( 'Purple', 'jetpack' ),
206            'pink'   => __( 'Pink', 'jetpack' ),
207            'silver' => __( 'Silver', 'jetpack' ),
208        );
209        echo '<p><label for="' . esc_attr( $this->get_field_id( 'imagecolor' ) ) . '">' . esc_html__( 'Image Color:', 'jetpack' ) . '
210        <select class="widefat" id="' . esc_attr( $this->get_field_id( 'imagecolor' ) ) . '" name="' . esc_attr( $this->get_field_name( 'imagecolor' ) ) . '">';
211        foreach ( $colors as $color => $label ) {
212            echo '<option value="' . esc_attr( $color ) . '"';
213            if ( $color === $image_color ) {
214                echo ' selected="selected"';
215            }
216            echo '>' . esc_html( $label ) . '</option>' . "\n";
217        }
218        echo '</select></label></p></div>';
219    }
220
221    /**
222     * Output a link with a link to the feed.
223     *
224     * @param string $type Widget type (posts or comments).
225     * @param array  $args Widget arguments.
226     */
227    private function rss_link( $type, $args ) {
228        $link_text    = null;
229        $rss_type     = null;
230        $subscribe_to = null;
231
232        if ( 'posts' === $type ) {
233            $subscribe_to = esc_html__( 'Subscribe to posts', 'jetpack' );
234            $link_text    = esc_html__( 'RSS - Posts', 'jetpack' );
235            $rss_type     = 'rss2_url';
236        } elseif ( 'comments' === $type ) {
237            $subscribe_to = esc_html__( 'Subscribe to comments', 'jetpack' );
238            $link_text    = esc_html__( 'RSS - Comments', 'jetpack' );
239            $rss_type     = 'comments_rss2_url';
240        }
241
242        /**
243         * Filters the target link attribute for the RSS link in the RSS widget.
244         *
245         * @module widgets
246         *
247         * @since 3.4.0
248         *
249         * @param bool false Control whether the link should open in a new tab. Default to false.
250         */
251        if ( apply_filters( 'jetpack_rsslinks_widget_target_blank', false ) ) {
252            $link_target = '_blank';
253        } else {
254            $link_target = '_self';
255        }
256
257        $link_contents = null;
258        $format        = $args['format'];
259        if ( 'image' === $format ) {
260            $link_contents = $this->get_image_tag( $args );
261        } elseif ( 'text-image' === $format ) {
262            $link_contents = sprintf(
263                '%1$s&nbsp;%2$s',
264                $this->get_image_tag( $args ),
265                $link_text
266            );
267        } elseif ( 'text' === $format ) {
268            $link_contents = $link_text;
269        }
270
271        printf(
272            '%1$s<a target="%3$s" href="%4$s" title="%5$s">%6$s</a>%2$s',
273            'text' === $format ? '<li>' : '<p>', // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
274            'text' === $format ? '</li>' : '</p>', // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
275            esc_attr( $link_target ),
276            esc_url( get_bloginfo( $rss_type ) ),
277            esc_attr( $subscribe_to ),
278            $link_contents // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- we are escaping this above.
279        );
280    }
281
282    /**
283     * Return an image tag for the RSS icon.
284     *
285     * @param array $args Widget arguments.
286     */
287    private function get_image_tag( $args ) {
288        $image_path = sprintf(
289            'images/rss/%1$s-%2$s.png',
290            $args['imagecolor'],
291            $args['imagesize']
292        );
293
294        /**
295         * Filters the image used as RSS icon in the RSS widget.
296         *
297         * @module widgets
298         *
299         * @since 3.6.0
300         *
301         * @param string $var URL of RSS Widget icon.
302         */
303        $image = apply_filters(
304            'jetpack_rss_widget_icon',
305            plugins_url( $image_path, dirname( __DIR__ ) )
306        );
307
308        return sprintf(
309            '<img src="%1$s" alt="%2$s" />',
310            esc_url( $image ),
311            esc_attr__( 'RSS feed', 'jetpack' )
312        );
313    }
314} // Class Jetpack_RSS_Links_Widget