Ticket #2955: 2955.patch
File 2955.patch, 23.4 KB (added by , 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
4 4 class Meeting_ICAL_Generator 5 5 { 6 6 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 } 156 158 } -
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/ 9 9 Text Domain: wporg 10 10 */ 11 11 12 //TODO:13 // be able to update a meeting14 // translations15 // remove dd16 17 12 require __DIR__ . '/class-ical-generator.php'; 18 13 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 } 14 class 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 } 207 200 } 208 201 209 // fire it up210 202 Meeting_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
2 2 /* 3 3 Plugin Name: WPORG Make Homepage Meeting Post Type 4 4 Description: Creates the meeting post type and assorted filters for https://make.wordpress.org/meetings 5 Version: 1. 05 Version: 1.1 6 6 License: GPLv2 or later 7 7 Author: WordPress.org 8 8 Author URI: http://wordpress.org/ … … class Meeting_Post_Type { 253 253 $occurrence = isset( $meta['occurrence'][0] ) ? unserialize( $meta['occurrence'][0] ) : array(); 254 254 $link = isset( $meta['link'][0] ) ? $meta['link'][0] : ''; 255 255 $location = isset( $meta['location'][0] ) ? $meta['location'][0] : ''; 256 $sequence = isset( $meta['sequence'][0] ) ? $meta['sequence'][0] : 0; 256 257 wp_nonce_field( 'save_meeting_meta_'.$post->ID , 'meeting_nonce' ); 257 258 ?> 258 259 … … class Meeting_Post_Type { 326 327 <input type="text" name="location" id="location" class="regular-text wide" value="<?php echo esc_attr( $location ); ?>"> 327 328 </label> 328 329 </p> 330 <input type="hidden" name="sequence" value="<?php echo esc_attr( $sequence ); ?>"> 329 331 <script> 330 332 jQuery(document).ready( function($) { 331 333 $('.date').datepicker({ … … class Meeting_Post_Type { 381 383 ? array_map( 'intval', $_POST['occurrence'] ) : array() ); 382 384 $meta['link'] = ( isset( $_POST['link'] ) ? esc_url( $_POST['link'] ) : '' ); 383 385 $meta['location'] = ( isset( $_POST['location'] ) ? esc_textarea( $_POST['location'] ) : '' ); 386 $meta['sequence'] = ( isset( $_POST['sequence'] ) ? intval( $_POST['sequence'] ) + 1 : 0 ); 384 387 385 388 foreach ( $meta as $key => $value ) { 386 389 update_post_meta( $post->ID, $key, $value );