Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 93
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
upcoming_events_register_widgets
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
Jetpack_Upcoming_Events_Widget
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 6
272
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
6
 css
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 form
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
6
 update
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 widget
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 1
90
 apply_timezone_offset
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2/**
3 * Upcoming Events widget
4 *
5 * It relies on the icalendar-reader library.
6 *
7 * @package automattic/jetpack
8 */
9
10if ( ! defined( 'ABSPATH' ) ) {
11    exit( 0 );
12}
13
14// phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move classes to appropriately-named class files.
15
16/**
17 * Register the widget.
18 */
19function upcoming_events_register_widgets() {
20    register_widget( Jetpack_Upcoming_Events_Widget::class );
21}
22add_action( 'widgets_init', 'upcoming_events_register_widgets' );
23
24/**
25 * Widget class.
26 */
27class Jetpack_Upcoming_Events_Widget extends WP_Widget {
28    /**
29     * Constructor
30     */
31    public function __construct() {
32        parent::__construct(
33            'upcoming_events_widget',
34            /** This filter is documented in modules/widgets/facebook-likebox.php */
35            apply_filters( 'jetpack_widget_name', __( 'Upcoming Events', 'jetpack' ) ),
36            array(
37                'description'                 => __( 'Display upcoming events from an iCalendar feed.', 'jetpack' ),
38                'customize_selective_refresh' => true,
39            )
40        );
41        if ( is_active_widget( false, false, $this->id_base ) ) {
42            add_action( 'wp_head', array( $this, 'css' ) );
43        }
44    }
45
46    /**
47     * Output CSS in the header everywhere where the widget is active.
48     */
49    public function css() {
50        ?>
51<style type="text/css">
52.upcoming-events li {
53    margin-bottom: 10px;
54}
55.upcoming-events li span {
56    display: block;
57}
58</style>
59        <?php
60    }
61
62    /**
63     * Displays the form for this widget on the Widgets page of the WP Admin area.
64     *
65     * @param array $instance Instance configuration.
66     *
67     * @return string|void
68     */
69    public function form( $instance ) {
70        $defaults = array(
71            'title'    => __( 'Upcoming Events', 'jetpack' ),
72            'feed-url' => '',
73            'count'    => 3,
74        );
75        $instance = array_merge( $defaults, (array) $instance );
76        ?>
77
78        <p>
79        <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'jetpack' ); ?></label>
80        <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $instance['title'] ); ?>" />
81        </p>
82
83        <p>
84        <label for="<?php echo esc_attr( $this->get_field_id( 'feed-url' ) ); ?>"><?php esc_html_e( 'iCalendar Feed URL:', 'jetpack' ); ?></label>
85        <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'feed-url' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'feed-url' ) ); ?>" type="text" value="<?php echo esc_attr( $instance['feed-url'] ); ?>" />
86        </p>
87
88        <p>
89        <label for="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>"><?php esc_html_e( 'Items to show:', 'jetpack' ); ?></label>
90        <select id="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'count' ) ); ?>">
91            <?php for ( $i = 1; $i <= 10; $i++ ) { ?>
92                <option <?php selected( $instance['count'], $i ); ?>><?php echo esc_html( (string) $i ); ?></option>
93            <?php } ?>
94            <option value="0" <?php selected( $instance['count'], 0 ); ?>><?php esc_html_e( 'All', 'jetpack' ); ?></option>
95        </select>
96        </p>
97        <?php
98    }
99
100    /**
101     * Deals with the settings when they are saved by the admin.
102     *
103     * @param array $new_instance New configuration values.
104     * @param array $old_instance Old configuration values.
105     *
106     * @return array
107     */
108    public function update( $new_instance, $old_instance ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
109        $instance             = array();
110        $instance['title']    = wp_strip_all_tags( $new_instance['title'] );
111        $instance['feed-url'] = wp_strip_all_tags( $new_instance['feed-url'] );
112        $instance['count']    = min( absint( $new_instance['count'] ), 10 ); // 10 or less
113        return $instance;
114    }
115
116    /**
117     * Outputs the HTML for this widget.
118     *
119     * @param array $args     An array of standard parameters for widgets in this theme.
120     * @param array $instance An array of settings for this widget instance.
121     *
122     * @return void Echoes it's output
123     */
124    public function widget( $args, $instance ) {
125        require_once JETPACK__PLUGIN_DIR . '/_inc/lib/icalendar-reader.php';
126
127        $ical   = new iCalendarReader();
128        $events = array();
129        if ( ! empty( $instance['feed-url'] ) ) {
130            $events = $ical->get_events( $instance['feed-url'], $instance['count'] );
131            $events = $this->apply_timezone_offset( $events );
132        }
133        $ical->timezone = null;
134
135        echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
136        if ( ! empty( $instance['title'] ) ) {
137            echo $args['before_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
138            echo esc_html( $instance['title'] );
139            echo $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
140        }
141
142        if ( empty( $instance['feed-url'] ) ) {
143            if ( current_user_can( 'manage_options' ) ) {
144                echo '<div class="error-message">';
145                esc_html_e( 'The events feed URL is not properly set up in this widget.', 'jetpack' );
146                echo '</div>';
147            }
148        } elseif ( ! $events ) {
149            echo '<p>';
150            esc_html_e( 'No upcoming events', 'jetpack' );
151            echo '</p>';
152        } else {
153            ?>
154            <ul class="upcoming-events">
155                <?php foreach ( $events as $event ) : ?>
156                <li>
157                    <strong class="event-summary">
158                        <?php
159                        echo $ical->escape( stripslashes( $event['SUMMARY'] ?? '' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- this method is built to escape.
160                        ?>
161                    </strong>
162                    <span class="event-when"><?php echo esc_html( $ical->formatted_date( $event ) ); ?></span>
163                    <?php if ( ! empty( $event['LOCATION'] ) ) : ?>
164                        <span class="event-location">
165                            <?php
166                            echo $ical->escape( stripslashes( $event['LOCATION'] ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- this method is built to escape.
167                            ?>
168                        </span>
169                    <?php endif; ?>
170                    <?php if ( ! empty( $event['DESCRIPTION'] ) ) : ?>
171                        <span class="event-description">
172                            <?php
173                            echo wp_trim_words( $ical->escape( stripcslashes( $event['DESCRIPTION'] ) ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- this method is built to escape.
174                            ?>
175                        </span>
176                    <?php endif; ?>
177                </li>
178                <?php endforeach; ?>
179            </ul>
180            <?php
181        }
182
183        echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
184
185        /** This action is documented in modules/widgets/gravatar-profile.php */
186        do_action( 'jetpack_stats_extra', 'widget_view', 'upcoming_events' );
187    }
188
189    /**
190     * Left this function here for backward compatibility
191     * just incase a site using jetpack is also using this function
192     *
193     * @param array|false $events Array of events, false on failure.
194     */
195    private function apply_timezone_offset( $events ) {
196        require_once JETPACK__PLUGIN_DIR . '/_inc/lib/icalendar-reader.php';
197
198        return ( new iCalendarReader() )->apply_timezone_offset( $events );
199    }
200}