My Calendar - Version 3.3.6

Version Description

  • Bug fix: Event template previews should only show to users who can use them.
  • Bug fix: Category key icons should show background colors when configured.
Download this release

Release Info

Developer joedolson
Plugin Icon 128x128 My Calendar
Version 3.3.6
Comparing to
See all releases

Code changes from version 3.3.0 to 3.3.6

css/backcompat.css ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .mcs-tabs .tabs {
2
+ margin: 0 !important;
3
+ padding: 0 4px;
4
+ position: relative;
5
+ top: 1px;
6
+ }
7
+
8
+ .mcs-tabs .tabs li {
9
+ display: inline;
10
+ margin: 0 auto;
11
+ line-height: 1;
12
+ float: none;
13
+ }
14
+
15
+ .mcs-tabs .tabs a {
16
+ display: inline-block;
17
+ padding: 4px 8px;
18
+ border-radius: 4px 4px 0 0;
19
+ border: 1px solid #ccc;
20
+ background: #f3f3f3;
21
+ }
22
+
23
+ .mcs-tabs.settings .tabs a {
24
+ padding: 8px;
25
+ font-size: 1.2em;
26
+ }
27
+
28
+ .mcs-tabs .tabs a.active {
29
+ border-bottom: 1px solid #fefefe;
30
+ background: #fefefe;
31
+ text-decoration: none;
32
+ cursor: text;
33
+ }
34
+
35
+ .mcs-tabs .wptab {
36
+ background: #fff;
37
+ margin-bottom: 10px;
38
+ border: 1px solid #ccc;
39
+ display: block !important;
40
+ }
css/mc-print.css CHANGED
@@ -4,7 +4,7 @@
4
  size: landscape;
5
  }
6
 
7
- .my-calendar-header, .mc_bottomnav, h3 img, .mc-toggle, .mc_edit_links, #mc-export, .longdesc, .shortdesc, .mc-print, form, .screen-reader-text, .sharing {
8
  display: none;
9
  }
10
 
4
  size: landscape;
5
  }
6
 
7
+ .my-calendar-header, .mc_bottomnav, h3 img, .mc-toggle, .mc_edit_links, #mc-export, .longdesc, .shortdesc, .mc-print, form, .screen-reader-text, .sharing, .mc-date .event-icon {
8
  display: none;
9
  }
10
 
css/mc-styles.css CHANGED
@@ -787,10 +787,30 @@ strong.label {
787
  margin-bottom: 10px;
788
  }
789
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
790
  .add_field .dashicons,
791
  .add-location .dashicons,
 
792
  .add-occurrence .dashicons {
793
  vertical-align: middle;
 
794
  }
795
 
796
  .mc-settings-page #mc-sortable .mc-updated,
@@ -900,6 +920,10 @@ input[name="mc_uri"] {
900
  margin-bottom: 1em;
901
  }
902
 
 
 
 
 
903
  .mc-primary-category option {
904
  display: none;
905
  }
787
  margin-bottom: 10px;
788
  }
789
 
790
+ .location-input {
791
+ width: 30em;
792
+ }
793
+
794
+ .wp-core-ui .location-toggle .button {
795
+ margin-bottom: 0;
796
+ }
797
+
798
+ #my-calendar.disabled .ui-sortable .postbox .inside > *:not(#mc-scheduled-dates) {
799
+ opacity: .3;
800
+ }
801
+
802
+ #my-calendar.disabled #mc-scheduled-dates {
803
+ padding: 1em .5em;
804
+ box-shadow: 3px 3px 3px #c3c4c7;
805
+ border: 1px solid #a7aaad;
806
+ }
807
+
808
  .add_field .dashicons,
809
  .add-location .dashicons,
810
+ .toggle-dates .dashicons,
811
  .add-occurrence .dashicons {
812
  vertical-align: middle;
813
+ font-size: 1.1rem;
814
  }
815
 
816
  .mc-settings-page #mc-sortable .mc-updated,
920
  margin-bottom: 1em;
921
  }
922
 
923
+ .icon-list .category-icon img {
924
+ max-width: 100%;
925
+ }
926
+
927
  .mc-primary-category option {
928
  display: none;
929
  }
css/reset.css CHANGED
@@ -15,11 +15,8 @@ div.site-content, table {
15
 
16
  .mc-main {
17
  line-height: 1;
18
- max-width: 980px !important;
19
- }
20
-
21
- .single-event {
22
- max-width: 610px !important;
23
  }
24
 
25
  .my-calendar-nav ul {
@@ -38,7 +35,6 @@ div.site-content, table {
38
  column-gap: 10px;
39
  row-gap: 10px;
40
  padding: .25rem 0;
41
- font-size: .9rem;
42
  }
43
 
44
  .mc-main .my-calendar-footer select:not(.my-calendar-admin select),
@@ -48,9 +44,9 @@ div.site-content, table {
48
  .mc-main .my-calendar-header input[type=text]:not(.my-calendar-admin input[type=text]),
49
  .mc-main .my-calendar-header input[type=submit]:not(.my-calendar-admin input[type=submit]) {
50
  line-height: 1;
51
- font-size: .9rem;
52
  padding-top: 6px;
53
  padding-bottom: 6px;
 
54
  }
55
 
56
  .mc-main .my-calendar-header input[type=text]:not(.my-calendar-admin input[type=text]),
15
 
16
  .mc-main {
17
  line-height: 1;
18
+ max-width: 1120px !important;
19
+ margin: 0 auto;
 
 
 
20
  }
21
 
22
  .my-calendar-nav ul {
35
  column-gap: 10px;
36
  row-gap: 10px;
37
  padding: .25rem 0;
 
38
  }
39
 
40
  .mc-main .my-calendar-footer select:not(.my-calendar-admin select),
44
  .mc-main .my-calendar-header input[type=text]:not(.my-calendar-admin input[type=text]),
45
  .mc-main .my-calendar-header input[type=submit]:not(.my-calendar-admin input[type=submit]) {
46
  line-height: 1;
 
47
  padding-top: 6px;
48
  padding-bottom: 6px;
49
+ margin: 0;
50
  }
51
 
52
  .mc-main .my-calendar-header input[type=text]:not(.my-calendar-admin input[type=text]),
includes/conditionals.php CHANGED
@@ -39,23 +39,30 @@ function mc_is_all_day( $event ) {
39
  }
40
 
41
  /**
42
- * Check whether a given icon is a custom or stock icon
43
  *
44
  * @return boolean
45
  */
46
  function mc_is_custom_icon() {
47
- $dir = plugin_dir_path( __FILE__ );
48
- $base = basename( $dir );
49
- if ( file_exists( str_replace( $base, '', $dir ) . 'my-calendar-custom' ) ) {
50
- $results = mc_directory_list( str_replace( $base, '', $dir ) . 'my-calendar-custom' );
51
- if ( empty( $results ) ) {
52
- return false;
53
- } else {
54
- return true;
 
 
 
 
 
 
 
55
  }
56
  }
57
 
58
- return false;
59
  }
60
 
61
  /**
39
  }
40
 
41
  /**
42
+ * Check whether using custom or stock icons.
43
  *
44
  * @return boolean
45
  */
46
  function mc_is_custom_icon() {
47
+ $on = get_transient( 'mc_custom_icons' );
48
+ $return = false;
49
+ if ( $on ) {
50
+ return true;
51
+ } else {
52
+ $dir = trailingslashit( dirname( __FILE__, 2 ) );
53
+ $base = basename( $dir );
54
+ if ( file_exists( str_replace( $base, '', $dir ) . 'my-calendar-custom' ) ) {
55
+ $results = mc_directory_list( str_replace( $base, '', $dir ) . 'my-calendar-custom' );
56
+ if ( empty( $results ) ) {
57
+ $return = false;
58
+ } else {
59
+ $return = true;
60
+ }
61
+ set_transient( 'mc_custom_icons', true, HOUR_IN_SECONDS );
62
  }
63
  }
64
 
65
+ return $return;
66
  }
67
 
68
  /**
includes/date-utilities.php CHANGED
@@ -395,7 +395,7 @@ function mc_exit_early( $event, $process_date ) {
395
  */
396
  function mc_private_event( $event, $type = true ) {
397
  // If this is an invalid event, consider it private.
398
- if ( ! property_exists( $event, 'category_private' ) ) {
399
  return true;
400
  }
401
  if ( $type ) {
@@ -497,7 +497,7 @@ function mc_date( $format, $timestamp = false, $offset = true ) {
497
  }
498
  $timestamp = $timestamp + $offset;
499
 
500
- return gmdate( $format, $timestamp );
501
  }
502
 
503
  /**
@@ -599,15 +599,15 @@ function mc_date_array( $timestamp, $period ) {
599
  );
600
  break;
601
  case 'week':
602
- $day_of_week = (int) mc_date( 'N', $timestamp );
603
  $start_of_week = ( get_option( 'start_of_week' ) === '1' ) ? 1 : 7; // convert start of week to ISO 8601 (Monday/Sunday).
604
  if ( $day_of_week !== $start_of_week ) {
605
  if ( $start_of_week > $day_of_week ) {
606
- $diff = $start_of_week - $day_of_week;
607
  } else {
608
- $diff = $day_of_week - $start_of_week;
609
  }
610
- $timestamp = strtotime( "-$diff days", $timestamp );
611
  }
612
  $from = mc_date( 'Y-m-d', $timestamp, false );
613
  $to = mc_date( 'Y-m-d', strtotime( '+6 days', $timestamp ), false );
395
  */
396
  function mc_private_event( $event, $type = true ) {
397
  // If this is an invalid event, consider it private.
398
+ if ( ! is_object( $event ) || ! property_exists( $event, 'category_private' ) ) {
399
  return true;
400
  }
401
  if ( $type ) {
497
  }
498
  $timestamp = $timestamp + $offset;
499
 
500
+ return ( '' === $format ) ? $timestamp : gmdate( $format, $timestamp );
501
  }
502
 
503
  /**
599
  );
600
  break;
601
  case 'week':
602
+ $day_of_week = (int) mc_date( 'N', $timestamp, false );
603
  $start_of_week = ( get_option( 'start_of_week' ) === '1' ) ? 1 : 7; // convert start of week to ISO 8601 (Monday/Sunday).
604
  if ( $day_of_week !== $start_of_week ) {
605
  if ( $start_of_week > $day_of_week ) {
606
+ $diff = 7 - ( ( $start_of_week - $day_of_week ) );
607
  } else {
608
+ $diff = ( $day_of_week - $start_of_week );
609
  }
610
+ $timestamp = ( 7 !== $diff ) ? strtotime( "-$diff days", $timestamp ) : $timestamp;
611
  }
612
  $from = mc_date( 'Y-m-d', $timestamp, false );
613
  $to = mc_date( 'Y-m-d', strtotime( '+6 days', $timestamp ), false );
includes/general-utilities.php CHANGED
@@ -283,7 +283,7 @@ function mc_skip_holidays() {
283
  $return = true;
284
  }
285
 
286
- return $return;
287
  }
288
 
289
  /**
283
  $return = true;
284
  }
285
 
286
+ return apply_filters( 'mc_skip_holidays', $return );
287
  }
288
 
289
  /**
includes/kses.php CHANGED
@@ -160,7 +160,7 @@ function mc_allowed_tags( $tags, $context ) {
160
  */
161
  function mc_kses_elements() {
162
  $elements = array(
163
- 'svg' => array(
164
  'class' => array(),
165
  'style' => array(),
166
  'focusable' => array(),
@@ -169,46 +169,46 @@ function mc_kses_elements() {
169
  'xmlns' => array(),
170
  'viewbox' => array(),
171
  ),
172
- 'g' => array(
173
  'fill' => array(),
174
  ),
175
- 'title' => array(
176
  'id' => array(),
177
  'title' => array(),
178
  ),
179
- 'path' => array(
180
  'd' => array(),
181
  'fill' => array(),
182
  ),
183
- 'h2' => array(
184
  'class' => array(),
185
  'id' => array(),
186
  ),
187
- 'h3' => array(
188
  'class' => array(),
189
  'id' => array(),
190
  ),
191
- 'h4' => array(
192
  'class' => array(),
193
  'id' => array(),
194
  ),
195
- 'h5' => array(
196
  'class' => array(),
197
  'id' => array(),
198
  ),
199
- 'h6' => array(
200
  'class' => array(),
201
  'id' => array(),
202
  ),
203
- 'label' => array(
204
  'for' => array(),
205
  'class' => array(),
206
  ),
207
- 'option' => array(
208
  'value' => array(),
209
  'selected' => array(),
210
  ),
211
- 'select' => array(
212
  'id' => array(),
213
  'aria-describedby' => array(),
214
  'aria-labelledby' => array(),
@@ -220,7 +220,7 @@ function mc_kses_elements() {
220
  'readonly' => array(),
221
  'autocomplete' => array(),
222
  ),
223
- 'input' => array(
224
  'id' => array(),
225
  'class' => array(),
226
  'aria-describedby' => array(),
@@ -238,7 +238,7 @@ function mc_kses_elements() {
238
  'autocomplete' => array(),
239
  'data-href' => array(),
240
  ),
241
- 'textarea' => array(
242
  'id' => array(),
243
  'class' => array(),
244
  'cols' => array(),
@@ -250,14 +250,14 @@ function mc_kses_elements() {
250
  'readonly' => array(),
251
  'name' => array(),
252
  ),
253
- 'form' => array(
254
  'id' => array(),
255
  'name' => array(),
256
  'action' => array(),
257
  'method' => array(),
258
  'class' => array(),
259
  ),
260
- 'button' => array(
261
  'name' => array(),
262
  'disabled' => array(),
263
  'type' => array(),
@@ -269,45 +269,46 @@ function mc_kses_elements() {
269
  'aria-controls' => array(),
270
  'data-href' => array(),
271
  ),
272
- 'ul' => array(
273
  'class' => array(),
274
  ),
275
- 'fieldset' => array(
276
  'class' => array(),
277
  'id' => array(),
278
  ),
279
- 'legend' => array(
280
  'class' => array(),
281
  'id' => array(),
282
  ),
283
- 'li' => array(
284
  'class' => array(),
285
  ),
286
- 'span' => array(
287
  'id' => array(),
288
  'class' => array(),
289
  'aria-live' => array(),
290
  'aria-hidden' => array(),
291
- 'span' => array(),
292
  ),
293
- 'i' => array(
294
  'id' => array(),
295
  'class' => array(),
296
  'aria-live' => array(),
297
  'aria-hidden' => array(),
298
  ),
299
- 'p' => array(
300
  'class' => array(),
301
  ),
302
- 'div' => array(
303
  'class' => array(),
304
  'aria-live' => array(),
305
  'id' => array(),
306
  'role' => array(),
307
  'data-default' => array(),
308
  'aria-labelledby' => array(),
 
309
  ),
310
- 'img' => array(
311
  'class' => true,
312
  'src' => true,
313
  'alt' => true,
@@ -317,53 +318,61 @@ function mc_kses_elements() {
317
  'longdesc' => true,
318
  'tabindex' => true,
319
  ),
320
- 'br' => array(),
321
- 'table' => array(
322
  'class' => array(),
323
  'id' => array(),
324
  ),
325
- 'caption' => array(),
326
- 'thead' => array(),
327
- 'tfoot' => array(),
328
- 'tbody' => array(),
329
- 'tr' => array(
330
  'class' => array(),
331
  'id' => array(),
332
  ),
333
- 'th' => array(
334
  'scope' => array(),
335
  'class' => array(),
336
  'id' => array(),
337
  ),
338
- 'td' => array(
339
  'class' => array(),
340
  'id' => array(),
341
  'aria-live' => array(),
342
  ),
343
- 'a' => array(
344
  'aria-labelledby' => array(),
345
  'aria-describedby' => array(),
346
  'href' => array(),
347
  'class' => array(),
348
  'aria-current' => array(),
 
349
  ),
350
- 'section' => array(
351
  'id' => array(),
352
  'class' => array(),
353
  ),
354
- 'aside' => array(
355
  'id' => array(),
356
  'class' => array(),
357
  ),
358
- 'code' => array(
359
  'class' => array(),
360
  ),
361
- 'pre' => array(
362
  'class' => array(),
363
  ),
364
- 'script' => array(
365
  'type' => 'application/ld+json',
366
  ),
 
 
 
 
 
 
 
367
  );
368
 
369
  return $elements;
160
  */
161
  function mc_kses_elements() {
162
  $elements = array(
163
+ 'svg' => array(
164
  'class' => array(),
165
  'style' => array(),
166
  'focusable' => array(),
169
  'xmlns' => array(),
170
  'viewbox' => array(),
171
  ),
172
+ 'g' => array(
173
  'fill' => array(),
174
  ),
175
+ 'title' => array(
176
  'id' => array(),
177
  'title' => array(),
178
  ),
179
+ 'path' => array(
180
  'd' => array(),
181
  'fill' => array(),
182
  ),
183
+ 'h2' => array(
184
  'class' => array(),
185
  'id' => array(),
186
  ),
187
+ 'h3' => array(
188
  'class' => array(),
189
  'id' => array(),
190
  ),
191
+ 'h4' => array(
192
  'class' => array(),
193
  'id' => array(),
194
  ),
195
+ 'h5' => array(
196
  'class' => array(),
197
  'id' => array(),
198
  ),
199
+ 'h6' => array(
200
  'class' => array(),
201
  'id' => array(),
202
  ),
203
+ 'label' => array(
204
  'for' => array(),
205
  'class' => array(),
206
  ),
207
+ 'option' => array(
208
  'value' => array(),
209
  'selected' => array(),
210
  ),
211
+ 'select' => array(
212
  'id' => array(),
213
  'aria-describedby' => array(),
214
  'aria-labelledby' => array(),
220
  'readonly' => array(),
221
  'autocomplete' => array(),
222
  ),
223
+ 'input' => array(
224
  'id' => array(),
225
  'class' => array(),
226
  'aria-describedby' => array(),
238
  'autocomplete' => array(),
239
  'data-href' => array(),
240
  ),
241
+ 'textarea' => array(
242
  'id' => array(),
243
  'class' => array(),
244
  'cols' => array(),
250
  'readonly' => array(),
251
  'name' => array(),
252
  ),
253
+ 'form' => array(
254
  'id' => array(),
255
  'name' => array(),
256
  'action' => array(),
257
  'method' => array(),
258
  'class' => array(),
259
  ),
260
+ 'button' => array(
261
  'name' => array(),
262
  'disabled' => array(),
263
  'type' => array(),
269
  'aria-controls' => array(),
270
  'data-href' => array(),
271
  ),
272
+ 'ul' => array(
273
  'class' => array(),
274
  ),
275
+ 'fieldset' => array(
276
  'class' => array(),
277
  'id' => array(),
278
  ),
279
+ 'legend' => array(
280
  'class' => array(),
281
  'id' => array(),
282
  ),
283
+ 'li' => array(
284
  'class' => array(),
285
  ),
286
+ 'span' => array(
287
  'id' => array(),
288
  'class' => array(),
289
  'aria-live' => array(),
290
  'aria-hidden' => array(),
291
+ 'style' => array(),
292
  ),
293
+ 'i' => array(
294
  'id' => array(),
295
  'class' => array(),
296
  'aria-live' => array(),
297
  'aria-hidden' => array(),
298
  ),
299
+ 'p' => array(
300
  'class' => array(),
301
  ),
302
+ 'div' => array(
303
  'class' => array(),
304
  'aria-live' => array(),
305
  'id' => array(),
306
  'role' => array(),
307
  'data-default' => array(),
308
  'aria-labelledby' => array(),
309
+ 'style' => array(),
310
  ),
311
+ 'img' => array(
312
  'class' => true,
313
  'src' => true,
314
  'alt' => true,
318
  'longdesc' => true,
319
  'tabindex' => true,
320
  ),
321
+ 'br' => array(),
322
+ 'table' => array(
323
  'class' => array(),
324
  'id' => array(),
325
  ),
326
+ 'caption' => array(),
327
+ 'thead' => array(),
328
+ 'tfoot' => array(),
329
+ 'tbody' => array(),
330
+ 'tr' => array(
331
  'class' => array(),
332
  'id' => array(),
333
  ),
334
+ 'th' => array(
335
  'scope' => array(),
336
  'class' => array(),
337
  'id' => array(),
338
  ),
339
+ 'td' => array(
340
  'class' => array(),
341
  'id' => array(),
342
  'aria-live' => array(),
343
  ),
344
+ 'a' => array(
345
  'aria-labelledby' => array(),
346
  'aria-describedby' => array(),
347
  'href' => array(),
348
  'class' => array(),
349
  'aria-current' => array(),
350
+ 'target' => array(),
351
  ),
352
+ 'section' => array(
353
  'id' => array(),
354
  'class' => array(),
355
  ),
356
+ 'aside' => array(
357
  'id' => array(),
358
  'class' => array(),
359
  ),
360
+ 'code' => array(
361
  'class' => array(),
362
  ),
363
+ 'pre' => array(
364
  'class' => array(),
365
  ),
366
+ 'script' => array(
367
  'type' => 'application/ld+json',
368
  ),
369
+ 'duet-date-picker' => array(
370
+ 'identifier' => array(),
371
+ 'first-day-of-week' => array(),
372
+ 'name' => array(),
373
+ 'value' => array(),
374
+ 'required' => array(),
375
+ ),
376
  );
377
 
378
  return $elements;
includes/widgets/class-my-calendar-mini-widget.php CHANGED
@@ -173,7 +173,7 @@ class My_Calendar_Mini_Widget extends WP_Widget {
173
  <p>
174
  <label for="<?php echo $this->get_field_id( 'below' ); ?>"><?php _e( 'Navigation below calendar', 'my-calendar' ); ?></label>
175
  <input type="text" class="widefat" name="<?php echo $this->get_field_name( 'below' ); ?>" id="<?php echo $this->get_field_id( 'below' ); ?>" value="<?php echo ( '' === $below ) ? 'key' : esc_attr( $below ); ?>" aria-describedby='<?php echo $this->get_field_id( 'below' ); ?>-navigation-fields' /> <span id='<?php echo $this->get_field_id( 'below' ); ?>-navigation-fields' class="field-description" style="font-size: 13px;color:#555">
176
- <?php _e( 'Navigation options:', 'my-calendar' ); ?> <code>nav,jump,print,key,feeds,exports,none</code><?php mc_help_link( 'Help', __( 'Navigation Keywords', 'my-calendar' ), 3 ); ?>
177
  </span>
178
  </p>
179
 
173
  <p>
174
  <label for="<?php echo $this->get_field_id( 'below' ); ?>"><?php _e( 'Navigation below calendar', 'my-calendar' ); ?></label>
175
  <input type="text" class="widefat" name="<?php echo $this->get_field_name( 'below' ); ?>" id="<?php echo $this->get_field_id( 'below' ); ?>" value="<?php echo ( '' === $below ) ? 'key' : esc_attr( $below ); ?>" aria-describedby='<?php echo $this->get_field_id( 'below' ); ?>-navigation-fields' /> <span id='<?php echo $this->get_field_id( 'below' ); ?>-navigation-fields' class="field-description" style="font-size: 13px;color:#555">
176
+ <?php _e( 'Navigation options:', 'my-calendar' ); ?> <code>nav,jump,print,key,feeds,exports,none</code><?php mc_help_link( __( 'Help', 'my-calendar' ), __( 'Navigation Keywords', 'my-calendar' ), 'navigation keywords', 3 ); ?>
177
  </span>
178
  </p>
179
 
js/ajax.js CHANGED
@@ -29,8 +29,10 @@
29
  var expanded = $( this ).attr( 'aria-expanded' );
30
  if ( expanded == 'true' ) {
31
  $( this ).attr( 'aria-expanded', 'false' ).find( '.dashicons' ).addClass( 'dashicons-plus' ).removeClass( 'dashicons-minus' );
 
32
  } else {
33
  $( this ).attr( 'aria-expanded', 'true' ).find( '.dashicons' ).addClass( 'dashicons-minus' ).removeClass( 'dashicons-plus' );
 
34
  }
35
  $( '.mc_add_new' ).toggle();
36
  });
29
  var expanded = $( this ).attr( 'aria-expanded' );
30
  if ( expanded == 'true' ) {
31
  $( this ).attr( 'aria-expanded', 'false' ).find( '.dashicons' ).addClass( 'dashicons-plus' ).removeClass( 'dashicons-minus' );
32
+ $( this ).attr( 'data-action', 'shiftback' );
33
  } else {
34
  $( this ).attr( 'aria-expanded', 'true' ).find( '.dashicons' ).addClass( 'dashicons-minus' ).removeClass( 'dashicons-plus' );
35
+ $( this ).attr( 'data-action', '' );
36
  }
37
  $( '.mc_add_new' ).toggle();
38
  });
js/jquery.admin.js CHANGED
@@ -177,6 +177,54 @@ jQuery(document).ready(function ($) {
177
  });
178
  }
179
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  // Set default conditions.
181
  $( '.event_span' ).hide();
182
  $( '.mc-actions input[type="submit"]' ).attr( 'disabled', 'disabled' );
@@ -351,6 +399,7 @@ jQuery(document).ready(function ($) {
351
  $( 'label[for=mc_event_endtime] span' ).hide();
352
  }
353
  });
 
354
  var firstItem = window.location.hash;
355
  var tabGroups = document.querySelectorAll( '.mc-tabs' );
356
 
@@ -587,6 +636,33 @@ var mediaPopup = '';
587
  mediaPopup.open();
588
  })
589
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
590
  })(jQuery);
591
 
592
  window.addEventListener( 'beforeunload', function(e) {
177
  });
178
  }
179
 
180
+ var viewDates = document.querySelector( '.toggle-dates' );
181
+ if ( null !== viewDates ) {
182
+ var addDates = document.getElementById( 'mc-view-scheduled-dates' );
183
+ var container = document.getElementById( 'my-calendar' );
184
+ var primary = document.querySelectorAll( '.button-primary' );
185
+
186
+ addDates.classList.add( 'hidden' );
187
+ viewDates.addEventListener( 'click', function(e) {
188
+ var expanded = this.getAttribute( 'aria-expanded' );
189
+ // If prior state is true, do these tasks.
190
+ if ( 'true' === expanded ) {
191
+ this.setAttribute( 'data-action', '' );
192
+ container.classList.remove( 'disabled' );
193
+ primary.forEach((el) => {
194
+ el.disabled = false;
195
+ });
196
+ addDates.classList.add( 'hidden' );
197
+ this.setAttribute( 'aria-expanded', 'false' );
198
+ this.firstChild.classList.add( 'dashicons-arrow-right' );
199
+ this.firstChild.classList.remove( 'dashicons-arrow-down' );
200
+ } else {
201
+ this.setAttribute( 'data-action', 'shiftforward' );
202
+ primary.forEach((el) => {
203
+ el.disabled = true;
204
+ });
205
+ container.classList.add( 'disabled' );
206
+ addDates.classList.remove( 'hidden' );
207
+ this.setAttribute( 'aria-expanded', 'true' );
208
+ this.firstChild.classList.add( 'dashicons-arrow-down' );
209
+ this.firstChild.classList.remove( 'dashicons-arrow-right' );
210
+ }
211
+ });
212
+ }
213
+
214
+ $(document).on( 'keydown', '#mc-scheduled-dates button',
215
+ function(e) {
216
+ var keycode = ( e.keyCode ? e.keyCode : e.which );
217
+ var action = $( ':focus' ).attr( 'data-action' );
218
+ if ( ( !e.shiftKey && keycode == 9 ) && action == 'shiftback' ) {
219
+ e.preventDefault();
220
+ $( '.toggle-dates' ).trigger( 'focus' );
221
+ }
222
+ if ( ( e.shiftKey && keycode == 9 ) && action == 'shiftforward' ) {
223
+ e.preventDefault();
224
+ $( '[data-action=shiftback]' ).trigger( 'focus' );
225
+ }
226
+ });
227
+
228
  // Set default conditions.
229
  $( '.event_span' ).hide();
230
  $( '.mc-actions input[type="submit"]' ).attr( 'disabled', 'disabled' );
399
  $( 'label[for=mc_event_endtime] span' ).hide();
400
  }
401
  });
