Making WordPress.org

Ticket #2955: 2955.patch

File 2955.patch, 23.4 KB (added by pierlo, 5 years ago)
  • wordpress.org/public_html/wp-content/plugins/wporg-meeting-ical/class-ical-generator.php

    diff --git wordpress.org/public_html/wp-content/plugins/wporg-meeting-ical/class-ical-generator.php wordpress.org/public_html/wp-content/plugins/wporg-meeting-ical/class-ical-generator.php
    index 59c264d0a..5e6540833 100644
     
    44class Meeting_ICAL_Generator
    55{
    66
    7         const NEWLINE = "\r\n";
    8 
    9         /**
    10          * Generate an iCalendar for the given set of meetings.
    11          *
    12          * @param WP_Post[] $posts
    13          * @return string
    14          */
    15         public function generate( $posts )
    16         {
    17                 $ical = 'BEGIN:VCALENDAR' . self::NEWLINE;
    18                 $ical .= 'VERSION:2.0' . self::NEWLINE;
    19                 $ical .= 'PRODID:-//WPORG Make//Meeting Events Calendar//EN' . self::NEWLINE;
    20                 $ical .= 'METHOD:PUBLISH' . self::NEWLINE;
    21                 $ical .= 'CALSCALE:GREGORIAN' . self::NEWLINE;
    22 
    23                 foreach ( $posts as $post ) {
    24                         $ical .= $this->generate_event( $post );
    25                 }
    26 
    27                 $ical .= 'END:VCALENDAR';
    28                 return $ical;
    29         }
    30 
    31         /**
    32          * Generate an event for a meeting.
    33          *
    34          * @param WP_Post $post
    35          * @return string
    36          */
    37         private function generate_event( $post )
    38         {
    39                 $id       = $post->ID;
    40                 $title    = $post->post_title;
    41                 $location = $post->location;
    42                 $link     = $post->link;
    43                 $team     = $post->team;
    44                 $recurring    = $post->recurring;
    45 
    46                 $start_date      = strftime( '%Y%m%d', strtotime( $post->next_date ) );
    47                 $start_time      = strftime( '%H%M%S', strtotime( $post->time ) );
    48                 $start_date_time = "{$start_date}T{$start_time}Z";
    49 
    50                 $end_date      = $start_date;
    51                 $end_time      = strftime( '%H%M%S', strtotime( "{$post->time} +1 hour" ) );
    52                 $end_date_time = "{$end_date}T{$end_time}Z";
    53 
    54                 $description = '';
    55                 $slack_channel = null;
    56 
    57                 if ( $location && preg_match( '/^#([-\w]+)$/', trim( $location ), $match ) ) {
    58                         $slack_channel = '#' . sanitize_title( $match[1] );
    59                         $location = "{$slack_channel} channel on Slack";
    60                 }
    61 
    62                 if ( $link ) {
    63                         if ( $slack_channel ) {
    64                                 $description .= "Slack channel link: https://wordpress.slack.com/messages/{$slack_channel}\\n";
    65                         }
    66 
    67                         $description .= "For more information visit {$link}";
    68                 }
    69 
    70                 $frequency = $this->get_frequency( $recurring, $post->next_date, $post->occurrence );
    71 
    72                 $event = "BEGIN:VEVENT" . self::NEWLINE;
    73                 $event .= "UID:{$id}" . self::NEWLINE;
    74 
    75                 $event .= "DTSTAMP:{$start_date_time}" . self::NEWLINE;
    76                 $event .= "DTSTART;VALUE=DATE:{$start_date_time}" . self::NEWLINE;
    77                 $event .= "DTEND;VALUE=DATE:{$end_date_time}" . self::NEWLINE;
    78                 $event .= "CATEGORIES:WordPress" . self::NEWLINE;
    79                 // Some calendars require the organizer's name and email address
    80                 $event .= "ORGANIZER;CN=WordPress {$team} Team:mailto:mail@example.com" . self::NEWLINE; // TODO: change email
    81                 $event .= "SUMMARY:{$team}: {$title}" . self::NEWLINE;
    82                 $event .= 'SEQUENCE:0' . self::NEWLINE; // TODO
    83                 $event .= 'STATUS:CONFIRMED' . self::NEWLINE;
    84                 $event .= 'TRANSP:OPAQUE' . self::NEWLINE;
    85 
    86                 if ( !empty( $location ) ) {
    87                         $event .= "LOCATION:{$location}" . self::NEWLINE;
    88                 }
    89 
    90                 if ( !empty( $description ) ) {
    91                         $event .= "DESCRIPTION:{$description}" . self::NEWLINE;
    92                 }
    93 
    94                 if ( !is_null( $frequency ) ) {
    95                         $event .= "RRULE:FREQ={$frequency}" . self::NEWLINE;
    96                 }
    97 
    98                 $event .= "END:VEVENT" . self::NEWLINE;
    99 
    100                 return $event;
    101         }
    102 
    103         private function get_frequency($recurrence, $date, $occurrences )
    104         {
    105                 switch ( $recurrence ) {
    106                         case 'weekly':
    107                                 $frequency = 'WEEKLY';
    108                                 break;
    109                         case 'biweekly':
    110                                 $frequency = 'WEEKLY;INTERVAL=2';
    111                                 break;
    112                         case 'monthly':
    113                                 $frequency = 'MONTHLY';
    114                                 break;
    115                         case 'occurrence':
    116                                 $frequency = $this->get_frequencies_by_day( $occurrences, $date );
    117                                 break;
    118                         default:
    119                                 $frequency = null;
    120                 }
    121 
    122                 return $frequency;
    123         }
    124 
    125         /**
    126          * Returns a comma separated list of days in which the event should repeat for the month.
    127          *
    128          * For example, given:
    129          *              $occurrences = array( 1, 3 ) // 1st and 3rd week in the month
    130          *              $date = '2019-09-15' // the day is Sunday
    131          * it will return: 'MONTHLY;BYDAY=1SU,3SU'
    132          *
    133          * @param array $occurrences
    134          * @param string $date
    135          * @return string
    136          */
    137         private function get_frequencies_by_day($occurrences, $date )
    138         {
    139                 // Get the first two letters of the day of the start date in uppercase letters
    140                 $day = strtoupper(
    141                         substr( strftime( '%a', strtotime( $date ) ), 0, 2 )
    142                 );
    143 
    144                 $by_days = array_reduce(array_keys( $occurrences ), function ($carry, $key) use ($day, $occurrences) {
    145                         $carry .= $occurrences[$key] . $day;
    146 
    147                         if ( $key < count( $occurrences ) - 1 ) {
    148                                 $carry .= ',';
    149                         }
    150 
    151                         return $carry;
    152                 });
    153 
    154                 return "MONTHLY;BYDAY={$by_days}";
    155         }
     7    const NEWLINE = "\r\n";
     8
     9    /**
     10     * Generate an iCalendar for the given set of meetings.
     11     *
     12     * @param WP_Post[] $posts
     13     * @return string
     14     */
     15    public function generate($posts)
     16    {
     17        $ical = 'BEGIN:VCALENDAR' . self::NEWLINE;
     18        $ical .= 'VERSION:2.0' . self::NEWLINE;
     19        $ical .= 'PRODID:-//WPORG Make//Meeting Events Calendar//EN' . self::NEWLINE;
     20        $ical .= 'METHOD:PUBLISH' . self::NEWLINE;
     21        $ical .= 'CALSCALE:GREGORIAN' . self::NEWLINE;
     22
     23        foreach ($posts as $post) {
     24            $ical .= $this->generate_event($post);
     25        }
     26
     27        $ical .= 'END:VCALENDAR';
     28        return $ical;
     29    }
     30
     31    /**
     32     * Generate an event for a meeting.
     33     *
     34     * @param WP_Post $post
     35     * @return string
     36     */
     37    private function generate_event($post)
     38    {
     39        $id = $post->ID;
     40        $title = $post->post_title;
     41        $location = $post->location;
     42        $link = $post->link;
     43        $team = $post->team;
     44        $recurring = $post->recurring;
     45        $sequence = empty($post->sequence) ? 0 : intval($post->sequence);
     46
     47        $start_date = strftime('%Y%m%d', strtotime($post->next_date));
     48        $start_time = strftime('%H%M%S', strtotime($post->time));
     49        $start_date_time = "{$start_date}T{$start_time}Z";
     50
     51        $end_date = $start_date;
     52        $end_time = strftime('%H%M%S', strtotime("{$post->time} +1 hour"));
     53        $end_date_time = "{$end_date}T{$end_time}Z";
     54
     55        $description = '';
     56        $slack_channel = null;
     57
     58        if ($location && preg_match('/^#([-\w]+)$/', trim($location), $match)) {
     59            $slack_channel = '#' . sanitize_title($match[1]);
     60            $location = "{$slack_channel} channel on Slack";
     61        }
     62
     63        if ($link) {
     64            if ($slack_channel) {
     65                $description .= "Slack channel link: https://wordpress.slack.com/messages/{$slack_channel}\\n";
     66            }
     67
     68            $description .= "For more information visit {$link}";
     69        }
     70
     71        $frequency = $this->get_frequency($recurring, $post->next_date, $post->occurrence);
     72
     73        $event = "BEGIN:VEVENT" . self::NEWLINE;
     74        $event .= "UID:{$id}" . self::NEWLINE;
     75
     76        $event .= "DTSTAMP:{$start_date_time}" . self::NEWLINE;
     77        $event .= "DTSTART;VALUE=DATE:{$start_date_time}" . self::NEWLINE;
     78        $event .= "DTEND;VALUE=DATE:{$end_date_time}" . self::NEWLINE;
     79        $event .= "CATEGORIES:WordPress" . self::NEWLINE;
     80        // Some calendars require the organizer's name and email address
     81        $event .= "ORGANIZER;CN=WordPress {$team} Team:mailto:mail@example.com" . self::NEWLINE;
     82        $event .= "SUMMARY:{$team}: {$title}" . self::NEWLINE;
     83        // Incrementing the sequence number updates the specified event
     84        $event .= "SEQUENCE:{$sequence}" . self::NEWLINE;
     85        $event .= 'STATUS:CONFIRMED' . self::NEWLINE;
     86        $event .= 'TRANSP:OPAQUE' . self::NEWLINE;
     87
     88        if (!empty($location)) {
     89            $event .= "LOCATION:{$location}" . self::NEWLINE;
     90        }
     91
     92        if (!empty($description)) {
     93            $event .= "DESCRIPTION:{$description}" . self::NEWLINE;
     94        }
     95
     96        if (!is_null($frequency)) {
     97            $event .= "RRULE:FREQ={$frequency}" . self::NEWLINE;
     98        }
     99
     100        $event .= "END:VEVENT" . self::NEWLINE;
     101
     102        return $event;
     103    }
     104
     105    private function get_frequency($recurrence, $date, $occurrences)
     106    {
     107        switch ($recurrence) {
     108            case 'weekly':
     109                $frequency = 'WEEKLY';
     110                break;
     111            case 'biweekly':
     112                $frequency = 'WEEKLY;INTERVAL=2';
     113                break;
     114            case 'monthly':
     115                $frequency = 'MONTHLY';
     116                break;
     117            case 'occurrence':
     118                $frequency = $this->get_frequencies_by_day($occurrences, $date);
     119                break;
     120            default:
     121                $frequency = null;
     122        }
     123
     124        return $frequency;
     125    }
     126
     127    /**
     128     * Returns a comma separated list of days in which the event should repeat for the month.
     129     *
     130     * For example, given:
     131     *   $occurrences = array( 1, 3 ) // 1st and 3rd week in the month
     132     *   $date = '2019-09-15' // the day is Sunday
     133     * it will return: 'MONTHLY;BYDAY=1SU,3SU'
     134     *
     135     * @param array $occurrences
     136     * @param string $date
     137     * @return string
     138     */
     139    private function get_frequencies_by_day($occurrences, $date)
     140    {
     141        // Get the first two letters of the day of the start date in uppercase letters
     142        $day = strtoupper(
     143            substr(strftime('%a', strtotime($date)), 0, 2)
     144        );
     145
     146        $by_days = array_reduce(array_keys($occurrences), function ($carry, $key) use ($day, $occurrences) {
     147            $carry .= $occurrences[$key] . $day;
     148
     149            if ($key < count($occurrences) - 1) {
     150                $carry .= ',';
     151            }
     152
     153            return $carry;
     154        });
     155
     156        return "MONTHLY;BYDAY={$by_days}";
     157    }
    156158}
  • wordpress.org/public_html/wp-content/plugins/wporg-meeting-ical/wporg-meeting-ical.php

    diff --git wordpress.org/public_html/wp-content/plugins/wporg-meeting-ical/wporg-meeting-ical.php wordpress.org/public_html/wp-content/plugins/wporg-meeting-ical/wporg-meeting-ical.php
    index b618ad161..4d9b98a78 100644
    Author URI: http://wordpress.org/ 
    99Text Domain: wporg
    1010*/
    1111
    12 //TODO:
    13 // be able to update a meeting
    14 // translations
    15 // remove dd
    16 
    1712require __DIR__ . '/class-ical-generator.php';
    1813
    19 if ( !class_exists('Meeting_ICAL') ):
    20 class Meeting_ICAL {
    21 
    22         private static $instance = NULL;
    23 
    24         const QUERY_KEY = 'meeting_ical';
    25         const QUERY_TEAM_KEY = 'meeting_team';
    26 
    27         public static function getInstance() {
    28                 require_once __DIR__ . '/../../../../vendor/autoload.php'; // TODO: remove
    29                 NULL === self::$instance && self::$instance = new self;
    30                 return self::$instance;
    31         }
    32 
    33         public static function init()
    34         {
    35                 $mi = Meeting_ICAL::getInstance();
    36 
    37                 register_activation_hook( __FILE__, array( $mi, 'on_activate' ) );
    38                 register_deactivation_hook( __FILE__, array( $mi, 'on_deactivate' ) );
    39 
    40                 add_action( 'init', array( $mi, 'add_rewrite_rules' ) );
    41                 add_action( 'parse_request', array( $mi, 'parse_request' ) );
    42 
    43                 add_filter( 'query_vars', array( $mi, 'query_vars' ) );
    44         }
    45 
    46         public function on_activate()
    47         {
    48                 $this->add_rewrite_rules();
    49                 flush_rewrite_rules();
    50         }
    51 
    52         public function on_deactivate()
    53         {
    54                 flush_rewrite_rules(); // remove custom rewrite rule
    55                 delete_option( self::QUERY_KEY ); // remove cache
    56         }
    57 
    58         public function add_rewrite_rules()
    59         {
    60                 add_rewrite_rule(
    61                         '^meetings/?([a-zA-Z\d\s_-]+)?/calendar\.ics$',
    62                         array( self::QUERY_KEY => 1, self::QUERY_TEAM_KEY => '$matches[1]' ),
    63                         'top'
    64                 );
    65         }
    66 
    67         public function parse_request( $request )
    68         {
    69                 if ( !array_key_exists( self::QUERY_KEY, $request->query_vars ) ) {
    70                         return;
    71                 }
    72 
    73                 $team = strtolower( $request->query_vars[ self::QUERY_TEAM_KEY ] );
    74 
    75                 // Generate a calendar if such a team exists
    76                 if ( $ical = $this->get_ical_contents( $team ) ) {
    77                         /**
    78                          * If the calendar has a 'method' property, the 'Content-Type' header must also specify it
    79                          */
    80                         header( 'Content-Type: text/calendar; charset=utf-8; method=publish' );
    81                         header( 'Content-Disposition: inline; filename=calendar.ics' );
    82                         echo $ical;
    83                         exit;
    84                 }
    85 
    86                 return;
    87         }
    88 
    89         public function query_vars( $query_vars )
    90         {
    91                 array_push( $query_vars, self::QUERY_KEY );
    92                 array_push( $query_vars, self::QUERY_TEAM_KEY );
    93                 return $query_vars;
    94         }
    95 
    96         private function get_ical_contents( $team )
    97         {
    98                 $ttl = 60; // in seconds
    99                 $option = $team ? self::QUERY_KEY . "_{$team}" : self::QUERY_KEY;
    100                 $cache = get_option( $option, false );
    101 
    102                 if ( is_array( $cache ) && $cache['timestamp'] > time() - $ttl ) {
    103                         return $cache['contents'];
    104                 }
    105 
    106                 if ( $contents = $this->generate_ical_contents( $team ) ) {
    107                         $cache = array( 'contents' => $contents, 'timestamp' => time() );
    108                         delete_option( $option );
    109                         add_option( $option, $cache, false, false );
    110 
    111                         return $cache['contents'];
    112                 }
    113 
    114                 return null;
    115         }
    116 
    117         private function generate_ical_contents( $team )
    118         {
    119                 $posts = $this->get_meeting_posts( $team );
    120 
    121                 // Don't generate a calendar if there are no meetings for that team
    122                 if ( empty( $posts ) ) {
    123                         return null;
    124                 }
    125 
    126                 $ical_generator = new Meeting_ICAL_Generator();
    127                 return $ical_generator->generate( $posts );
    128         }
    129 
    130         /**
    131          * Get all meetings for a team. If the 'team' parameter is empty, all meetings are returned.
    132          *
    133          * @param string $team Name of the team to fetch meetings for.
    134          * @return array
    135          */
    136         private function get_meeting_posts( $team = '' )
    137         {
    138                 // meta query to eliminate expired meetings from query
    139                 add_filter( 'get_meta_sql', function ($sql) {
    140                         return str_replace( "'CURDATE()'", 'CURDATE()', $sql );
    141                 } );
    142 
    143                 // TODO: uncomment
    144                 //              switch_to_blog( get_main_site_id() );
    145 
    146                 $query = new WP_Query(
    147                         array(
    148                                 'post_type' => 'meeting',
    149                                 'nopaging'  => true,
    150                                 'meta_query' => array(
    151                                         'relation' => 'AND',
    152                                         array(
    153                                                 'key'     => 'team',
    154                                                 'value'   => $team,
    155                                                 'compare' => empty( $team ) ? '!=' : '=',
    156                                         ),
    157                                         array(
    158                                                 'relation'=>'OR',
    159                                                 // not recurring  AND start_date >= CURDATE() = one-time meeting today or still in future
    160                                                 array(
    161                                                         'relation'=>'AND',
    162                                                         array(
    163                                                                 'key'=>'recurring',
    164                                                                 'value'=>array( 'weekly', 'biweekly', 'occurrence', 'monthly', '1' ),
    165                                                                 'compare'=>'NOT IN',
    166                                                         ),
    167                                                         array(
    168                                                                 'key'=>'start_date',
    169                                                                 'type'=>'DATE',
    170                                                                 'compare'=>'>=',
    171                                                                 'value'=>'CURDATE()',
    172                                                         )
    173                                                 ),
    174                                                 // recurring = 1 AND ( end_date = '' OR end_date > CURDATE() ) = recurring meeting that has no end or has not ended yet
    175                                                 array(
    176                                                         'relation'=>'AND',
    177                                                         array(
    178                                                                 'key'=>'recurring',
    179                                                                 'value'=>array( 'weekly', 'biweekly', 'occurrence', 'monthly', '1' ),
    180                                                                 'compare'=>'IN',
    181                                                         ),
    182                                                         array(
    183                                                                 'relation'=>'OR',
    184                                                                 array(
    185                                                                         'key'=>'end_date',
    186                                                                         'value'=>'',
    187                                                                         'compare'=>'=',
    188                                                                 ),
    189                                                                 array(
    190                                                                         'key'=>'end_date',
    191                                                                         'type'=>'DATE',
    192                                                                         'compare'=>'>',
    193                                                                         'value'=>'CURDATE()',
    194                                                                 )
    195                                                         )
    196                                                 ),
    197                                         )
    198                                 )
    199                         )
    200                 );
    201 
    202                 // TODO: uncomment
    203                 //              restore_current_blog();
    204 
    205                 return $query->posts;
    206         }
     14class Meeting_ICAL
     15{
     16
     17    private static $instance = NULL;
     18
     19    const QUERY_KEY = 'meeting_ical';
     20    const QUERY_TEAM_KEY = 'meeting_team';
     21
     22    public static function getInstance()
     23    {
     24        NULL === self::$instance && self::$instance = new self;
     25        return self::$instance;
     26    }
     27
     28    public static function init()
     29    {
     30        $mi = Meeting_ICAL::getInstance();
     31
     32        register_activation_hook(__FILE__, array($mi, 'on_activate'));
     33        register_deactivation_hook(__FILE__, array($mi, 'on_deactivate'));
     34
     35        add_action('init', array($mi, 'add_rewrite_rules'));
     36        add_action('parse_request', array($mi, 'parse_request'));
     37
     38        add_filter('query_vars', array($mi, 'query_vars'));
     39    }
     40
     41    public function on_activate()
     42    {
     43        $this->add_rewrite_rules();
     44        flush_rewrite_rules();
     45    }
     46
     47    public function on_deactivate()
     48    {
     49        flush_rewrite_rules(); // remove custom rewrite rule
     50        delete_option(self::QUERY_KEY); // remove cache
     51    }
     52
     53    public function add_rewrite_rules()
     54    {
     55        add_rewrite_rule(
     56            '^meetings/?([a-zA-Z\d\s_-]+)?/calendar\.ics$',
     57            array(self::QUERY_KEY => 1, self::QUERY_TEAM_KEY => '$matches[1]'),
     58            'top'
     59        );
     60    }
     61
     62    public function parse_request($request)
     63    {
     64        if (!array_key_exists(self::QUERY_KEY, $request->query_vars)) {
     65            return;
     66        }
     67
     68        $team = strtolower($request->query_vars[self::QUERY_TEAM_KEY]);
     69
     70        // Generate a calendar if such a team exists
     71        if ($ical = $this->get_ical_contents($team)) {
     72            /**
     73             * If the calendar has a 'method' property, the 'Content-Type' header must also specify it
     74             */
     75            header('Content-Type: text/calendar; charset=utf-8; method=publish');
     76            header('Content-Disposition: inline; filename=calendar.ics');
     77            echo $ical;
     78            exit;
     79        }
     80
     81        return;
     82    }
     83
     84    public function query_vars($query_vars)
     85    {
     86        array_push($query_vars, self::QUERY_KEY);
     87        array_push($query_vars, self::QUERY_TEAM_KEY);
     88        return $query_vars;
     89    }
     90
     91    private function get_ical_contents($team)
     92    {
     93        $ttl = 60; // in seconds
     94        $option = $team ? self::QUERY_KEY . "_{$team}" : self::QUERY_KEY;
     95        $cache = get_option($option, false);
     96
     97        if (is_array($cache) && $cache['timestamp'] > time() - $ttl) {
     98            return $cache['contents'];
     99        }
     100
     101        if ($contents = $this->generate_ical_contents($team)) {
     102            $cache = array('contents' => $contents, 'timestamp' => time());
     103            delete_option($option);
     104            add_option($option, $cache, false, false);
     105
     106            return $cache['contents'];
     107        }
     108
     109        return null;
     110    }
     111
     112    private function generate_ical_contents($team)
     113    {
     114        $posts = $this->get_meeting_posts($team);
     115
     116        // Don't generate a calendar if there are no meetings for that team
     117        if (empty($posts)) {
     118            return null;
     119        }
     120
     121        $ical_generator = new Meeting_ICAL_Generator();
     122        return $ical_generator->generate($posts);
     123    }
     124
     125    /**
     126     * Get all meetings for a team. If the 'team' parameter is empty, all meetings are returned.
     127     *
     128     * @param string $team Name of the team to fetch meetings for.
     129     * @return array
     130     */
     131    private function get_meeting_posts($team = '')
     132    {
     133        // meta query to eliminate expired meetings from query
     134        add_filter('get_meta_sql', function ($sql) {
     135            return str_replace("'CURDATE()'", 'CURDATE()', $sql);
     136        });
     137
     138        switch_to_blog(get_main_site_id());
     139
     140        $query = new WP_Query(
     141            array(
     142                'post_type' => 'meeting',
     143                'nopaging' => true,
     144                'meta_query' => array(
     145                    'relation' => 'AND',
     146                    array(
     147                        'key' => 'team',
     148                        'value' => $team,
     149                        'compare' => empty($team) ? '!=' : '=',
     150                    ),
     151                    array(
     152                        'relation' => 'OR',
     153                        // not recurring  AND start_date >= CURDATE() = one-time meeting today or still in future
     154                        array(
     155                            'relation' => 'AND',
     156                            array(
     157                                'key' => 'recurring',
     158                                'value' => array('weekly', 'biweekly', 'occurrence', 'monthly', '1'),
     159                                'compare' => 'NOT IN',
     160                            ),
     161                            array(
     162                                'key' => 'start_date',
     163                                'type' => 'DATE',
     164                                'compare' => '>=',
     165                                'value' => 'CURDATE()',
     166                            )
     167                        ),
     168                        // recurring = 1 AND ( end_date = '' OR end_date > CURDATE() ) = recurring meeting that has no end or has not ended yet
     169                        array(
     170                            'relation' => 'AND',
     171                            array(
     172                                'key' => 'recurring',
     173                                'value' => array('weekly', 'biweekly', 'occurrence', 'monthly', '1'),
     174                                'compare' => 'IN',
     175                            ),
     176                            array(
     177                                'relation' => 'OR',
     178                                array(
     179                                    'key' => 'end_date',
     180                                    'value' => '',
     181                                    'compare' => '=',
     182                                ),
     183                                array(
     184                                    'key' => 'end_date',
     185                                    'type' => 'DATE',
     186                                    'compare' => '>',
     187                                    'value' => 'CURDATE()',
     188                                )
     189                            )
     190                        ),
     191                    )
     192                )
     193            )
     194        );
     195
     196        restore_current_blog();
     197
     198        return $query->posts;
     199    }
    207200}
    208201
    209 // fire it up
    210202Meeting_ICAL::init();
    211 
    212 endif;
  • wordpress.org/public_html/wp-content/plugins/wporg-meeting-posttype/wporg-meeting-posttype.php

    diff --git wordpress.org/public_html/wp-content/plugins/wporg-meeting-posttype/wporg-meeting-posttype.php wordpress.org/public_html/wp-content/plugins/wporg-meeting-posttype/wporg-meeting-posttype.php
    index 9dd64b010..ff3b2ed63 100644
     
    22/*
    33Plugin Name: WPORG Make Homepage Meeting Post Type
    44Description: Creates the meeting post type and assorted filters for https://make.wordpress.org/meetings
    5 Version:     1.0
     5Version:     1.1
    66License:     GPLv2 or later
    77Author:      WordPress.org
    88Author URI:  http://wordpress.org/
    class Meeting_Post_Type { 
    253253                $occurrence = isset( $meta['occurrence'][0] ) ? unserialize( $meta['occurrence'][0] ) : array();
    254254                $link       = isset( $meta['link'][0] ) ? $meta['link'][0] : '';
    255255                $location   = isset( $meta['location'][0] ) ? $meta['location'][0] : '';
     256        $sequence   = isset( $meta['sequence'][0] ) ? $meta['sequence'][0] : 0;
    256257                wp_nonce_field( 'save_meeting_meta_'.$post->ID , 'meeting_nonce' );
    257258                ?>
    258259
    class Meeting_Post_Type { 
    326327                        <input type="text" name="location" id="location" class="regular-text wide" value="<?php echo esc_attr( $location ); ?>">
    327328                </label>
    328329                </p>
     330        <input type="hidden" name="sequence" value="<?php echo esc_attr( $sequence ); ?>">
    329331                <script>
    330332                jQuery(document).ready( function($) {
    331333                        $('.date').datepicker({
    class Meeting_Post_Type { 
    381383                                         ? array_map( 'intval', $_POST['occurrence'] ) : array() );
    382384                $meta['link']        = ( isset( $_POST['link'] ) ? esc_url( $_POST['link'] ) : '' );
    383385                $meta['location']    = ( isset( $_POST['location'] ) ? esc_textarea( $_POST['location'] ) : '' );
     386        $meta['sequence']    = ( isset( $_POST['sequence'] ) ? intval( $_POST['sequence'] ) + 1 : 0 );
    384387
    385388                foreach ( $meta as $key => $value ) {
    386389                        update_post_meta( $post->ID, $key, $value );