402
+
403
  var firstItem = window.location.hash;
404
  var tabGroups = document.querySelectorAll( '.mc-tabs' );
405
 
636
  mediaPopup.open();
637
  })
638
  });
639
+
640
+ // Historic; for older My Calendar Pro only.
641
+ if ( mcAdmin.mcs < 2.1 ) {
642
+ $( '.mcs-tabs' ).each( function ( index ) {
643
+ var tabs = $('.mcs-tabs .wptab').length;
644
+ var firstItem = window.location.hash;
645
+ if ( ! firstItem ) {
646
+ var firstItem = '#' + $( '.mcs-tabs .wptab:nth-of-type(1)' ).attr( 'id' );
647
+ }
648
+ $('.mcs-tabs .tabs a[href="' + firstItem + '"]').addClass('active').attr( 'aria-selected', 'true' );
649
+ if ( tabs > 1 ) {
650
+ $( '.mcs-tabs .wptab' ).not( firstItem ).attr( 'aria-hidden', 'true' );
651
+ $( '.mcs-tabs .wptab' ).removeClass( 'initial-hidden' );
652
+ $( firstItem ).show();
653
+ $( '.mcs-tabs .tabs a' ).on( 'click', function (e) {
654
+ e.preventDefault();
655
+ $('.mcs-tabs .tabs a').removeClass('active').attr( 'aria-selected', 'false' );
656
+ $(this).addClass('active').attr( 'aria-selected', 'true' );
657
+ var target = $(this).attr('href');
658
+ window.location.hash = target;
659
+ $('.mcs-tabs .wptab').not(target).attr( 'aria-hidden', 'true' );
660
+ $(target).removeAttr( 'aria-hidden' ).show().trigger( 'focus' );
661
+ });
662
+ }
663
+ });
664
+ }
665
+
666
  })(jQuery);
667
 
668
  window.addEventListener( 'beforeunload', function(e) {
my-calendar-categories.php CHANGED
@@ -156,13 +156,14 @@ function my_calendar_manage_categories() {
156
  $cat_id = (int) $_GET['category_id'];
157
  $results = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . my_calendar_categories_table() . ' WHERE category_id=%d', $cat_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
158
 
159
- // Also delete relationships for this category.
160
- $rel_results = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . my_calendar_category_relationships_table() . ' WHERE category_id = %d', $cat_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
161
-
162
  if ( $results ) {
163
  // Set events with deleted category as primary to default category as primary.
164
- $set_category = ( is_numeric( $default_category ) ) ? absint( $default_category ) : 1;
165
  $cal_results = $wpdb->query( $wpdb->prepare( 'UPDATE `' . my_calendar_table() . '` SET event_category=%d WHERE event_category=%d', $set_category, $cat_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
 
 
 
 
166
  } else {
167
  $cal_results = false;
168
  }
@@ -447,7 +448,7 @@ function mc_edit_category_form( $view = 'edit', $cat_id = '' ) {
447
  <input type="text" class="autocomplete-input" id="cat_icon" name='category_icon' placeholder="<?php _e( 'Search for an icon', 'my-calendar' ); ?>" value="<?php echo esc_attr( $icon ); ?>" />
448
  <ul class="autocomplete-result-list"></ul>
449
  </div>
450
- <?php mc_help_link( __( 'Show Category Icons', 'my-calendar' ), __( 'Category Icons', 'my-calendar' ), 6 ); ?>
451
  </div>
452
  <?php
453
  if ( 'add' === $view ) {
@@ -999,6 +1000,26 @@ function mc_category_select( $data = false, $option = true, $multiple = false, $
999
  return $default . $list;
1000
  }
1001
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1002
  /**
1003
  * Show category output for editing lists.
1004
  *
@@ -1011,6 +1032,8 @@ function mc_admin_category_list( $event ) {
1011
  // Events *must* have a category.
1012
  mc_update_event( 'event_category', 1, $event->event_id, '%d' );
1013
  }
 
 
1014
  $cat = mc_get_category_detail( $event->event_category, false );
1015
  if ( ! is_object( $cat ) ) {
1016
  $cat = (object) array(
@@ -1147,27 +1170,35 @@ function mc_categories_html( $results, $primary ) {
1147
  * @return string
1148
  */
1149
  function mc_get_img( $file, $is_custom = false ) {
 
 
 
 
1150
  if ( $is_custom ) {
1151
- $url = plugin_dir_url( __FILE__ );
1152
- $dir = plugin_dir_path( __FILE__ );
1153
- $base = basename( $dir );
1154
- $path = str_replace( $base, 'my-calendar-custom', $url ) . '/';
1155
  } else {
1156
- $path = plugins_url( 'images/icons', __FILE__ ) . '/';
 
1157
  }
1158
  $file = ( $is_custom ) ? $file : str_replace( '.png', '.svg', $file );
1159
- $src = $path . $file;
1160
- if ( false !== stripos( $file, '.png' ) ) {
1161
- return '<img src="' . esc_url( $src ) . '" alt="" />';
1162
  }
 
1163
  $label_id = sanitize_title( $file );
1164
- $svg = wp_remote_get( $src );
1165
- if ( ! is_wp_error( $svg ) ) {
1166
- $image = wp_remote_retrieve_body( $svg );
1167
- $image = str_replace( '<svg ', '<svg focusable="false" role="img" aria-labelledby="' . $label_id . '" class="category-icon" ', $image );
1168
- $image = str_replace( '<path ', "<title id='" . $label_id . "'>$file</title><path ", $image );
1169
- } else {
1170
- $image = '<img src="data:image/png;base64,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" alt="Error fetching image" />';
 
 
 
 
 
1171
  }
1172
 
1173
  return $image;
@@ -1206,6 +1237,10 @@ function mc_category_icon( $event, $type = 'html' ) {
1206
  if ( 'html' === $type ) {
1207
  if ( false !== stripos( $src, '.svg' ) ) {
1208
  $image = get_option( 'mc_category_icon_' . $context . '_' . $event->category_id, '' );
 
 
 
 
1209
  if ( '' === $image ) {
1210
  $image = mc_generate_category_icon( $event );
1211
  }
@@ -1232,7 +1267,7 @@ function mc_category_icon( $event, $type = 'html' ) {
1232
  * @return string
1233
  */
1234
  function mc_generate_category_icon( $source ) {
1235
- $path = plugins_url( 'images/icons', __FILE__ ) . '/';
1236
  $src = $path . str_replace( '.png', '.svg', $source->category_icon );
1237
  $hex = ( strpos( $source->category_color, '#' ) !== 0 ) ? '#' : '';
1238
  $color = $hex . $source->category_color;
@@ -1254,12 +1289,18 @@ function mc_generate_category_icon( $source ) {
1254
  $context = 'category';
1255
  }
1256
  $label_id = 'cat_' . $occur_id;
1257
- $svg = wp_remote_get( $src );
1258
- $image = wp_remote_retrieve_body( $svg );
1259
- $image = str_replace( '<svg ', '<svg style="fill:' . $color . '" focusable="false" role="img" aria-labelledby="' . $label_id . '" class="category-icon" ', $image );
1260
- $image = str_replace( '<path ', "<title id='" . $label_id . "'>$cat_name</title><path ", $image );
1261
-
1262
- update_option( 'mc_category_icon_' . $context . '_' . $source->category_id, $image );
 
 
 
 
 
 
1263
 
1264
  return $image;
1265
  }
156
  $cat_id = (int) $_GET['category_id'];
157
  $results = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . my_calendar_categories_table() . ' WHERE category_id=%d', $cat_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
158
 
 
 
 
159
  if ( $results ) {
160
  // Set events with deleted category as primary to default category as primary.
161
+ $set_category = ( is_numeric( $default_category ) && $cat_id !== (int) $default_category ) ? absint( $default_category ) : 1;
162
  $cal_results = $wpdb->query( $wpdb->prepare( 'UPDATE `' . my_calendar_table() . '` SET event_category=%d WHERE event_category=%d', $set_category, $cat_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
163
+ // Update existing relationships with this category.
164
+ $rel_results = $wpdb->query( $wpdb->prepare( 'UPDATE `' . my_calendar_category_relationships_table() . '` SET category_id = %d WHERE category_id=%d', $set_category, $cat_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
165
+ // clean out duplicates.
166
+ $remove_dups = $wpdb->query( 'DELETE cr1 FROM `' . my_calendar_category_relationships_table() . '` AS cr1 INNER JOIN `' . my_calendar_category_relationships_table() . '` AS cr2 WHERE cr1.relationship_id > cr2.relationship_id AND cr1.category_id = cr2.category_id AND cr1.event_id = cr2.event_id' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
167
  } else {
168
  $cal_results = false;
169
  }
448
  <input type="text" class="autocomplete-input" id="cat_icon" name='category_icon' placeholder="<?php _e( 'Search for an icon', 'my-calendar' ); ?>" value="<?php echo esc_attr( $icon ); ?>" />
449
  <ul class="autocomplete-result-list"></ul>
450
  </div>
451
+ <?php mc_help_link( __( 'Show Category Icons', 'my-calendar' ), __( 'Category Icons', 'my-calendar' ), 'Category Icons', 6 ); ?>
452
  </div>
453
  <?php
454
  if ( 'add' === $view ) {
1000
  return $default . $list;
1001
  }
1002
 
1003
+ /**
1004
+ * Verify that an event has a valid category relationship.
1005
+ *
1006
+ * @param object $event Event object.
1007
+ */
1008
+ function mc_check_category_relationships( $event ) {
1009
+ global $wpdb;
1010
+ $relationship = $wpdb->get_var( $wpdb->prepare( 'SELECT relationship_id FROM ' . my_calendar_category_relationships_table() . ' WHERE event_id = %d AND category_id = %d', $event->event_id, $event->event_category ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1011
+ if ( ! $relationship ) {
1012
+ $wpdb->insert(
1013
+ my_calendar_category_relationships_table(),
1014
+ array(
1015
+ 'event_id' => $event->event_id,
1016
+ 'category_id' => $event->event_category,
1017
+ ),
1018
+ array( '%d', '%d' )
1019
+ );
1020
+ }
1021
+ }
1022
+
1023
  /**
1024
  * Show category output for editing lists.
1025
  *
1032
  // Events *must* have a category.
1033
  mc_update_event( 'event_category', 1, $event->event_id, '%d' );
1034
  }
1035
+ // Verify valid category relationships. Corrects problems caused by deleting a category pre 3.3.3.
1036
+ mc_check_category_relationships( $event );
1037
  $cat = mc_get_category_detail( $event->event_category, false );
1038
  if ( ! is_object( $cat ) ) {
1039
  $cat = (object) array(
1170
  * @return string
1171
  */
1172
  function mc_get_img( $file, $is_custom = false ) {
1173
+ $parent_path = plugin_dir_path( __DIR__ );
1174
+ $parent_url = plugin_dir_url( __DIR__ );
1175
+ $url = plugin_dir_url( __FILE__ );
1176
+ $self = plugin_dir_path( __FILE__ );
1177
  if ( $is_custom ) {
1178
+ $path = $parent . 'my-calendar-custom/';
1179
+ $link = $parent_url . 'my-calendar-custom/';
 
 
1180
  } else {
1181
+ $path = $self . 'images/icons/';
1182
+ $link = $url . 'images/icons/';
1183
  }
1184
  $file = ( $is_custom ) ? $file : str_replace( '.png', '.svg', $file );
1185
+ if ( false === stripos( $file, '.svg' ) ) {
1186
+ return '<img src="' . esc_url( $link . $file ) . '" alt="" />';
 
1187
  }
1188
+ $src = $path . $file;
1189
  $label_id = sanitize_title( $file );
1190
+ global $wp_filesystem;
1191
+ require_once( ABSPATH . '/wp-admin/includes/file.php' );
1192
+ WP_Filesystem();
1193
+ $svg = ( $wp_filesystem->exists( $src ) ) ? $wp_filesystem->get_contents( $src ) : false;
1194
+ $image = '<img src="data:image/png;base64,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" alt="Error fetching image" />';
1195
+ if ( $svg ) {
1196
+ $image = $svg;
1197
+ // If remote access is blocked, this will not return an SVG.
1198
+ if ( 0 === stripos( $image, '<svg' ) ) {
1199
+ $image = str_replace( '<svg ', '<svg focusable="false" role="img" aria-labelledby="' . $label_id . '" class="category-icon" ', $image );
1200
+ $image = str_replace( '<path ', "<title id='" . $label_id . "'>$file</title><path ", $image );
1201
+ }
1202
  }
1203
 
1204
  return $image;
1237
  if ( 'html' === $type ) {
1238
  if ( false !== stripos( $src, '.svg' ) ) {
1239
  $image = get_option( 'mc_category_icon_' . $context . '_' . $event->category_id, '' );
1240
+ // If there's a value, but it's not an svg, zero out.
1241
+ if ( $image && 0 !== stripos( $image, '<svg' ) ) {
1242
+ $image = '';
1243
+ }
1244
  if ( '' === $image ) {
1245
  $image = mc_generate_category_icon( $event );
1246
  }
1267
  * @return string
1268
  */
1269
  function mc_generate_category_icon( $source ) {
1270
+ $path = plugin_dir_path( __FILE__ ) . 'images/icons/';
1271
  $src = $path . str_replace( '.png', '.svg', $source->category_icon );
1272
  $hex = ( strpos( $source->category_color, '#' ) !== 0 ) ? '#' : '';
1273
  $color = $hex . $source->category_color;
1289
  $context = 'category';
1290
  }
1291
  $label_id = 'cat_' . $occur_id;
1292
+ global $wp_filesystem;
1293
+ require_once( ABSPATH . '/wp-admin/includes/file.php' );
1294
+ WP_Filesystem();
1295
+ $image = ( $wp_filesystem->exists( $src ) ) ? $wp_filesystem->get_contents( $src ) : false;
1296
+ if ( 0 === stripos( $image, '<svg' ) ) {
1297
+ $image = str_replace( '<svg ', '<svg style="fill:' . $color . '" focusable="false" role="img" aria-labelledby="' . $label_id . '" class="category-icon" ', $image );
1298
+ $image = str_replace( '<path ', "<title id='" . $label_id . "'>$cat_name</title><path ", $image );
1299
+
1300
+ update_option( 'mc_category_icon_' . $context . '_' . $source->category_id, $image );
1301
+ } else {
1302
+ $image = '';
1303
+ }
1304
 
1305
  return $image;
1306
  }
my-calendar-core.php CHANGED
@@ -259,7 +259,7 @@ $style_vars
259
  }
260
  }
261
  if ( mc_is_single_event() ) {
262
- $mc_id = absint( $_GET['mc_id'] );
263
  if ( $mc_id ) {
264
  $event = mc_get_event( $mc_id );
265
  $schema = mc_event_schema( $event );
@@ -308,11 +308,11 @@ function mc_generate_category_styles() {
308
  $alt = 'color';
309
  }
310
  $inverse = mc_inverse_color( $color );
311
- $inv = "$alt: $inverse;";
312
  if ( 'font' === get_option( 'mc_apply_color' ) || 'background' === get_option( 'mc_apply_color' ) ) {
313
  // always an anchor as of 1.11.0, apply also to title.
314
- $category_styles .= "\n.mc-main .$class .event-title, .mc-main .$class .event-title a { $type: $color; $inv }";
315
- $category_styles .= "\n.mc-main .$class .event-title a:hover, .mc-main .$class .event-title a:focus { $type: $hcolor;}";
316
  }
317
  // Variables aren't dependent on options.
318
  $category_vars .= '--category-' . $class . ': ' . $color . '; ';
@@ -1127,6 +1127,25 @@ function mc_admin_bar() {
1127
  }
1128
  }
1129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1130
  /**
1131
  * Send email notification about an event.
1132
  *
@@ -1375,6 +1394,7 @@ function mc_scripts() {
1375
  $slug = sanitize_title( __( 'My Calendar', 'my-calendar' ) );
1376
 
1377
  if ( false !== strpos( $id, 'my-calendar' ) ) {
 
1378
  wp_enqueue_script( 'mc.admin', plugins_url( 'js/jquery.admin.js', __FILE__ ), array( 'jquery', 'jquery-ui-sortable', 'wp-a11y' ), $version );
1379
  wp_localize_script(
1380
  'mc.admin',
@@ -1386,8 +1406,12 @@ function mc_scripts() {
1386
  'imageRemoved' => __( 'Featured image removed', 'my-calendar' ),
1387
  'modalTitle' => __( 'Choose an Image', 'my-calendar' ),
1388
  'buttonName' => __( 'Select', 'my-calendar' ),
 
1389
  )
1390
  );
 
 
 
1391
  }
1392
 
1393
  wp_enqueue_style( 'wp-color-picker' );
@@ -2014,7 +2038,7 @@ add_filter( 'the_posts', 'mc_close_comments' );
2014
  * @return array $posts
2015
  */
2016
  function mc_close_comments( $posts ) {
2017
- if ( ! is_single() || empty( $posts ) ) {
2018
  return $posts;
2019
  }
2020
 
259
  }
260
  }
261
  if ( mc_is_single_event() ) {
262
+ $mc_id = ( isset( $_GET['mc_id'] ) ) ? absint( $_GET['mc_id'] ) : false;
263
  if ( $mc_id ) {
264
  $event = mc_get_event( $mc_id );
265
  $schema = mc_event_schema( $event );
308
  $alt = 'color';
309
  }
310
  $inverse = mc_inverse_color( $color );
311
+ $inv = "$alt: $inverse !important;";
312
  if ( 'font' === get_option( 'mc_apply_color' ) || 'background' === get_option( 'mc_apply_color' ) ) {
313
  // always an anchor as of 1.11.0, apply also to title.
314
+ $category_styles .= "\n.mc-main .$class .event-title, .mc-main .$class .event-title a { $type: $color !important; $inv }";
315
+ $category_styles .= "\n.mc-main .$class .event-title a:hover, .mc-main .$class .event-title a:focus { $type: $hcolor !important;}";
316
  }
317
  // Variables aren't dependent on options.
318
  $category_vars .= '--category-' . $class . ': ' . $color . '; ';
1127
  }
1128
  }
1129
 
1130
+ /**
1131
+ * Label My Calendar pages in the admin.
1132
+ *
1133
+ * @param array $states States for post.
1134
+ * @param object $post The post object.
1135
+ *
1136
+ * @return array
1137
+ */
1138
+ function mc_admin_state( $states, $post ) {
1139
+ if ( is_admin() ) {
1140
+ if ( absint( get_option( 'mc_uri_id' ) ) === $post->ID ) {
1141
+ $states[] = __( 'My Calendar Page', 'my-calendar' );
1142
+ }
1143
+ }
1144
+
1145
+ return $states;
1146
+ }
1147
+ add_filter( 'display_post_states', 'mc_admin_state', 10, 2 );
1148
+
1149
  /**
1150
  * Send email notification about an event.
1151
  *
1394
  $slug = sanitize_title( __( 'My Calendar', 'my-calendar' ) );
1395
 
1396
  if ( false !== strpos( $id, 'my-calendar' ) ) {
1397
+ $mcs_version = ( get_option( 'mcs_version', '' ) ) ? get_option( 'mcs_version' ) : 1.0;
1398
  wp_enqueue_script( 'mc.admin', plugins_url( 'js/jquery.admin.js', __FILE__ ), array( 'jquery', 'jquery-ui-sortable', 'wp-a11y' ), $version );
1399
  wp_localize_script(
1400
  'mc.admin',
1406
  'imageRemoved' => __( 'Featured image removed', 'my-calendar' ),
1407
  'modalTitle' => __( 'Choose an Image', 'my-calendar' ),
1408
  'buttonName' => __( 'Select', 'my-calendar' ),
1409
+ 'mcs' => $mcs_version,
1410
  )
1411
  );
1412
+ if ( version_compare( $mcs_version, '2.1', '<' ) ) {
1413
+ wp_enqueue_style( 'mcs-back-compat', plugins_url( 'css/backcompat.css', __FILE__ ), array(), $version );
1414
+ }
1415
  }
1416
 
1417
  wp_enqueue_style( 'wp-color-picker' );
2038
  * @return array $posts
2039
  */
2040
  function mc_close_comments( $posts ) {
2041
+ if ( is_admin() || ! is_single() || empty( $posts ) ) {
2042
  return $posts;
2043
  }
2044
 
my-calendar-design.php CHANGED
@@ -45,7 +45,7 @@ function my_calendar_design() {
45
  <h2>
46
  <?php
47
  _e( 'Template Editor', 'my-calendar' );
48
- mc_help_link( __( 'Template Tag Help', 'my-calendar' ), __( 'Template Tags', 'my-calendar' ), 5 );
49
  ?>
50
  </h2>
51
  <?php
45
  <h2>
46
  <?php
47
  _e( 'Template Editor', 'my-calendar' );
48
+ mc_help_link( __( 'Template Tag Help', 'my-calendar' ), __( 'Template Tags', 'my-calendar' ), 'template tags', 5 );
49
  ?>
50
  </h2>
51
  <?php
my-calendar-event-editor.php CHANGED
@@ -713,7 +713,7 @@ function mc_show_edit_block( $field ) {
713
  $screen = get_current_screen();
714
  $show = get_user_meta( $user, 'mc_show_on_page', true );
715
  if ( empty( $show ) || $show < 1 ) {
716
- $show = $screen->get_option( 'mc_show_on_page', 'default' );
717
  }
718
  // if this doesn't exist in array, leave it on.
719
  if ( ! isset( $input[ $field ] ) || ! isset( $show[ $field ] ) ) {
@@ -754,7 +754,7 @@ function mc_edit_block_is_visible( $field ) {
754
  $screen = get_current_screen();
755
  $show = get_user_meta( $user, 'mc_show_on_page', true );
756
  if ( empty( $show ) || $show < 1 ) {
757
- $show = $screen->get_option( 'mc_show_on_page', 'default' );
758
  }
759
  if ( empty( $show ) ) {
760
  $show = $defaults;
@@ -780,6 +780,8 @@ function mc_edit_block_is_visible( $field ) {
780
  return true;
781
  }
782
  }
 
 
783
  }
784
 
785
  /**
@@ -1017,8 +1019,8 @@ function mc_show_block( $field, $has_data, $data, $echo = true, $default = '', $
1017
  $event = mc_get_instance_data( $last->occur_id );
1018
  $repeats = gmdate( 'Y-m-d', strtotime( $event->occur_begin ) );
1019
  }
1020
- $hol_checked = ( mc_skip_holidays() ) ? true : false;
1021
- $fifth_checked = ( mc_no_fifth_week() ) ? true : false;
1022
  if ( $has_data ) {
1023
  $hol_checked = ( '1' === $data->event_holiday ) ? true : $hol_checked;
1024
  $fifth_checked = ( '1' === $data->event_fifth_week ) ? true : $fifth_checked;
@@ -1050,7 +1052,7 @@ function mc_show_block( $field, $has_data, $data, $echo = true, $default = '', $
1050
  $active = ( $has_data && '' !== $recur_data ) ? ' active' : '';
1051
  $display = '<div class="mc_recur_string ' . $active . '" aria-live="polite"><p>' . $recur_data . '</p></div>';
1052
  $return = $pre . '
1053
- <h2>' . __( 'Repetition Pattern', 'my-calendar' ) . mc_help_link( 'Help', __( 'Repetition Pattern', 'my-calendar' ), '2', false ) . '</h2>
1054
  <div class="inside recurrences ' . $class . '">' . $prev . $display . $warning . '
1055
  <fieldset class="recurring">
1056
  <legend class="screen-reader-text">' . __( 'Recurring Events', 'my-calendar' ) . '</legend>
@@ -1159,18 +1161,18 @@ function mc_additional_dates( $data ) {
1159
  $instances = mc_admin_instances( $data->event_id, $date );
1160
  $input = mc_recur_datetime_input( $data );
1161
  $output = "
1162
- <div id='mc-accordion'>
1163
- <h4><button type='button' class='button'><span class='dashicons' aria-hidden='true'></span>" . esc_html__( 'View scheduled dates', 'my-calendar' ) . '</button></h4>
1164
- <div>' . $edit_desc . "
1165
  <div class='mc_response' aria-live='assertive'></div>
1166
  <ul class='columns instance-list'>
1167
  $instances
1168
  </ul>
1169
- <p><button type='button' class='add-occurrence button-secondary' aria-expanded='false'><span class='dashicons dashicons-plus' aria-hidden='true'> </span>" . esc_html__( 'Add another date', 'my-calendar' ) . "</button></p>
1170
  <div class='mc_add_new'>
1171
  $input
1172
  <p>
1173
- <button type='button' class='save-occurrence button-primary clear'>" . esc_html__( 'Add Date', 'my-calendar' ) . '</button>
1174
  </p>
1175
  </div>
1176
  </div>
@@ -1280,7 +1282,7 @@ function mc_form_fields( $data, $mode, $event_id ) {
1280
  ?>
1281
  </div>
1282
  <?php
1283
- if ( ! empty( $_GET['date'] ) && ! ( 'S' === $data->event_recur || 'S1' === $data->event_recur ) ) {
1284
  $event = mc_get_event( $instance );
1285
  $date = date_i18n( mc_date_format(), mc_strtotime( $event->occur_begin ) );
1286
  $edit_url = esc_url( admin_url( 'admin.php?page=my-calendar&mode=edit&event_id=' . $data->event_id ) );
@@ -1364,7 +1366,7 @@ function mc_form_fields( $data, $mode, $event_id ) {
1364
  }
1365
  ?>
1366
  <p class="event_span">
1367
- <button type="button" class="add_field button button-secondary"><span class="dashicons dashicons-plus" aria-hidden="true"></span><?php esc_html_e( 'Add Copy', 'my-calendar' ); ?></button> <?php mc_help_link( 'Help', __( 'Copy an event', 'my-calendar' ), 4 ); ?>
1368
  </p>
1369
  <ol class="mc-repeat-events">
1370
  <li id="event1" class="datetime-template enabled">
@@ -1380,7 +1382,7 @@ function mc_form_fields( $data, $mode, $event_id ) {
1380
  ?>
1381
  </fieldset>
1382
  <div class="buttons">
1383
- <button type="button" class="add_field button button-secondary"><span class="dashicons dashicons-plus" aria-hidden="true"></span><?php esc_html_e( 'Add Copy', 'my-calendar' ); ?></button> <?php mc_help_link( 'Help', __( 'Copy an event', 'my-calendar' ), '1' ); ?>
1384
  </div>
1385
  </li>
1386
  </ol>
@@ -1490,7 +1492,8 @@ function mc_form_fields( $data, $mode, $event_id ) {
1490
  </div>
1491
  <?php
1492
  }
1493
- ?>
 
1494
  <div class="postbox">
1495
  <h2><?php esc_html_e( 'Preview Template Output', 'my-calendar' ); ?></h2>
1496
  <div class="inside">
@@ -1523,7 +1526,8 @@ function mc_form_fields( $data, $mode, $event_id ) {
1523
  </div>
1524
  </div>
1525
  </div>
1526
- <?php
 
1527
  }
1528
  ?>
1529
  </div>
@@ -1875,23 +1879,28 @@ function mc_check_data( $action, $post, $i, $ignore_required = false ) {
1875
  $event_access = $location->location_access;
1876
  }
1877
  } else {
1878
- $event_label = ! empty( $post['event_label'] ) ? $post['event_label'] : '';
1879
- $event_street = ! empty( $post['event_street'] ) ? $post['event_street'] : '';
1880
- $event_street2 = ! empty( $post['event_street2'] ) ? $post['event_street2'] : '';
1881
- $event_city = ! empty( $post['event_city'] ) ? $post['event_city'] : '';
1882
- $event_state = ! empty( $post['event_state'] ) ? $post['event_state'] : '';
1883
- $event_postcode = ! empty( $post['event_postcode'] ) ? $post['event_postcode'] : '';
1884
- $event_region = ! empty( $post['event_region'] ) ? $post['event_region'] : '';
1885
- $event_country = ! empty( $post['event_country'] ) ? $post['event_country'] : '';
1886
- $event_url = ! empty( $post['event_url'] ) ? $post['event_url'] : '';
1887
- $event_longitude = ! empty( $post['event_longitude'] ) ? $post['event_longitude'] : '';
1888
- $event_latitude = ! empty( $post['event_latitude'] ) ? $post['event_latitude'] : '';
1889
- $event_zoom = ! empty( $post['event_zoom'] ) ? $post['event_zoom'] : '';
1890
- $event_phone = ! empty( $post['event_phone'] ) ? $post['event_phone'] : '';
1891
- $event_phone2 = ! empty( $post['event_phone2'] ) ? $post['event_phone2'] : '';
1892
- $event_access = ! empty( $post['event_access'] ) ? $post['event_access'] : '';
1893
- $event_access = ! empty( $post['event_access_hidden'] ) ? unserialize( $post['event_access_hidden'] ) : $event_access;
1894
- if ( isset( $post['mc_copy_location'] ) && 'on' === $post['mc_copy_location'] && 0 === $i ) {
 
 
 
 
 
1895
  // Only add this with the first event, if adding multiples.
1896
  $add_loc = array(
1897
  'location_label' => $event_label,
@@ -2688,6 +2697,9 @@ function mc_increment_event( $id, $post = array(), $test = false, $instances = a
2688
  $orig_begin = $post_begin . ' ' . $post_time;
2689
  $orig_end = $post_end . ' ' . $post_endtime;
2690
  }
 
 
 
2691
 
2692
  $group_id = $event->event_group_id;
2693
  $format = array( '%d', '%s', '%s', '%d' );
@@ -2749,8 +2761,8 @@ function mc_increment_event( $id, $post = array(), $test = false, $instances = a
2749
  // Every = $every = e.g. every 14 weekdays.
2750
  // Num forward = $numforward = e.g. 7 times.
2751
  for ( $i = 0; $i <= $numforward; $i ++ ) {
2752
- $begin = strtotime( $orig_begin . ' ' . ( $every * $i ) . ' weekdays' );
2753
- $end = strtotime( $orig_end . ' ' . ( $every * $i ) . ' weekdays' );
2754
  $data = array(
2755
  'occur_event_id' => $id,
2756
  'occur_begin' => mc_date( 'Y-m-d H:i:s', $begin, false ),
713
  $screen = get_current_screen();
714
  $show = get_user_meta( $user, 'mc_show_on_page', true );
715
  if ( empty( $show ) || $show < 1 ) {
716
+ $show = get_option( 'mc_input_options' );
717
  }
718
  // if this doesn't exist in array, leave it on.
719
  if ( ! isset( $input[ $field ] ) || ! isset( $show[ $field ] ) ) {
754
  $screen = get_current_screen();
755
  $show = get_user_meta( $user, 'mc_show_on_page', true );
756
  if ( empty( $show ) || $show < 1 ) {
757
+ $show = get_option( 'mc_input_options' );
758
  }
759
  if ( empty( $show ) ) {
760
  $show = $defaults;
780
  return true;
781
  }
782
  }
783
+
784
+ return false;
785
  }
786
 
787
  /**
1019
  $event = mc_get_instance_data( $last->occur_id );
1020
  $repeats = gmdate( 'Y-m-d', strtotime( $event->occur_begin ) );
1021
  }
1022
+ $hol_checked = ( mc_skip_holidays() && ! $has_data ) ? true : false;
1023
+ $fifth_checked = ( mc_no_fifth_week() && ! $has_data ) ? true : false;
1024
  if ( $has_data ) {
1025
  $hol_checked = ( '1' === $data->event_holiday ) ? true : $hol_checked;
1026
  $fifth_checked = ( '1' === $data->event_fifth_week ) ? true : $fifth_checked;
1052
  $active = ( $has_data && '' !== $recur_data ) ? ' active' : '';
1053
  $display = '<div class="mc_recur_string ' . $active . '" aria-live="polite"><p>' . $recur_data . '</p></div>';
1054
  $return = $pre . '
1055
+ <h2>' . __( 'Repetition Pattern', 'my-calendar' ) . mc_help_link( __( 'Help', 'my-calendar' ), __( 'Repetition Pattern', 'my-calendar' ), 'repetition pattern', '2', false ) . '</h2>
1056
  <div class="inside recurrences ' . $class . '">' . $prev . $display . $warning . '
1057
  <fieldset class="recurring">
1058
  <legend class="screen-reader-text">' . __( 'Recurring Events', 'my-calendar' ) . '</legend>
1161
  $instances = mc_admin_instances( $data->event_id, $date );
1162
  $input = mc_recur_datetime_input( $data );
1163
  $output = "
1164
+ <div id='mc-scheduled-dates'>
1165
+ <button type='button' aria-expanded='false' class='toggle-dates button'><span class='dashicons dashicons-arrow-right' aria-hidden='true'></span>" . esc_html__( 'View scheduled dates', 'my-calendar' ) . '</button>
1166
+ <div id="mc-view-scheduled-dates">' . $edit_desc . "
1167
  <div class='mc_response' aria-live='assertive'></div>
1168
  <ul class='columns instance-list'>
1169
  $instances
1170
  </ul>
1171
+ <p><button data-action='shiftback' type='button' class='add-occurrence button-secondary' aria-expanded='false'><span class='dashicons dashicons-plus' aria-hidden='true'> </span>" . esc_html__( 'Add another date', 'my-calendar' ) . "</button></p>
1172
  <div class='mc_add_new'>
1173
  $input
1174
  <p>
1175
+ <button type='button' data-action='shiftback' class='save-occurrence button-secondary clear'>" . esc_html__( 'Add Date', 'my-calendar' ) . '</button>
1176
  </p>
1177
  </div>
1178
  </div>
1282
  ?>
1283
  </div>
1284
  <?php
1285
+ if ( ! empty( $_GET['date'] ) ) {
1286
  $event = mc_get_event( $instance );
1287
  $date = date_i18n( mc_date_format(), mc_strtotime( $event->occur_begin ) );
1288
  $edit_url = esc_url( admin_url( 'admin.php?page=my-calendar&mode=edit&event_id=' . $data->event_id ) );
1366
  }
1367
  ?>
1368
  <p class="event_span">
1369
+ <button type="button" class="add_field button button-secondary"><span class="dashicons dashicons-plus" aria-hidden="true"></span><?php esc_html_e( 'Add Copy', 'my-calendar' ); ?></button> <?php mc_help_link( __( 'Help', 'my-calendar' ), __( 'Copy an event', 'my-calendar' ), 'copy an event', 4 ); ?>
1370
  </p>
1371
  <ol class="mc-repeat-events">
1372
  <li id="event1" class="datetime-template enabled">
1382
  ?>
1383
  </fieldset>
1384
  <div class="buttons">
1385
+ <button type="button" class="add_field button button-secondary"><span class="dashicons dashicons-plus" aria-hidden="true"></span><?php esc_html_e( 'Add Copy', 'my-calendar' ); ?></button> <?php mc_help_link( __( 'Help', 'my-calendar' ), __( 'Copy an event', 'my-calendar' ), 'copy an event', '1' ); ?>
1386
  </div>
1387
  </li>
1388
  </ol>
1492
  </div>
1493
  <?php
1494
  }
1495
+ if ( current_user_can( 'mc_edit_templates' ) || current_user_can( 'manage_options' ) ) {
1496
+ ?>
1497
  <div class="postbox">
1498
  <h2><?php esc_html_e( 'Preview Template Output', 'my-calendar' ); ?></h2>
1499
  <div class="inside">
1526
  </div>
1527
  </div>
1528
  </div>
1529
+ <?php
1530
+ }
1531
  }
1532
  ?>
1533
  </div>
1879
  $event_access = $location->location_access;
1880
  }
1881
  } else {
1882
+ $event_label = ! empty( $post['event_label'] ) ? $post['event_label'] : '';
1883
+ $event_street = ! empty( $post['event_street'] ) ? $post['event_street'] : '';
1884
+ $event_street2 = ! empty( $post['event_street2'] ) ? $post['event_street2'] : '';
1885
+ $event_city = ! empty( $post['event_city'] ) ? $post['event_city'] : '';
1886
+ $event_state = ! empty( $post['event_state'] ) ? $post['event_state'] : '';
1887
+ $event_postcode = ! empty( $post['event_postcode'] ) ? $post['event_postcode'] : '';
1888
+ $event_region = ! empty( $post['event_region'] ) ? $post['event_region'] : '';
1889
+ $event_country = ! empty( $post['event_country'] ) ? $post['event_country'] : '';
1890
+ $event_url = ! empty( $post['event_url'] ) ? $post['event_url'] : '';
1891
+ $event_longitude = ! empty( $post['event_longitude'] ) ? $post['event_longitude'] : '';
1892
+ $event_latitude = ! empty( $post['event_latitude'] ) ? $post['event_latitude'] : '';
1893
+ $event_zoom = ! empty( $post['event_zoom'] ) ? $post['event_zoom'] : '';
1894
+ $event_phone = ! empty( $post['event_phone'] ) ? $post['event_phone'] : '';
1895
+ $event_phone2 = ! empty( $post['event_phone2'] ) ? $post['event_phone2'] : '';
1896
+ $event_access = ! empty( $post['event_access'] ) ? $post['event_access'] : '';
1897
+ $event_access = ! empty( $post['event_access_hidden'] ) ? unserialize( $post['event_access_hidden'] ) : $event_access;
1898
+ $has_location_data = false;
1899
+
1900
+ if ( '' !== trim( $event_label . $event_street . $event_street2 . $event_city . $event_state . $event_postcode . $event_region . $event_country . $event_url . $event_longitude . $event_latitude . $event_zoom . $event_phone . $event_phone2 . $event_access ) ) {
1901
+ $has_location_data = true;
1902
+ }
1903
+ if ( $has_location_data && isset( $post['mc_copy_location'] ) && 'on' === $post['mc_copy_location'] && 0 === $i ) {
1904
  // Only add this with the first event, if adding multiples.
1905
  $add_loc = array(
1906
  'location_label' => $event_label,
2697
  $orig_begin = $post_begin . ' ' . $post_time;
2698
  $orig_end = $post_end . ' ' . $post_endtime;
2699
  }
2700
+ // Calculate time offset for date and time.
2701
+ $begin_diff = strtotime( gmdate( 'Y-m-d H:i:s', strtotime( $orig_begin ) ) ) - strtotime( gmdate( 'Y-m-d', strtotime( $orig_begin ) ) );
2702
+ $end_diff = strtotime( gmdate( 'Y-m-d H:i:s', strtotime( $orig_end ) ) ) - strtotime( gmdate( 'Y-m-d', strtotime( $orig_end ) ) );
2703
 
2704
  $group_id = $event->event_group_id;
2705
  $format = array( '%d', '%s', '%s', '%d' );
2761
  // Every = $every = e.g. every 14 weekdays.
2762
  // Num forward = $numforward = e.g. 7 times.
2763
  for ( $i = 0; $i <= $numforward; $i ++ ) {
2764
+ $begin = strtotime( $orig_begin . ' ' . ( $every * $i ) . ' weekdays' ) + $begin_diff;
2765
+ $end = strtotime( $orig_end . ' ' . ( $every * $i ) . ' weekdays' ) + $end_diff;
2766
  $data = array(
2767
  'occur_event_id' => $id,
2768
  'occur_begin' => mc_date( 'Y-m-d H:i:s', $begin, false ),
my-calendar-event-manager.php CHANGED
@@ -318,6 +318,10 @@ function my_calendar_manage() {
318
  'below' => 'categories,locations,access',
319
  'above' => 'nav,jump,search',
320
  );
 
 
 
 
321
  echo my_calendar( $calendar );
322
  } else {
323
  mc_list_events();
@@ -630,7 +634,7 @@ function mc_list_events() {
630
  $event = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM ' . my_calendar_table() . ' WHERE event_id = %d', $e->event_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
631
  $invalid = true;
632
  }
633
- $class = ( $invalid ) ? 'invalid' : $class;
634
  $pending = ( 0 === (int) $event->event_approved ) ? 'pending' : '';
635
  $trashed = ( 2 === (int) $event->event_approved ) ? 'trashed' : '';
636
  $author = ( 0 !== (int) $event->event_author ) ? get_userdata( $event->event_author ) : 'Public Submitter';
@@ -752,10 +756,14 @@ function mc_list_events() {
752
  </td>
753
  <td>
754
  <?php
755
- if ( '' !== $event->event_label ) {
756
- $elabel = urlencode( $event->event_label );
 
 
 
 
757
  ?>
758
- <a class='mc_filter' href='<?php echo esc_url( mc_admin_url( "admin.php?page=my-calendar-manage&amp;filter=$elabel&amp;restrict=where" ) ); ?>'><span class="screen-reader-text"><?php esc_html_e( 'Show only: ', 'my-calendar' ); ?></span><?php echo esc_html( stripslashes( $event->event_label ) ); ?></a>
759
  <?php
760
  }
761
  ?>
318
  'below' => 'categories,locations,access',
319
  'above' => 'nav,jump,search',
320
  );
321
+ if ( mc_count_locations() > 200 ) {
322
+ $calendar['below'] = 'categories,access';
323
+ }
324
+ apply_filters( 'mc_filter_admin_grid_args', $calendar );
325
  echo my_calendar( $calendar );
326
  } else {
327
  mc_list_events();
634
  $event = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM ' . my_calendar_table() . ' WHERE event_id = %d', $e->event_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
635
  $invalid = true;
636
  }
637
+ $class = ( $invalid ) ? 'invalid' : '';
638
  $pending = ( 0 === (int) $event->event_approved ) ? 'pending' : '';
639
  $trashed = ( 2 === (int) $event->event_approved ) ? 'trashed' : '';
640
  $author = ( 0 !== (int) $event->event_author ) ? get_userdata( $event->event_author ) : 'Public Submitter';
756
  </td>
757
  <td>
758
  <?php
759
+ if ( property_exists( $event, 'location' ) && is_object( $event->location ) ) {
760
+ $elabel = $event->location->location_label;
761
+ } else {
762
+ $elabel = $event->event_label;
763
+ }
764
+ if ( '' !== $elabel ) {
765
  ?>
766
+ <a class='mc_filter' href='<?php echo esc_url( mc_admin_url( 'admin.php?page=my-calendar-manage&amp;filter=' . urlencode( $elabel ) . '&amp;restrict=where' ) ); ?>'><span class="screen-reader-text"><?php esc_html_e( 'Show only: ', 'my-calendar' ); ?></span><?php echo esc_html( stripslashes( $elabel ) ); ?></a>
767
  <?php
768
  }
769
  ?>
my-calendar-events.php CHANGED
@@ -74,13 +74,13 @@ function mc_ts( $test = false ) {
74
  * @return string
75
  */
76
  $offset = apply_filters( 'mc_filter_offset', $offset );
77
- if ( $test ) {
78
- return $offset;
79
- }
80
  $offset = substr( $offset, 0, -3 );
81
  if ( strpos( $offset, '-' ) !== 0 ) {
82
  $offset = '+' . $offset;
83
  }
 
 
 
84
  $wp_time = get_option( 'gmt_offset', '0' );
85
  $wp_time = ( $wp_time < 0 ) ? '-' . str_pad( absint( $wp_time ), 2, 0, STR_PAD_LEFT ) : '+' . str_pad( $wp_time, 2, 0, STR_PAD_LEFT );
86
  $wp_time .= ':00';
@@ -923,7 +923,7 @@ function mc_instance_list( $args ) {
923
  } elseif ( mc_key_exists( $template ) ) {
924
  $template = mc_get_custom_template( $template );
925
  } else {
926
- $details = my_calendar_draw_event( $event, 'single', $event->event_begin, $event->event_time, '' );
927
  }
928
  }
929
  $item = ( '' !== $list ) ? mc_draw_template( $array, $list ) : '';
@@ -963,8 +963,8 @@ function mc_admin_instances( $id, $occur = false ) {
963
  $count = count( $results );
964
  if ( is_array( $results ) && is_admin() ) {
965
  foreach ( $results as $result ) {
966
- $start = strtotime( $result->occur_begin );
967
- $end = strtotime( $result->occur_end );
968
  if ( ( ( $end + 1 ) - $start ) === DAY_IN_SECONDS || ( $end - $start ) === DAY_IN_SECONDS ) {
969
  $time = '';
970
  } elseif ( ( $end - $start ) <= HOUR_IN_SECONDS ) {
@@ -972,7 +972,7 @@ function mc_admin_instances( $id, $occur = false ) {
972
  } else {
973
  $time = mc_date( get_option( 'mc_time_format' ), $start ) . '-' . mc_date( get_option( 'mc_time_format' ), $end );
974
  }
975
- $date = date_i18n( mc_date_format(), $start );
976
  $date = "<span id='occur_date_$result->occur_id'>" . $date . '<br />' . $time . '</span>';
977
  $class = '';
978
  if ( (int) $result->occur_id === (int) $occur || 1 === $count ) {
@@ -1031,29 +1031,30 @@ function mc_adjacent_event( $mc_id, $adjacent = 'previous' ) {
1031
  $exclude_categories = mc_private_categories();
1032
  $ts_string = mc_ts();
1033
  $source = mc_get_event( $mc_id );
1034
- $date = mc_date( 'Y-m-d H:i:s', strtotime( $source->occur_begin ), false );
1035
- $now = $date;
 
 
 
 
 
 
 
 
 
1036
 
1037
- $event_query = 'SELECT *, ' . $ts_string . '
1038
- FROM ' . my_calendar_event_table( $site ) . '
1039
- JOIN ' . my_calendar_table( $site ) . ' AS e
1040
- ON (event_id=occur_event_id)
1041
- JOIN ' . my_calendar_categories_table( $site ) . " as c
1042
- ON (e.event_category=c.category_id)
1043
- WHERE $select_published $exclude_categories
1044
- AND occur_begin $adjacence CAST('$now' as DATETIME) ORDER BY occur_begin $order LIMIT 0,1";
1045
-
1046
- $events = $mcdb->get_results( $event_query );
1047
- if ( ! empty( $events ) ) {
1048
- foreach ( array_keys( $events ) as $key ) {
1049
- $event =& $events[ $key ];
1050
- $arr_events[] = $event;
1051
  }
1052
- }
1053
- if ( ! empty( $arr_events ) ) {
1054
- $return = mc_create_tags( $arr_events[0] );
1055
- } else {
1056
- $return = array();
1057
  }
1058
 
1059
  return $return;
74
  * @return string
75
  */
76
  $offset = apply_filters( 'mc_filter_offset', $offset );
 
 
 
77
  $offset = substr( $offset, 0, -3 );
78
  if ( strpos( $offset, '-' ) !== 0 ) {
79
  $offset = '+' . $offset;
80
  }
81
+ if ( $test ) {
82
+ return $offset;
83
+ }
84
  $wp_time = get_option( 'gmt_offset', '0' );
85
  $wp_time = ( $wp_time < 0 ) ? '-' . str_pad( absint( $wp_time ), 2, 0, STR_PAD_LEFT ) : '+' . str_pad( $wp_time, 2, 0, STR_PAD_LEFT );
86
  $wp_time .= ':00';
923
  } elseif ( mc_key_exists( $template ) ) {
924
  $template = mc_get_custom_template( $template );
925
  } else {
926
+ $details = my_calendar_draw_event( $event, 'single', $event->event_begin, $event->event_time, '', '', $array );
927
  }
928
  }
929
  $item = ( '' !== $list ) ? mc_draw_template( $array, $list ) : '';
963
  $count = count( $results );
964
  if ( is_array( $results ) && is_admin() ) {
965
  foreach ( $results as $result ) {
966
+ $start = $result->ts_occur_begin;
967
+ $end = $result->ts_occur_end;
968
  if ( ( ( $end + 1 ) - $start ) === DAY_IN_SECONDS || ( $end - $start ) === DAY_IN_SECONDS ) {
969
  $time = '';
970
  } elseif ( ( $end - $start ) <= HOUR_IN_SECONDS ) {
972
  } else {
973
  $time = mc_date( get_option( 'mc_time_format' ), $start ) . '-' . mc_date( get_option( 'mc_time_format' ), $end );
974
  }
975
+ $date = date_i18n( mc_date_format(), mc_date( '', $start ) );
976
  $date = "<span id='occur_date_$result->occur_id'>" . $date . '<br />' . $time . '</span>';
977
  $class = '';
978
  if ( (int) $result->occur_id === (int) $occur || 1 === $count ) {
1031
  $exclude_categories = mc_private_categories();
1032
  $ts_string = mc_ts();
1033
  $source = mc_get_event( $mc_id );
1034
+ $return = array();
1035
+ if ( is_object( $source ) ) {
1036
+ $date = mc_date( 'Y-m-d H:i:s', strtotime( $source->occur_begin ), false );
1037
+ $event_query = 'SELECT *, ' . $ts_string . '
1038
+ FROM ' . my_calendar_event_table( $site ) . '
1039
+ JOIN ' . my_calendar_table( $site ) . ' AS e
1040
+ ON (event_id=occur_event_id)
1041
+ JOIN ' . my_calendar_categories_table( $site ) . " as c
1042
+ ON (e.event_category=c.category_id)
1043
+ WHERE $select_published $exclude_categories
1044
+ AND occur_begin $adjacence CAST('$date' as DATETIME) ORDER BY occur_begin $order LIMIT 0,1";
1045
 
1046
+ $events = $mcdb->get_results( $event_query );
1047
+ if ( ! empty( $events ) ) {
1048
+ foreach ( array_keys( $events ) as $key ) {
1049
+ $event =& $events[ $key ];
1050
+ $arr_events[] = $event;
1051
+ }
1052
+ }
1053
+ if ( ! empty( $arr_events ) ) {
1054
+ $return = mc_create_tags( $arr_events[0] );
1055
+ } else {
1056
+ $return = array();
 
 
 
1057
  }
 
 
 
 
 
1058
  }
1059
 
1060
  return $return;
my-calendar-help.php CHANGED
@@ -154,13 +154,14 @@ function my_calendar_help() {
154
  *
155
  * @param string $link_text Link text.
156
  * @param string $modal_title Modal iframe title.
 
157
  * @param int $id Help text ID.
158
  * @param bool $echo true to echo.
159
  *
160
  * @return string
161
  */
162
- function mc_help_link( $link_text, $modal_title, $id, $echo = true ) {
163
- $url = esc_url( admin_url( 'admin.php?help=' . (int) $id . '&query=' . urlencode( $modal_title ) . '&page=mc-contextual-help&TB_iframe=true&width=600&height=550&modal_window=true' ) );
164
  $link = sprintf(
165
  '<a href="%s" class="thickbox my-calendar-contextual-help" data-title="%s"><span class="dashicons dashicons-editor-help" aria-hidden="true"></span><span class="screen-reader-text">%s</span></a>',
166
  $url,
@@ -200,7 +201,7 @@ function mc_print_contextual_help() {
200
  <?php
201
  echo wp_kses( mc_get_help_text( $id ), mc_kses_elements() );
202
  $return_url = add_query_arg( 's', $query, 'https://docs.joedolson.com/my-calendar/' );
203
- $return = wp_kses_post( '<p class="docs-link"><a href="' . esc_url( $return_url ) . '">' . __( 'Documentation', 'my-calendar' ) . '</a></p>' );
204
  echo wp_kses_post( mc_get_help_footer( $return ) );
205
  ?>
206
  </div>
@@ -228,7 +229,7 @@ function mc_get_help_footer( $return = '' ) {
228
  $return = '
229
  <ul class="help">
230
  <li>
231
- <a href="https://docs.joedolson.com/my-calendar/quick-start/">' . __( 'Documentation', 'my-calendar' ) . '</a>
232
  </li>
233
  <li>
234
  <a href="' . admin_url( 'admin.php?page=my-calendar-shortcodes' ) . '">' . __( 'Shortcode Generator', 'my-calendar' ) . '</a>
@@ -252,7 +253,7 @@ function mc_get_help_footer( $return = '' ) {
252
  </li>
253
  <li>
254
  <div class="dashicons dashicons-translation" aria-hidden="true"></div>
255
- <a href="http://translate.joedolson.com/projects/my-calendar">' . __( 'Help translate this plugin!', 'my-calendar' ) . '</a>
256
  </li>
257
  </ul>';
258
  }
@@ -309,7 +310,7 @@ function mc_get_help_text( $id ) {
309
  */
310
  function mc_display_icons() {
311
  $is_custom = mc_is_custom_icon();
312
- $output = get_transient( 'my_calendar_svg_list' );
313
  if ( ! $output ) {
314
  if ( $is_custom ) {
315
  $dir = plugin_dir_path( __FILE__ );
@@ -325,9 +326,10 @@ function mc_display_icons() {
325
  $img = mc_get_img( $icon, $is_custom );
326
  $output .= '<li class="category-icon"><code>' . $icon . '</code>' . $img . '</li>';
327
  }
328
- $output .= '</ul><p><a href="https://fontawesome.com/license">' . __( 'Icons by Font Awesome', 'my-calendar' ) . '</a></p>';
329
- set_transient( 'my_calendar_svg_list', $output, MONTH_IN_SECONDS );
330
  }
 
331
 
332
- return $output;
333
  }
154
  *
155
  * @param string $link_text Link text.
156
  * @param string $modal_title Modal iframe title.
157
+ * @param string $query Non-translatable version of modal title for search query.
158
  * @param int $id Help text ID.
159
  * @param bool $echo true to echo.
160
  *
161
  * @return string
162
  */
163
+ function mc_help_link( $link_text, $modal_title, $query, $id, $echo = true ) {
164
+ $url = esc_url( admin_url( 'admin.php?help=' . (int) $id . '&query=' . urlencode( $query ) . '&page=mc-contextual-help&TB_iframe=true&width=600&height=550&modal_window=true' ) );
165
  $link = sprintf(
166
  '<a href="%s" class="thickbox my-calendar-contextual-help" data-title="%s"><span class="dashicons dashicons-editor-help" aria-hidden="true"></span><span class="screen-reader-text">%s</span></a>',
167
  $url,
201
  <?php
202
  echo wp_kses( mc_get_help_text( $id ), mc_kses_elements() );
203
  $return_url = add_query_arg( 's', $query, 'https://docs.joedolson.com/my-calendar/' );
204
+ $return = wp_kses_post( '<p class="docs-link"><a target="_parent" href="' . esc_url( $return_url ) . '">' . __( 'Documentation', 'my-calendar' ) . '</a></p>' );
205
  echo wp_kses_post( mc_get_help_footer( $return ) );
206
  ?>
207
  </div>
229
  $return = '
230
  <ul class="help">
231
  <li>
232
+ <a href="https://docs.joedolson.com/my-calendar/">' . __( 'Documentation', 'my-calendar' ) . '</a>
233
  </li>
234
  <li>
235
  <a href="' . admin_url( 'admin.php?page=my-calendar-shortcodes' ) . '">' . __( 'Shortcode Generator', 'my-calendar' ) . '</a>
253
  </li>
254
  <li>
255
  <div class="dashicons dashicons-translation" aria-hidden="true"></div>
256
+ <a href="https://translate.wordpress.org/projects/wp-plugins/my-calendar/">' . __( 'Help translate this plugin!', 'my-calendar' ) . '</a>
257
  </li>
258
  </ul>';
259
  }
310
  */
311
  function mc_display_icons() {
312
  $is_custom = mc_is_custom_icon();
313
+ $output = get_transient( 'mc_svg_list' );
314
  if ( ! $output ) {
315
  if ( $is_custom ) {
316
  $dir = plugin_dir_path( __FILE__ );
326
  $img = mc_get_img( $icon, $is_custom );
327
  $output .= '<li class="category-icon"><code>' . $icon . '</code>' . $img . '</li>';
328
  }
329
+ $output .= '</ul>';
330
+ set_transient( 'mc_svg_list', $output, MONTH_IN_SECONDS );
331
  }
332
+ $append = ( $is_custom ) ? '' : '<p><a target="_parent" href="https://fontawesome.com/license">' . __( 'Icons by Font Awesome', 'my-calendar' ) . '</a></p>';
333
 
334
+ return $output . $append;
335
  }
my-calendar-location-manager.php CHANGED
@@ -261,14 +261,14 @@ function mc_manage_locations() {
261
  $default_location = get_option( 'mc_default_location', '' );
262
  if ( $default_location ) {
263
  $default = mc_get_location( $default_location );
264
- echo wp_kses_post( mc_location_manager_row( $default ) );
265
  }
266
  foreach ( $locations as $loc ) {
267
  if ( (int) $default_location === (int) $loc->location_id ) {
268
  continue;
269
  }
270
  $location = mc_get_location( $loc->location_id );
271
- echo wp_kses_post( mc_location_manager_row( $location ) );
272
  }
273
  ?>
274
  </tbody>
@@ -288,6 +288,31 @@ function mc_manage_locations() {
288
  }
289
  }
290
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
  /**
292
  * Generate the location manager row for a location.
293
  *
@@ -296,7 +321,12 @@ function mc_manage_locations() {
296
  * @return string
297
  */
298
  function mc_location_manager_row( $location ) {
299
- $card = mc_hcard( $location, 'true', 'false', 'location' );
 
 
 
 
 
300
  if ( (int) get_option( 'mc_default_location' ) === (int) $location->location_id ) {
301
  $card = str_replace( '</strong>', ' ' . __( '(Default)', 'my-calendar' ) . '</strong>', $card );
302
  $default = '<span class="mc_default">' . __( 'Default Location', 'my-calendar' ) . '</span>';
261
  $default_location = get_option( 'mc_default_location', '' );
262
  if ( $default_location ) {
263
  $default = mc_get_location( $default_location );
264
+ echo wp_kses( mc_location_manager_row( $default ), mc_kses_elements() );
265
  }
266
  foreach ( $locations as $loc ) {
267
  if ( (int) $default_location === (int) $loc->location_id ) {
268
  continue;
269
  }
270
  $location = mc_get_location( $loc->location_id );
271
+ echo wp_kses( mc_location_manager_row( $location ), mc_kses_elements() );
272
  }
273
  ?>
274
  </tbody>
288
  }
289
  }
290
 
291
+ /**
292
+ * Verify that a location has valid fields. If a location has no valid data, delete it.
293
+ *
294
+ * @param object $location Location object.
295
+ *
296
+ * @return bool
297
+ */
298
+ function mc_verify_location( $location ) {
299
+ $location_id = $location->location_id;
300
+ // Unset location ID and location Post, which will always exist.
301
+ $location->location_id = '';
302
+ $location->location_post = '';
303
+ $json = json_encode( $location );
304
+ if ( '{"location_id":"","location_label":"","location_street":"","location_street2":"","location_city":"","location_state":"","location_postcode":"","location_region":"","location_url":"","location_country":"","location_longitude":"0.000000","location_latitude":"0.000000","location_zoom":"16","location_phone":"","location_phone2":"","location_access":"","location_post":""}' === $json ) {
305
+ if ( $location_id ) {
306
+ mc_delete_location( $location_id );
307
+ mc_location_delete_post( true, $location_id );
308
+ }
309
+
310
+ return false;
311
+ }
312
+
313
+ return true;
314
+ }
315
+
316
  /**
317
  * Generate the location manager row for a location.
318
  *
321
  * @return string
322
  */
323
  function mc_location_manager_row( $location ) {
324
+ $card = mc_hcard( $location, 'true', 'false', 'location' );
325
+ $verify = mc_verify_location( $location );
326
+ if ( ! $verify ) {
327
+ return '';
328
+ }
329
+
330
  if ( (int) get_option( 'mc_default_location' ) === (int) $location->location_id ) {
331
  $card = str_replace( '</strong>', ' ' . __( '(Default)', 'my-calendar' ) . '</strong>', $card );
332
  $default = '<span class="mc_default">' . __( 'Default Location', 'my-calendar' ) . '</span>';
my-calendar-locations.php CHANGED
@@ -318,12 +318,13 @@ function mc_modify_location( $update, $where ) {
318
  */
319
  function mc_delete_location( $location ) {
320
  global $wpdb;
321
- $results = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . my_calendar_locations_table() . ' WHERE location_id=%d', $_GET['location_id'] ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
322
- do_action( 'mc_delete_location', $results, (int) $_GET['location_id'] );
 
323
  if ( $results ) {
324
  $return = mc_show_notice( __( 'Location deleted successfully', 'my-calendar' ), false );
325
  $default_location = get_option( 'mc_default_location', false );
326
- if ( (int) $default_location === (int) $_GET['location_id'] ) {
327
  delete_option( 'mc_default_location' );
328
  }
329
  } else {
@@ -1225,6 +1226,7 @@ function mc_display_location_details( $content ) {
1225
  'before' => 0,
1226
  'fallback' => __( 'No events currently scheduled at this location.', 'my-calendar' ),
1227
  );
 
1228
  $events = my_calendar_upcoming_events( $args );
1229
  $content = '
1230
  <div class="mc-view-location">
318
  */
319
  function mc_delete_location( $location ) {
320
  global $wpdb;
321
+ $location = (int) ( isset( $_GET['location_id'] ) ) ? $_GET['location_id'] : $location;
322
+ $results = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . my_calendar_locations_table() . ' WHERE location_id=%d', $location ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
323
+ do_action( 'mc_delete_location', $results, $location );
324
  if ( $results ) {
325
  $return = mc_show_notice( __( 'Location deleted successfully', 'my-calendar' ), false );
326
  $default_location = get_option( 'mc_default_location', false );
327
+ if ( (int) $default_location === $location ) {
328
  delete_option( 'mc_default_location' );
329
  }
330
  } else {
1226
  'before' => 0,
1227
  'fallback' => __( 'No events currently scheduled at this location.', 'my-calendar' ),
1228
  );
1229
+ $args = apply_filters( 'mc_display_location_events', $args, $location );
1230
  $events = my_calendar_upcoming_events( $args );
1231
  $content = '
1232
  <div class="mc-view-location">
my-calendar-navigation.php CHANGED
@@ -332,7 +332,8 @@ function mc_category_key( $category ) {
332
  if ( '' !== $cat->category_icon && $has_icons ) {
333
  $image = mc_category_icon( $cat );
334
  $type = ( stripos( $image, 'svg' ) ) ? 'svg' : 'img';
335
- $cat_key .= '<span class="category-color-sample ' . $type . '">' . $image . '</span>' . $cat_name;
 
336
  } elseif ( 'default' !== get_option( 'mc_apply_color' ) ) {
337
  $cat_key .= ( ( '' !== $cat->category_color ) ? '<span class="category-color-sample no-icon" style="background:' . $hex . $cat->category_color . ';"> &nbsp; </span>' : '' ) . $cat_name;
338
  } else {
@@ -858,7 +859,9 @@ function mc_date_switcher( $type = 'calendar', $cid = 'all', $time = 'month', $d
858
  }
859
  $date_switcher .= '</select>' . "\n" . $day_switcher . ' <label class="maybe-hide" for="' . $cid . '-year">' . __( 'Year', 'my-calendar' ) . '</label> <select id="' . $cid . '-year" name="yr">' . "\n";
860
  // Query to identify oldest start date in the database.
861
- $year1 = mc_date( 'Y', strtotime( $mcdb->get_var( 'SELECT event_begin FROM ' . my_calendar_table() . ' WHERE event_approved = 1 AND event_flagged <> 1 ORDER BY event_begin ASC LIMIT 0 , 1' ), false ) );
 
 
862
  $diff1 = mc_date( 'Y' ) - $year1;
863
  $past = $diff1;
864
  $future = apply_filters( 'mc_jumpbox_future_years', 5, $cid );
332
  if ( '' !== $cat->category_icon && $has_icons ) {
333
  $image = mc_category_icon( $cat );
334
  $type = ( stripos( $image, 'svg' ) ) ? 'svg' : 'img';
335
+ $back = ( 'default' !== get_option( 'mc_apply_color' ) ) ? ' style="background:' . $hex . $cat->category_color . ';"' : '';
336
+ $cat_key .= '<span class="category-color-sample ' . $type . '"' . $back . '>' . $image . '</span>' . $cat_name;
337
  } elseif ( 'default' !== get_option( 'mc_apply_color' ) ) {
338
  $cat_key .= ( ( '' !== $cat->category_color ) ? '<span class="category-color-sample no-icon" style="background:' . $hex . $cat->category_color . ';"> &nbsp; </span>' : '' ) . $cat_name;
339
  } else {
859
  }
860
  $date_switcher .= '</select>' . "\n" . $day_switcher . ' <label class="maybe-hide" for="' . $cid . '-year">' . __( 'Year', 'my-calendar' ) . '</label> <select id="' . $cid . '-year" name="yr">' . "\n";
861
  // Query to identify oldest start date in the database.
862
+ $first = $mcdb->get_var( 'SELECT event_begin FROM ' . my_calendar_table() . ' WHERE event_approved = 1 AND event_flagged <> 1 ORDER BY event_begin ASC LIMIT 0 , 1' );
863
+ $first = ( '1970-01-01' === $first ) ? '2000-01-01' : $first;
864
+ $year1 = mc_date( 'Y', strtotime( $first, false ) );
865
  $diff1 = mc_date( 'Y' ) - $year1;
866
  $past = $diff1;
867
  $future = apply_filters( 'mc_jumpbox_future_years', 5, $cid );
my-calendar-output.php CHANGED
@@ -108,8 +108,9 @@ function my_calendar_draw_events( $events, $params, $process_date, $template = '
108
  $check = '';
109
  }
110
  if ( '' === $check ) {
111
- $output_array[] = my_calendar_draw_event( $event, $type, $process_date, $time, $template, $id );
112
- $json = mc_event_schema( $event );
 
113
  }
114
  }
115
  if ( is_array( $output_array ) ) {
@@ -144,10 +145,11 @@ function my_calendar_draw_events( $events, $params, $process_date, $template = '
144
  * @param string $time Time view being drawn.
145
  * @param string $template Template to use to draw event.
146
  * @param string $id ID for the calendar calling this function.
 
147
  *
148
  * @return string Generated HTML.
149
  */
150
- function my_calendar_draw_event( $event, $type, $process_date, $time, $template = '', $id = '' ) {
151
  $exit_early = mc_exit_early( $event, $process_date );
152
  if ( $exit_early ) {
153
  return '';
@@ -172,8 +174,8 @@ function my_calendar_draw_event( $event, $type, $process_date, $time, $template
172
  $access = '';
173
  $image = '';
174
  $tickets = '';
175
- $data = mc_create_tags( $event, $id );
176
  $details = '';
 
177
  $otype = ( 'calendar' === $type ) ? 'grid' : $type;
178
 
179
  if ( mc_show_details( $time, $type ) ) {
@@ -301,8 +303,7 @@ function my_calendar_draw_event( $event, $type, $process_date, $time, $template
301
  }
302
  }
303
  }
304
-
305
- if ( ( 'false' !== $display_more && ! isset( $_GET['mc_id'] ) ) || mc_output_is_visible( 'more', $type, $event ) ) {
306
  $details_label = mc_get_details_label( $event, $data );
307
  $details_link = mc_get_details_link( $event );
308
  // Translators: Event title.
@@ -387,7 +388,7 @@ function my_calendar_draw_event( $event, $type, $process_date, $time, $template
387
  }
388
  $event_link = mc_event_link( $event );
389
 
390
- if ( '' !== $event_link && ( 'false' !== $display_link || mc_output_is_visible( 'link', $type, $event ) ) ) {
391
  $external_class = ( mc_external_link( $event_link ) ) ? "$type-link external url" : "$type-link url";
392
  $link_template = ( '' !== mc_get_template( 'link' ) ) ? mc_get_template( 'link' ) : __( 'More information', 'my-calendar' );
393
  $link_text = mc_draw_template( $data, $link_template );
@@ -618,8 +619,9 @@ function mc_event_classes( $event, $type ) {
618
  $date_relation = 'future-event';
619
  break;
620
  }
621
- $primary = 'mc_primary_' . sanitize_title( mc_get_category_detail( $event->event_category, 'category_name' ) );
622
-
 
623
  $is_recurring = ( mc_is_recurring( $event ) ) ? 'recurring' : 'nonrecurring';
624
 
625
  $classes = array(
@@ -629,6 +631,8 @@ function mc_event_classes( $event, $type ) {
629
  $date_relation,
630
  $primary,
631
  $is_recurring,
 
 
632
  );
633
 
634
  if ( $event->event_begin !== $event->event_end ) {
@@ -696,7 +700,7 @@ function mc_edit_panel( $html, $event, $type, $time ) {
696
  if ( 'S' === $recur ) {
697
  $edit .= "<a href='" . admin_url( "admin.php?page=my-calendar&amp;mode=edit&amp;event_id=$event->event_id&amp;ref=$referer" ) . "' class='edit'>" . __( 'Edit', 'my-calendar' ) . "</a> &bull; <a href='" . admin_url( "admin.php?page=my-calendar&amp;mode=delete&amp;event_id=$event->event_id&amp;ref=$referer" ) . "' class='delete'>" . __( 'Delete', 'my-calendar' ) . "</a>$groupedit";
698
  } else {
699
- $edit .= "<a href='" . admin_url( "admin.php?page=my-calendar&amp;mode=edit&amp;event_id=$event->event_id&amp;date=$mc_id&amp;ref=$referer" ) . "' class='edit'>" . __( 'Edit This Date', 'my-calendar' ) . "</a> &bull; <a href='" . admin_url( "admin.php?page=my-calendar&amp;mode=edit&amp;event_id=$event->event_id&amp;ref=$referer" ) . "' class='edit'>" . __( 'Edit All', 'my-calendar' ) . "</a> &bull; <a href='" . admin_url( "admin.php?page=my-calendar&amp;mode=delete&amp;event_id=$event->event_id&amp;date=$mc_id&amp;ref=$referer" ) . "' class='delete'>" . __( 'Delete This Date', 'my-calendar' ) . "</a> &bull; <a href='" . admin_url( "admin.php?page=my-calendar&amp;mode=delete&amp;event_id=$event->event_id&amp;ref=$referer" ) . "' class='delete'>" . __( 'Delete All', 'my-calendar' ) . "</a>
700
  $groupedit";
701
  }
702
  $edit .= '</p></div>';
@@ -757,9 +761,8 @@ function mc_events_class( $events, $date = false ) {
757
  function mc_list_title( $events ) {
758
  usort( $events, 'mc_time_cmp' );
759
  $now = $events[0];
760
- $event = mc_create_tags( $now );
761
  $count = count( $events ) - 1;
762
- $event_title = apply_filters( 'mc_list_title_title', strip_tags( stripcslashes( $event['title'] ), mc_strip_tags() ), $now );
763
  if ( 0 === $count ) {
764
  $cstate = $event_title;
765
  } elseif ( 1 === $count ) {
@@ -786,8 +789,7 @@ function mc_list_titles( $events ) {
786
  $titles = array();
787
 
788
  foreach ( $events as $now ) {
789
- $event = mc_create_tags( $now );
790
- $title = apply_filters( 'mc_list_event_title_hint', strip_tags( stripcslashes( $event['title'] ), mc_strip_tags() ), $now, $events );
791
  $titles[] = $title;
792
  }
793
 
@@ -1338,7 +1340,8 @@ function my_calendar( $args ) {
1338
  if ( 'week' !== $params['time'] && 'day' !== $params['time'] ) {
1339
  $heading = ( $months <= 1 ) ? $current_header . $caption_text . "\n" : $current_month_header . '&ndash;' . $through_month_header . $caption_text;
1340
  // Translators: time period displayed.
1341
- $heading = sprintf( __( 'Events in %s', 'my-calendar' ), $heading );
 
1342
  if ( isset( $_GET['searched'] ) && 1 === (int) $_GET['searched'] ) {
1343
  $heading = __( 'Search Results', 'my-calendar' );
1344
  }
@@ -1770,13 +1773,15 @@ function my_calendar_show_locations( $datatype = 'name', $template = '' ) {
1770
  // If no template provided, return hcard.
1771
  $datatype = ( '' === trim( $template ) ) ? 'hcard' : $datatype;
1772
  foreach ( $locations as $key => $value ) {
1773
- if ( 'hcard' !== $datatype && '' !== $template ) {
1774
- $label = stripslashes( $value->{$datatype} );
1775
- $url = mc_maplink( $value, 'url', 'location' );
1776
- $output .= ( $url ) ? "<li><a href='" . esc_url( $url ) . "'>$label</a></li>" : "<li>$label</li>";
1777
- } elseif ( 'hcard' === $datatype && '' === $template ) {
 
 
1778
  $label = mc_hcard( $value, 'true', 'true', 'location' );
1779
- $output .= "<li>$label</li>";
1780
  } elseif ( '' !== $template ) {
1781
  if ( mc_key_exists( $template ) ) {
1782
  $template = mc_get_custom_template( $template );
@@ -1799,7 +1804,7 @@ function my_calendar_show_locations( $datatype = 'name', $template = '' ) {
1799
  'phone2' => $value->location_phone2,
1800
  );
1801
  $label = mc_draw_template( $values, $template );
1802
- $output .= ( '' !== $label ) ? "<li>$label</li>" : '';
1803
  }
1804
  }
1805
  $output = '<ul class="mc-locations">' . $output . '</ul>';
108
  $check = '';
109
  }
110
  if ( '' === $check ) {
111
+ $tags = mc_create_tags( $event, $id );
112
+ $output_array[] = my_calendar_draw_event( $event, $type, $process_date, $time, $template, $id, $tags );
113
+ $json = mc_event_schema( $event, $tags );
114
  }
115
  }
116
  if ( is_array( $output_array ) ) {
145
  * @param string $time Time view being drawn.
146
  * @param string $template Template to use to draw event.
147
  * @param string $id ID for the calendar calling this function.
148
+ * @param array $tags Event tags array.
149
  *
150
  * @return string Generated HTML.
151
  */
152
+ function my_calendar_draw_event( $event, $type, $process_date, $time, $template = '', $id = '', $tags = array() ) {
153
  $exit_early = mc_exit_early( $event, $process_date );
154
  if ( $exit_early ) {
155
  return '';
174
  $access = '';
175
  $image = '';
176
  $tickets = '';
 
177
  $details = '';
178
+ $data = ( empty( $tags ) ) ? mc_create_tags( $event, $id ) : $tags;
179
  $otype = ( 'calendar' === $type ) ? 'grid' : $type;
180
 
181
  if ( mc_show_details( $time, $type ) ) {
303
  }
304
  }
305
  }
306
+ if ( ( 'true' === $display_more && ! isset( $_GET['mc_id'] ) ) || mc_output_is_visible( 'more', $type, $event ) ) {
 
307
  $details_label = mc_get_details_label( $event, $data );
308
  $details_link = mc_get_details_link( $event );
309
  // Translators: Event title.
388
  }
389
  $event_link = mc_event_link( $event );
390
 
391
+ if ( '' !== $event_link && ( 'true' === $display_link || mc_output_is_visible( 'link', $type, $event ) ) ) {
392
  $external_class = ( mc_external_link( $event_link ) ) ? "$type-link external url" : "$type-link url";
393
  $link_template = ( '' !== mc_get_template( 'link' ) ) ? mc_get_template( 'link' ) : __( 'More information', 'my-calendar' );
394
  $link_text = mc_draw_template( $data, $link_template );
619
  $date_relation = 'future-event';
620
  break;
621
  }
622
+ $primary = 'mc_primary_' . sanitize_title( mc_get_category_detail( $event->event_category, 'category_name' ) );
623
+ $length = sanitize_title( 'mc-' . mc_runtime( $event->ts_occur_begin, $event->ts_occur_end, $event ) );
624
+ $start = sanitize_title( 'mc-start-' . mc_date( 'H-i', $event->ts_occur_begin ) );
625
  $is_recurring = ( mc_is_recurring( $event ) ) ? 'recurring' : 'nonrecurring';
626
 
627
  $classes = array(
631
  $date_relation,
632
  $primary,
633
  $is_recurring,
634
+ $length,
635
+ $start,
636
  );
637
 
638
  if ( $event->event_begin !== $event->event_end ) {
700
  if ( 'S' === $recur ) {
701
  $edit .= "<a href='" . admin_url( "admin.php?page=my-calendar&amp;mode=edit&amp;event_id=$event->event_id&amp;ref=$referer" ) . "' class='edit'>" . __( 'Edit', 'my-calendar' ) . "</a> &bull; <a href='" . admin_url( "admin.php?page=my-calendar&amp;mode=delete&amp;event_id=$event->event_id&amp;ref=$referer" ) . "' class='delete'>" . __( 'Delete', 'my-calendar' ) . "</a>$groupedit";
702
  } else {
703
+ $edit .= "<a href='" . admin_url( "admin.php?page=my-calendar&amp;mode=edit&amp;event_id=$event->event_id&amp;date=$mc_id&amp;ref=$referer" ) . "' class='edit'>" . __( 'Edit This Date', 'my-calendar' ) . "</a> &bull; <a href='" . admin_url( "admin.php?page=my-calendar&amp;mode=edit&amp;event_id=$event->event_id&amp;ref=$referer" ) . "' class='edit'>" . __( 'Edit All', 'my-calendar' ) . "</a> &bull; <a href='" . admin_url( "admin.php?page=my-calendar-manage&amp;mode=delete&amp;event_id=$event->event_id&amp;date=$mc_id&amp;ref=$referer" ) . "' class='delete'>" . __( 'Delete This Date', 'my-calendar' ) . "</a> &bull; <a href='" . admin_url( "admin.php?page=my-calendar-manage&amp;mode=delete&amp;event_id=$event->event_id&amp;ref=$referer" ) . "' class='delete'>" . __( 'Delete All', 'my-calendar' ) . "</a>
704
  $groupedit";
705
  }
706
  $edit .= '</p></div>';
761
  function mc_list_title( $events ) {
762
  usort( $events, 'mc_time_cmp' );
763
  $now = $events[0];
 
764
  $count = count( $events ) - 1;
765
+ $event_title = apply_filters( 'mc_list_title_title', strip_tags( stripcslashes( $now->event_title ), mc_strip_tags() ), $now );
766
  if ( 0 === $count ) {
767
  $cstate = $event_title;
768
  } elseif ( 1 === $count ) {
789
  $titles = array();
790
 
791
  foreach ( $events as $now ) {
792
+ $title = apply_filters( 'mc_list_event_title_hint', strip_tags( stripcslashes( $now->event_title ), mc_strip_tags() ), $now, $events );
 
793
  $titles[] = $title;
794
  }
795
 
1340
  if ( 'week' !== $params['time'] && 'day' !== $params['time'] ) {
1341
  $heading = ( $months <= 1 ) ? $current_header . $caption_text . "\n" : $current_month_header . '&ndash;' . $through_month_header . $caption_text;
1342
  // Translators: time period displayed.
1343
+ $header = ( '' === get_option( 'mc_heading_text', '' ) ) ? __( 'Events in %s', 'my-calendar' ) : str_replace( '{date}', '%s', get_option( 'mc_heading_text' ) );
1344
+ $heading = sprintf( $header, $heading );
1345
  if ( isset( $_GET['searched'] ) && 1 === (int) $_GET['searched'] ) {
1346
  $heading = __( 'Search Results', 'my-calendar' );
1347
  }
1773
  // If no template provided, return hcard.
1774
  $datatype = ( '' === trim( $template ) ) ? 'hcard' : $datatype;
1775
  foreach ( $locations as $key => $value ) {
1776
+ if ( 'hcard' !== $datatype && '' === $template ) {
1777
+ $label = stripslashes( $value->{$datatype} );
1778
+ if ( $label ) {
1779
+ $url = mc_maplink( $value, 'url', 'location' );
1780
+ $output .= ( $url ) ? "<li><a href='" . esc_url( $url ) . "'>$label</a></li>" : "<li>$label</li>";
1781
+ }
1782
+ } elseif ( 'hcard' === $datatype || 'hcard' === $template ) {
1783
  $label = mc_hcard( $value, 'true', 'true', 'location' );
1784
+ $output .= ( $label ) ? "<li>$label</li>" : '';
1785
  } elseif ( '' !== $template ) {
1786
  if ( mc_key_exists( $template ) ) {
1787
  $template = mc_get_custom_template( $template );
1804
  'phone2' => $value->location_phone2,
1805
  );
1806
  $label = mc_draw_template( $values, $template );
1807
+ $output .= ( '' !== trim( $label ) ) ? "<li>$label</li>" : '';
1808
  }
1809
  }
1810
  $output = '<ul class="mc-locations">' . $output . '</ul>';
my-calendar-settings.php CHANGED
@@ -353,6 +353,7 @@ function mc_update_text_settings( $post ) {
353
  $mc_details_label = $post['mc_details_label'];
354
  $mc_link_label = $post['mc_link_label'];
355
  $mc_event_title_template = $post['mc_event_title_template'];
 
356
  $mc_notime_text = $post['mc_notime_text'];
357
  $mc_hosted_by = $post['mc_hosted_by'];
358
  $mc_posted_by = $post['mc_posted_by'];
@@ -371,6 +372,7 @@ function mc_update_text_settings( $post ) {
371
  $templates['link'] = $mc_link_label;
372
  update_option( 'mc_templates', $templates );
373
  update_option( 'mc_event_title_template', $mc_event_title_template );
 
374
  update_option( 'mc_notime_text', $mc_notime_text );
375
  update_option( 'mc_hosted_by', $mc_hosted_by );
376
  update_option( 'mc_posted_by', $mc_posted_by );
@@ -719,6 +721,19 @@ function mc_remote_db() {
719
  );
720
  ?>
721
  </li>
 
 
 
 
 
 
 
 
 
 
 
 
 
722
  <li><?php mc_settings_field( 'mc_caption', __( 'Extended caption:', 'my-calendar' ), '', __( 'Follows month/year in calendar heading.', 'my-calendar' ) ); ?></li>
723
  </ul>
724
  </fieldset>
@@ -900,7 +915,7 @@ function mc_remote_db() {
900
  'description' => __( 'Description', 'my-calendar' ),
901
  'image' => __( 'Featured Image', 'my-calendar' ),
902
  'tickets' => __( 'Registration Settings', 'my-calendar' ),
903
- 'link' => __( 'Read More Link', 'my-calendar' ),
904
  'access' => __( 'Accessibility', 'my-calendar' ),
905
  ),
906
  array( 'author', 'ical', 'address', 'gcal', 'description', 'image', 'tickets', 'access', 'link', 'gmap_link' ),
353
  $mc_details_label = $post['mc_details_label'];
354
  $mc_link_label = $post['mc_link_label'];
355
  $mc_event_title_template = $post['mc_event_title_template'];
356
+ $mc_heading_text = $post['mc_heading_text'];
357
  $mc_notime_text = $post['mc_notime_text'];
358
  $mc_hosted_by = $post['mc_hosted_by'];
359
  $mc_posted_by = $post['mc_posted_by'];
372
  $templates['link'] = $mc_link_label;
373
  update_option( 'mc_templates', $templates );
374
  update_option( 'mc_event_title_template', $mc_event_title_template );
375
+ update_option( 'mc_heading_text', $mc_heading_text );
376
  update_option( 'mc_notime_text', $mc_notime_text );
377
  update_option( 'mc_hosted_by', $mc_hosted_by );
378
  update_option( 'mc_posted_by', $mc_posted_by );
721
  );
722
  ?>
723
  </li>
724
+ <li>
725
+ <?php
726
+ mc_settings_field(
727
+ 'mc_heading_text',
728
+ __( 'Calendar month heading', 'my-calendar' ),
729
+ '',
730
+ __( 'Use <code>{date}</code> to display month/year in heading.', 'my-calendar' ),
731
+ array(
732
+ 'placeholder' => 'Events in {date}',
733
+ )
734
+ );
735
+ ?>
736
+ </li>
737
  <li><?php mc_settings_field( 'mc_caption', __( 'Extended caption:', 'my-calendar' ), '', __( 'Follows month/year in calendar heading.', 'my-calendar' ) ); ?></li>
738
  </ul>
739
  </fieldset>
915
  'description' => __( 'Description', 'my-calendar' ),
916
  'image' => __( 'Featured Image', 'my-calendar' ),
917
  'tickets' => __( 'Registration Settings', 'my-calendar' ),
918
+ 'link' => __( 'More Information', 'my-calendar' ),
919
  'access' => __( 'Accessibility', 'my-calendar' ),
920
  ),
921
  array( 'author', 'ical', 'address', 'gcal', 'description', 'image', 'tickets', 'access', 'link', 'gmap_link' ),
my-calendar-shortcodes.php CHANGED
@@ -461,7 +461,7 @@ function mc_calendar_generator_fields( $post, $callback_args ) {
461
  <?php
462
  // Translators: Settings page URL.
463
  printf( __( "Navigation above and below the calendar: your <a href='%s'>settings</a> if this is left blank. Use <code>none</code> to hide all navigation.", 'my-calendar' ), admin_url( 'admin.php?page=my-calendar-config#mc-output' ) );
464
- mc_help_link( 'Help', __( 'Navigation Keywords', 'my-calendar' ), 3 );
465
  ?>
466
  </p>
467
  <p>
461
  <?php
462
  // Translators: Settings page URL.
463
  printf( __( "Navigation above and below the calendar: your <a href='%s'>settings</a> if this is left blank. Use <code>none</code> to hide all navigation.", 'my-calendar' ), admin_url( 'admin.php?page=my-calendar-config#mc-output' ) );
464
+ mc_help_link( __( 'Help', 'my-calendar' ), __( 'Navigation Keywords', 'my-calendar' ), 'navigation keywords', 3 );
465
  ?>
466
  </p>
467
  <p>
my-calendar-styles.php CHANGED
@@ -167,7 +167,7 @@ function my_calendar_style_edit() {
167
  <legend><?php esc_html_e( 'CSS Style Options', 'my-calendar' ); ?></legend>
168
  <p>
169
  <label for="mc_show_css"><?php esc_html_e( 'Load CSS only on selected pages', 'my-calendar' ); ?></label>
170
- <input type="text" id="mc_show_css" name="mc_show_css" placeholder="3,19,27" value="<?php echo esc_attr( $mc_show_css ); ?>" aria-describedby="mc_css_info" /> <span id="mc_css_info"><i class="dashicons dashicons-editor-help" aria-hidden="true"></i><?php esc_html_e( 'Comma-separated post IDs', 'my-calendar' ); ?></span>
171
  </p>
172
  <p>
173
  <input type="checkbox" id="use_styles" name="use_styles" <?php mc_is_checked( 'mc_use_styles', 'true' ); ?> />
167
  <legend><?php esc_html_e( 'CSS Style Options', 'my-calendar' ); ?></legend>
168
  <p>
169
  <label for="mc_show_css"><?php esc_html_e( 'Load CSS only on selected pages', 'my-calendar' ); ?></label>
170
+ <input type="text" id="mc_show_css" name="mc_show_css" value="<?php echo esc_attr( $mc_show_css ); ?>" aria-describedby="mc_css_info" /> <span id="mc_css_info"><i class="dashicons dashicons-editor-help" aria-hidden="true"></i><?php esc_html_e( 'Comma-separated post IDs', 'my-calendar' ); ?></span>
171
  </p>
172
  <p>
173
  <input type="checkbox" id="use_styles" name="use_styles" <?php mc_is_checked( 'mc_use_styles', 'true' ); ?> />
my-calendar-templates.php CHANGED
@@ -88,7 +88,6 @@ function mc_map_string( $event, $source = 'event' ) {
88
  if ( ! is_object( $event ) ) {
89
  return '';
90
  }
91
- $event = mc_clean_location( $event, $source );
92
  if ( 'event' === $source ) {
93
  $map_string = $event->event_street . ' ' . $event->event_street2 . ' ' . $event->event_city . ' ' . $event->event_state . ' ' . $event->event_postcode . ' ' . $event->event_country;
94
  } else {
@@ -98,61 +97,6 @@ function mc_map_string( $event, $source = 'event' ) {
98
  return $map_string;
99
  }
100
 
101
- /**
102
- * Clean up my errors from assigning location values as 'none'
103
- *
104
- * @param object $event Event Object or Location Object.
105
- * @param string $source (event,location).
106
- *
107
- * @return object $event
108
- */
109
- function mc_clean_location( $event, $source = 'event' ) {
110
- if ( ! is_object( $event ) ) {
111
- return $event;
112
- }
113
- if ( 'event' === $source ) {
114
- if ( 'none' === strtolower( $event->event_city ) ) {
115
- $event->event_city = '';
116
- }
117
- if ( 'none' === strtolower( $event->event_state ) ) {
118
- $event->event_state = '';
119
- }
120
- if ( 'none' === strtolower( $event->event_country ) ) {
121
- $event->event_country = '';
122
- }
123
- if ( 'none' === strtolower( $event->event_postcode ) ) {
124
- $event->event_postcode = '';
125
- }
126
- if ( 'none' === strtolower( $event->event_region ) ) {
127
- $event->event_region = '';
128
- }
129
- if ( 'none' === strtolower( $event->event_location ) ) {
130
- $event->event_location = '';
131
- }
132
- } else {
133
- if ( 'none' === strtolower( $event->location_city ) ) {
134
- $event->location_city = '';
135
- }
136
- if ( 'none' === strtolower( $event->location_state ) ) {
137
- $event->location_state = '';
138
- }
139
- if ( 'none' === strtolower( $event->location_country ) ) {
140
- $event->location_country = '';
141
- }
142
- if ( 'none' === strtolower( $event->location_postcode ) ) {
143
- $event->location_postcode = '';
144
- }
145
- if ( 'none' === strtolower( $event->location_region ) ) {
146
- $event->location_region = '';
147
- }
148
- if ( 'none' === strtolower( $event->location_label ) ) {
149
- $event->location_label = '';
150
- }
151
- }
152
-
153
- return $event;
154
- }
155
-
156
  /**
157
  * Set up link to Google Maps
158
  *
@@ -259,7 +203,6 @@ function mc_hcard( $event, $address = 'true', $map = 'true', $source = 'event' )
259
  $source = 'location';
260
  }
261
  $the_map = mc_maplink( $event, 'url', $source );
262
- $event = mc_clean_location( $event, $source );
263
  $url = ( 'event' === $source ) ? $event->event_url : $event->location_url;
264
  $url = esc_url( $url );
265
  $label = strip_tags( stripslashes( ( 'event' === $source ) ? $event->event_label : $event->location_label ), mc_strip_tags() );
@@ -291,7 +234,7 @@ function mc_hcard( $event, $address = 'true', $map = 'true', $source = 'event' )
291
  $link = $link . $distance;
292
  }
293
  $post = mc_get_location_post( $loc_id );
294
- $events = ( $post && ! is_single( $post ) && ! is_admin() ) ? '<a class="location-link" href="' . esc_url( get_the_permalink( $post ) ) . '">' . __( 'View Location', 'my-calendar' ) . '</a>' : '';
295
  /**
296
  * Filter link to location-specific events in hcard.
297
  *
@@ -347,7 +290,6 @@ function mc_create_tags( $event, $context = 'filters' ) {
347
  $calendar_id = $context;
348
  }
349
  $site = ( isset( $event->site_id ) ) ? $event->site_id : false;
350
- $event = mc_clean_location( $event, 'event' );
351
  $e = array();
352
  $e['post'] = $event->event_post;
353
  $date_format = mc_date_format();
@@ -469,10 +411,19 @@ function mc_create_tags( $event, $context = 'filters' ) {
469
  $e['link_title'] = $e['title'];
470
  }
471
 
472
- $e['details_link'] = $e_link;
473
- $e['details'] = "<a href='" . esc_url( $e_link ) . "' class='mc-details' $nofollow>$e_label</a>";
474
- $e['linking'] = ( '' !== $e['link'] ) ? $event->event_link : $e_link;
475
- $e['linking_title'] = ( '' !== $e['linking'] ) ? "<a href='" . esc_url( $e['linking'] ) . "' $nofollow>" . $e['title'] . '</a>' : $e['title'];
 
 
 
 
 
 
 
 
 
476
 
477
  if ( 'related' !== $context && ( mc_is_single_event() ) ) {
478
  $related_template = apply_filters( 'mc_related_template', '{date}, {time}', $event );
@@ -1225,11 +1176,12 @@ function mc_event_recur_string( $event, $begin ) {
1225
  * Generate JSON/LD Schema for event.
1226
  *
1227
  * @param object $e Event object.
 
1228
  *
1229
  * @return array
1230
  */
1231
- function mc_event_schema( $e ) {
1232
- $event = mc_create_tags( $e );
1233
  $wp_time = mc_ts( true );
1234
  $wp_time = str_replace( array( ':30:00', ':00:00' ), array( ':30', ':00' ), $wp_time );
1235
  $image = ( $event['image_url'] ) ? $event['image_url'] : get_site_icon_url();
88
  if ( ! is_object( $event ) ) {
89
  return '';
90
  }
 
91
  if ( 'event' === $source ) {
92
  $map_string = $event->event_street . ' ' . $event->event_street2 . ' ' . $event->event_city . ' ' . $event->event_state . ' ' . $event->event_postcode . ' ' . $event->event_country;
93
  } else {
97
  return $map_string;
98
  }
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  /**
101
  * Set up link to Google Maps
102
  *
203
  $source = 'location';
204
  }
205
  $the_map = mc_maplink( $event, 'url', $source );
 
206
  $url = ( 'event' === $source ) ? $event->event_url : $event->location_url;
207
  $url = esc_url( $url );
208
  $label = strip_tags( stripslashes( ( 'event' === $source ) ? $event->event_label : $event->location_label ), mc_strip_tags() );
234
  $link = $link . $distance;
235
  }
236
  $post = mc_get_location_post( $loc_id );
237
+ $events = ( $post && ! is_single( $post ) && ! is_admin() && 'mc-locations' === get_post_type( $post ) ) ? '<a class="location-link" href="' . esc_url( get_the_permalink( $post ) ) . '">' . __( 'View Location', 'my-calendar' ) . '</a>' : '';
238
  /**
239
  * Filter link to location-specific events in hcard.
240
  *
290
  $calendar_id = $context;
291
  }
292
  $site = ( isset( $event->site_id ) ) ? $event->site_id : false;
 
293
  $e = array();
294
  $e['post'] = $event->event_post;
295
  $date_format = mc_date_format();
411
  $e['link_title'] = $e['title'];
412
  }
413
 
414
+ $e['details_link'] = $e_link;
415
+ $e['details'] = "<a href='" . esc_url( $e_link ) . "' class='mc-details' $nofollow>$e_label</a>";
416
+ $e['linking'] = ( '' !== $e['link'] ) ? $event->event_link : $e_link;
417
+
418
+ $rel = $nofollow;
419
+ if ( mc_external_link( $e['linking'] ) ) {
420
+ if ( $rel ) {
421
+ $rel = 'rel="external nofollow"';
422
+ } else {
423
+ $rel = 'rel="external"';
424
+ }
425
+ }
426
+ $e['linking_title'] = ( '' !== $e['linking'] ) ? "<a href='" . esc_url( $e['linking'] ) . "' $rel>" . $e['title'] . '</a>' : $e['title'];
427
 
428
  if ( 'related' !== $context && ( mc_is_single_event() ) ) {
429
  $related_template = apply_filters( 'mc_related_template', '{date}, {time}', $event );
1176
  * Generate JSON/LD Schema for event.
1177
  *
1178
  * @param object $e Event object.
1179
+ * @param array $tags Event tag array.
1180
  *
1181
  * @return array
1182
  */
1183
+ function mc_event_schema( $e, $tags = array() ) {
1184
+ $event = ( empty( $tags ) ) ? mc_create_tags( $e ) : $tags;
1185
  $wp_time = mc_ts( true );
1186
  $wp_time = str_replace( array( ':30:00', ':00:00' ), array( ':30', ':00' ), $wp_time );
1187
  $image = ( $event['image_url'] ) ? $event['image_url'] : get_site_icon_url();
my-calendar-templating.php CHANGED
@@ -37,13 +37,14 @@ function mc_templates_do_edit() {
37
  wp_safe_redirect( admin_url( 'admin.php?page=my-calendar-design&action=duplicate#my-calendar-templates' ) );
38
  } else {
39
  if ( mc_is_core_template( $key ) && isset( $_POST['mc_template'] ) ) {
40
- $template = ( ! empty( $_POST['mc_template'] ) ) ? $_POST['mc_template'] : '';
 
41
  $templates[ $key ] = $template;
42
  update_option( 'mc_templates', $templates );
43
  update_option( 'mc_use_' . $key . '_template', ( empty( $_POST['mc_use_template'] ) ? 0 : 1 ) );
44
  wp_safe_redirect( esc_url_raw( admin_url( 'admin.php?page=my-calendar-design&action=core&mc_template=' . $key . '#my-calendar-templates' ) ) );
45
  } elseif ( isset( $_POST['mc_template'] ) ) {
46
- $template = sanitize_textarea_field( $_POST['mc_template'] );
47
  if ( mc_key_exists( $key ) ) {
48
  $key = mc_update_template( $key, $template );
49
  } else {
@@ -144,7 +145,7 @@ function mc_templates_edit() {
144
  <p>
145
  <input type="submit" name="save" class="button-primary" value="<?php esc_attr_e( 'Update Template', 'my-calendar' ); ?>" />
146
  <?php if ( ! mc_is_core_template( $key ) ) { ?>
147
- <input type="submit" name="delete" class="button-secondary" value=<?php esc_attr_e( 'Delete Template', 'my-calendar' ); ?>" />
148
  <?php } ?>
149
  </p>
150
  <?php } ?>
@@ -180,7 +181,7 @@ function mc_templates_edit() {
180
  <h2>
181
  <?php
182
  esc_html_e( 'Template Tags', 'my-calendar' );
183
- mc_help_link( __( 'Template Tag Help', 'my-calendar' ), __( 'Template Tags', 'my-calendar' ), 5 );
184
  ?>
185
  </h2>
186
 
37
  wp_safe_redirect( admin_url( 'admin.php?page=my-calendar-design&action=duplicate#my-calendar-templates' ) );
38
  } else {
39
  if ( mc_is_core_template( $key ) && isset( $_POST['mc_template'] ) ) {
40
+ $template = ( ! empty( $_POST['mc_template'] ) ) ? wp_kses_post( stripslashes( $_POST['mc_template'] ) ) : '';
41
+ $templates = get_option( 'mc_templates' );
42
  $templates[ $key ] = $template;
43
  update_option( 'mc_templates', $templates );
44
  update_option( 'mc_use_' . $key . '_template', ( empty( $_POST['mc_use_template'] ) ? 0 : 1 ) );
45
  wp_safe_redirect( esc_url_raw( admin_url( 'admin.php?page=my-calendar-design&action=core&mc_template=' . $key . '#my-calendar-templates' ) ) );
46
  } elseif ( isset( $_POST['mc_template'] ) ) {
47
+ $template = wp_kses_post( stripslashes( $_POST['mc_template'] ) );
48
  if ( mc_key_exists( $key ) ) {
49
  $key = mc_update_template( $key, $template );
50
  } else {
145
  <p>
146
  <input type="submit" name="save" class="button-primary" value="<?php esc_attr_e( 'Update Template', 'my-calendar' ); ?>" />
147
  <?php if ( ! mc_is_core_template( $key ) ) { ?>
148
+ <input type="submit" name="delete" class="button-secondary" value="<?php esc_attr_e( 'Delete Template', 'my-calendar' ); ?>" />
149
  <?php } ?>
150
  </p>
151
  <?php } ?>
181
  <h2>
182
  <?php
183
  esc_html_e( 'Template Tags', 'my-calendar' );
184
+ mc_help_link( __( 'Template Tag Help', 'my-calendar' ), __( 'Template Tags', 'my-calendar' ), 'template-tags', 5 );
185
  ?>
186
  </h2>
187
 
my-calendar.php CHANGED
@@ -4,7 +4,7 @@
4
  *
5
  * @package MyCalendar
6
  * @author Joe Dolson
7
- * @copyright 2009-2021 Joe Dolson
8
  * @license GPL-2.0+
9
  *
10
  * @wordpress-plugin
@@ -17,11 +17,11 @@
17
  * License: GPL-2.0+
18
  * License URI: http://www.gnu.org/license/gpl-2.0.txt
19
  * Domain Path: lang
20
- * Version: 3.3.0
21
  */
22
 
23
  /*
24
- Copyright 2009-2021 Joe Dolson (email : joe@joedolson.com)
25
 
26
  This program is free software; you can redistribute it and/or modify
27
  it under the terms of the GNU General Public License as published by
@@ -42,7 +42,7 @@ if ( ! defined( 'ABSPATH' ) ) {
42
  }
43
 
44
  global $mc_version, $wpdb;
45
- $mc_version = '3.3.0';
46
 
47
  define( 'MC_DEBUG', false );
48
 
@@ -100,9 +100,7 @@ function mc_delete_posts( $type ) {
100
  * Uninstall function for removing terms and posts.
101
  */
102
  function mc_uninstall() {
103
- wp_mail( 'joe@joedolson.com', 'Before deleting Data', 'test of content' );
104
  if ( get_option( 'mc_drop_tables' ) === 'true' ) {
105
- wp_mail( 'joe@joedolson.com', 'Deleting Data', 'test of content' );
106
  mc_delete_posts( 'mc-events' );
107
  mc_delete_posts( 'mc-locations' );
108
  $terms = get_terms(
4
  *
5
  * @package MyCalendar
6
  * @author Joe Dolson
7
+ * @copyright 2009-2022 Joe Dolson
8
  * @license GPL-2.0+
9
  *
10
  * @wordpress-plugin
17
  * License: GPL-2.0+
18
  * License URI: http://www.gnu.org/license/gpl-2.0.txt
19
  * Domain Path: lang
20
+ * Version: 3.3.6
21
  */
22
 
23
  /*
24
+ Copyright 2009-2022 Joe Dolson (email : joe@joedolson.com)
25
 
26
  This program is free software; you can redistribute it and/or modify
27
  it under the terms of the GNU General Public License as published by
42
  }
43
 
44
  global $mc_version, $wpdb;
45
+ $mc_version = '3.3.6';
46
 
47
  define( 'MC_DEBUG', false );
48
 
100
  * Uninstall function for removing terms and posts.
101
  */
102
  function mc_uninstall() {
 
103
  if ( get_option( 'mc_drop_tables' ) === 'true' ) {
 
104
  mc_delete_posts( 'mc-events' );
105
  mc_delete_posts( 'mc-locations' );
106
  $terms = get_terms(
readme.txt CHANGED
@@ -3,10 +3,10 @@ Contributors: joedolson
3
  Donate link: http://www.joedolson.com/donate/
4
  Tags: calendar, dates, times, event, events, scheduling, schedule, event manager, event calendar, class, concert, venue, location, box office, tickets, registration
5
  Requires at least: 4.4
6
- Tested up to: 5.8
7
  Requires PHP: 7.0
8
  Text domain: my-calendar
9
- Stable tag: 3.3.0
10
  License: GPLv2 or later
11
 
12
  Accessible WordPress event calendar plugin. Show events from multiple calendars on pages, in posts, or in widgets.
@@ -84,6 +84,82 @@ Translating my plugins is always appreciated. Visit <a href="https://translate.w
84
 
85
  == Changelog ==
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  = 3.3.0 =
88
 
89
  Backend Changes:
3
  Donate link: http://www.joedolson.com/donate/
4
  Tags: calendar, dates, times, event, events, scheduling, schedule, event manager, event calendar, class, concert, venue, location, box office, tickets, registration
5
  Requires at least: 4.4
6
+ Tested up to: 5.9
7
  Requires PHP: 7.0
8
  Text domain: my-calendar
9
+ Stable tag: 3.3.6
10
  License: GPLv2 or later
11
 
12
  Accessible WordPress event calendar plugin. Show events from multiple calendars on pages, in posts, or in widgets.
84
 
85
  == Changelog ==
86
 
87
+ = 3.3.6 =
88
+
89
+ * Bug fix: Event template previews should only show to users who can use them.
90
+ * Bug fix: Category key icons should show background colors when configured.
91
+
92
+ = 3.3.5 =
93
+
94
+ * Bug fix: Default values for screen options were not called.
95
+ * Bug fix: Event count dots should not show in print view.
96
+ * Bug fix: PHP notice if mc_id not set on single event views.
97
+ * Bug fix: Documentation link led to removed page.
98
+ * Bug fix: Modal help links should open in parent window, not within modal.
99
+ * Bug fix: Search query sent to docs site should not be translatable.
100
+ * Bug fix: JPG or GIF custom icons should be accepted.
101
+ * Bug fix: Template attributes containing HTML stripped attributes in template manager.
102
+ * Bug fix: PHP Warning when checking for private category property and object not defined.
103
+ * Bug fix: Don't show admin grid view location dropdown if more than 200 locations.
104
+ * Bug fix: Prevent large icons from overflowing custom icon list.
105
+ * Bug fix: Fix display of custom icons in icons modal.
106
+ * Performance: only run mc_create_tags() once per event.
107
+ * Performance: cache whether icons are custom rather than inspecting directory for every icon load.
108
+ * New filter: `mc_display_location_events` on upcoming event arguments for location screen.
109
+ * Change: label My Calendar page in pages list.
110
+
111
+ = 3.3.4 =
112
+
113
+ * Bug fix: is_single() shouldn't be called in admin
114
+ * Bug fix: Prevent invalid events from breaking year dropdown.
115
+ * Bug fix: Make sure category colors are important.
116
+ * Bug fix: Set margins to 0 on input/button in nav.
117
+ * Bug fix: Decreasing font sizes in nav caused too many problems in older themes.
118
+ * Bug fix: Don't insert locations if no data passed to inserter.
119
+ * Bug fix: Delete location argument was not used.
120
+ * Bug fix: don't output empty locations.
121
+ * Bug fix: 'span' is not an attribute on 'span'.
122
+ * Bug fix: Verify validity of category relationships when parsing admin lists.
123
+ * Bug fix: $templates was undefined and broke saving templates.
124
+ * Bug fix: missing quote in 'delete template' button.
125
+ * Bug fix: custom templates sanitized incorrectly.
126
+ * Bug fix: translations link went to old translations site.
127
+ * Bug fix: Handle what happens if default category is deleted.
128
+ * Bug fix: Invalid class not reset in admin lists.
129
+ * Bug fix: date displayed in wrong timezone in admin recurring events list.
130
+ * Change: If location without any unique data is listed in admin, auto delete.
131
+ * Change: changes to add dates UI to clarify usage.
132
+
133
+ = 3.3.3 =
134
+
135
+ * Bug fix: Timezone omits positive/negative signifier in JSON LD in UTC+ timezones.
136
+ * Bug fix: Widen location autocomplete field.
137
+ * Bug fix: Fix show location shortcode templating.
138
+ * Bug fix: Recur daily by weekday did not produce valid times.
139
+ * Bug fix: Skip holidays default state filter missing.
140
+ * Bug fix: Only apply default state on special case recurrence fields on new events.
141
+ * Bug fix: Category relationships not updated correctly if category deleted.
142
+ * Bug fix: File path incorrectly referenced when finding custom icon directories.
143
+
144
+ = 3.3.2 =
145
+
146
+ * Change: Add classes representing start time and event length.
147
+ * Bug fix: Remove unneeded generic class declarations.
148
+ * Bug fix: Show stored location, not event location, in events list.
149
+ * Bug fix: Add missing elements to KSES filters for widgets.
150
+ * Bug fix: Incorrect logic to hide read more link.
151
+ * Feature: Add field to set calendar month heading.
152
+
153
+ = 3.3.1 =
154
+
155
+ * Bug fix: Bulk removal of locations broken.
156
+ * Bug fix: SVG category icons should not be queried remotely; use filesystem.
157
+ * Layout: wider max-width by default, center calendar in container.
158
+ * Bug fix: Display more information link had inverted logic & wrong label.
159
+ * Bug fix: Don't show location link if location is not post type mc-locations.
160
+ * Bug fix: Week view could end up offset incorrectly in some views due to dates getting double timezone offsets.
161
+ * Bug fix: Provide back-compatibility for tabs in older versions of My Calendar Pro
162
+
163
  = 3.3.0 =
164
 
165
  Backend Changes: