Source: my-calendar-navigation.php

  1. <?php
  2. /**
  3. * Navigation Output. Functions that generate elements of the My Calendar navigation.
  4. *
  5. * @category Output
  6. * @package My Calendar
  7. * @author Joe Dolson
  8. * @license GPLv2 or later
  9. * @link https://www.joedolson.com/my-calendar/
  10. */
  11. if ( ! defined( 'ABSPATH' ) ) {
  12. exit;
  13. }
  14. /**
  15. * Create navigation elements used in My Calendar main view
  16. *
  17. * @param array $params Calendar parameters (modified).
  18. * @param int $cat Original category from calendar args.
  19. * @param int $start_of_week First day of week.
  20. * @param int $show_months num months to show (modified).
  21. * @param string $main_class Class/ID.
  22. * @param int|string $site Which site in multisite.
  23. * @param array $date current date.
  24. * @param string $from date view started from.
  25. *
  26. * @return array of calendar nav for top & bottom
  27. */
  28. function mc_generate_calendar_nav( $params, $cat, $start_of_week, $show_months, $main_class, $site, $date, $from ) {
  29. if ( $site ) {
  30. $site = ( 'global' === $site ) ? BLOG_ID_CURRENT_SITE : $site;
  31. $restore = $site;
  32. restore_current_blog();
  33. }
  34. $format = $params['format'];
  35. $category = $params['category'];
  36. $above = $params['above'];
  37. $below = $params['below'];
  38. $time = $params['time'];
  39. $ltype = $params['ltype'];
  40. $lvalue = $params['lvalue'];
  41. if ( 'none' === $above && 'none' === $below ) {
  42. return array(
  43. 'bottom' => '',
  44. 'top' => '',
  45. );
  46. }
  47. // Fallback values.
  48. $mc_toporder = array( 'nav', 'toggle', 'jump', 'print', 'timeframe' );
  49. $mc_bottomorder = array( 'key', 'feeds' );
  50. $available = array( 'nav', 'toggle', 'jump', 'print', 'timeframe', 'key', 'feeds', 'exports', 'categories', 'locations', 'access', 'search' );
  51. if ( 'none' === $above ) {
  52. $mc_toporder = array();
  53. } else {
  54. // Set up above-calendar order of fields.
  55. if ( '' !== mc_get_option( 'topnav', '' ) ) {
  56. $mc_toporder = array_map( 'trim', explode( ',', mc_get_option( 'topnav' ) ) );
  57. }
  58. if ( '' !== $above ) {
  59. $mc_toporder = array_map( 'trim', explode( ',', $above ) );
  60. }
  61. }
  62. if ( 'none' === $below ) {
  63. $mc_bottomorder = array();
  64. } else {
  65. if ( '' !== mc_get_option( 'bottomnav', '' ) ) {
  66. $mc_bottomorder = array_map( 'trim', explode( ',', mc_get_option( 'bottomnav' ) ) );
  67. }
  68. if ( '' !== $below ) {
  69. $mc_bottomorder = array_map( 'trim', explode( ',', $below ) );
  70. }
  71. }
  72. // Navigation elements passed from shortcode or settings.
  73. $used = array_merge( $mc_toporder, $mc_bottomorder );
  74. /**
  75. * Filter the order in which navigation elements are shown on the top of the calendar.
  76. * Insert custom navigation elements by adding a value into the array with a callable function as a value.
  77. * E.g. `my_custom_nav`, that expects the $params array as an argument.
  78. *
  79. * @hook mc_header_navigation
  80. * @since 3.4.0
  81. *
  82. * @param {array} $mc_toporder Array of navigation elements.
  83. * @param {array} $used Array of all navigation elements in use for this view.
  84. * @param {array} $params Current calendar view parameters.
  85. *
  86. * @return {array}
  87. */
  88. $mc_toporder = apply_filters( 'mc_header_navigation', $mc_toporder, $used, $params );
  89. $aboves = $mc_toporder;
  90. /**
  91. * Filter the order in which navigation elements are shown at the bottom of the calendar.
  92. * Insert custom navigation elements by adding a value into the array with a callable function as a value.
  93. * E.g. `my_custom_nav`, that expects the $params array as an argument.
  94. *
  95. * @hook mc_footer_navigation
  96. * @since 3.4.0
  97. *
  98. * @param {array} $mc_bottomorder Array of navigation elements.
  99. * @param {array} $used Array of all navigation elements in use for this view.
  100. * @param {array} $params Current calendar view parameters.
  101. *
  102. * @return {array}
  103. */
  104. $mc_bottomorder = apply_filters( 'mc_footer_navigation', $mc_bottomorder, $used, $params );
  105. $belows = $mc_bottomorder;
  106. // Generate array of navigation elements in use, to avoid executing unneeded code.
  107. $used = array_merge( $aboves, $belows );
  108. // Define navigation element strings.
  109. $timeframe = '';
  110. $print = '';
  111. $toggle = '';
  112. $nav = '';
  113. $feeds = '';
  114. $exports = '';
  115. $jump = '';
  116. $mc_topnav = '';
  117. $mc_bottomnav = '';
  118. // Setup link data.
  119. $add = array(
  120. 'time' => $time,
  121. 'ltype' => $ltype,
  122. 'lvalue' => $lvalue,
  123. 'mcat' => $category,
  124. 'yr' => $date['year'],
  125. 'month' => $date['month'],
  126. 'dy' => $date['day'],
  127. 'href' => ( isset( $params['self'] ) && esc_url( $params['self'] ) ) ? urlencode( $params['self'] ) : urlencode( mc_get_current_url() ),
  128. );
  129. if ( 'list' === $format ) {
  130. $add['format'] = 'list';
  131. }
  132. $subtract = array();
  133. if ( '' === $ltype ) {
  134. $subtract[] = 'ltype';
  135. unset( $add['ltype'] );
  136. }
  137. if ( '' === $lvalue ) {
  138. $subtract[] = 'lvalue';
  139. unset( $add['lvalue'] );
  140. }
  141. if ( 'all' === $category ) {
  142. $subtract[] = 'mcat';
  143. unset( $add['mcat'] );
  144. }
  145. // Set up print link.
  146. if ( in_array( 'print', $used, true ) ) {
  147. $print_add = array_merge( $add, array( 'cid' => 'mc-print-view' ) );
  148. $mc_print_url = mc_build_url( $print_add, $subtract, home_url() );
  149. $print = "<div class='mc-print'><a id='mc_print-$main_class' href='$mc_print_url' rel='nofollow'><span class='mc-icon' aria-hidden='true'></span>" . __( 'Print<span class="maybe-hide"> View</span>', 'my-calendar' ) . '</a></div>';
  150. }
  151. // Set up format toggle.
  152. $toggle = ( in_array( 'toggle', $used, true ) ) ? mc_format_toggle( $format, 'yes', $time, $main_class ) : '';
  153. // Set up time toggle.
  154. if ( in_array( 'timeframe', $used, true ) ) {
  155. $timeframe = mc_time_toggle( $format, $time, $date['month'], $date['year'], $date['current_date'], $start_of_week, $from, $main_class );
  156. }
  157. // Set up category key.
  158. $key = ( in_array( 'key', $used, true ) ) ? mc_category_key( $cat, $main_class ) : '';
  159. // Set up category filter.
  160. $cat_args = array(
  161. 'categories',
  162. 'id' => $main_class . '-categories',
  163. );
  164. $cats = mc_category_select_ids( $cat );
  165. $categories = ( in_array( 'categories', $used, true ) ) ? mc_filters( $cat_args, mc_get_current_url(), 'id', $cats ) : '';
  166. // Set up location filter.
  167. $loc_args = array(
  168. 'locations',
  169. 'id' => $main_class . '-locations',
  170. );
  171. $locations = ( in_array( 'locations', $used, true ) ) ? mc_filters( $loc_args, mc_get_current_url(), 'id' ) : '';
  172. // Set up access filter.
  173. $acc_args = array(
  174. 'access',
  175. 'id' => $main_class . '-access',
  176. );
  177. $access = ( in_array( 'access', $used, true ) ) ? mc_filters( $acc_args, mc_get_current_url() ) : '';
  178. // Set up search.
  179. $search = ( in_array( 'search', $used, true ) ) ? my_calendar_searchform( 'simple', mc_get_current_url(), $main_class ) : '';
  180. // Set up navigation links.
  181. if ( in_array( 'nav', $used, true ) ) {
  182. $nav = mc_nav( $date, $format, $time, $show_months, $main_class, $site );
  183. }
  184. // Set up subscription feeds.
  185. if ( in_array( 'feeds', $used, true ) ) {
  186. $feeds = mc_sub_links( $subtract );
  187. }
  188. // Set up exports.
  189. if ( in_array( 'exports', $used, true ) ) {
  190. $ical_m = ( isset( $_GET['month'] ) ) ? (int) $_GET['month'] : mc_date( 'n' );
  191. $ical_y = ( isset( $_GET['yr'] ) ) ? (int) $_GET['yr'] : mc_date( 'Y' );
  192. $next_link = my_calendar_next_link( $date, $format, $time, $show_months );
  193. $exports = mc_export_links( $ical_y, $ical_m, $next_link, $add, $subtract );
  194. }
  195. // Set up date switcher.
  196. if ( in_array( 'jump', $used, true ) ) {
  197. $jump = mc_date_switcher( $format, $main_class, $time, $date, $site );
  198. }
  199. foreach ( $mc_toporder as $value ) {
  200. if ( 'none' !== $value && in_array( $value, $used, true ) && in_array( $value, $available, true ) ) {
  201. $value = trim( $value );
  202. $mc_topnav .= ${$value};
  203. }
  204. if ( ! in_array( $value, $available, true ) && $value && 'none' !== strtolower( $value ) ) {
  205. if ( function_exists( $value ) ) {
  206. $mc_topnav .= call_user_func( $value, $params );
  207. }
  208. }
  209. }
  210. foreach ( $mc_bottomorder as $value ) {
  211. if ( 'none' !== strtolower( $value ) && 'stop' !== strtolower( $value ) && in_array( $value, $used, true ) && in_array( $value, $available, true ) ) {
  212. $value = trim( $value );
  213. $mc_bottomnav .= ${$value};
  214. }
  215. if ( ! in_array( $value, $available, true ) && $value && 'none' !== strtolower( $value ) ) {
  216. if ( function_exists( $value ) ) {
  217. $mc_bottomnav .= call_user_func( $value, $params );
  218. }
  219. }
  220. }
  221. if ( '' !== $mc_topnav ) {
  222. $mc_topnav = PHP_EOL . '<nav class="my-calendar-navigation" aria-label="' . __( 'Calendar (top)', 'my-calendar' ) . '">' . PHP_EOL . '<div class="my-calendar-header">' . $mc_topnav . '</div>' . PHP_EOL . '</nav>' . PHP_EOL;
  223. }
  224. if ( '' !== $mc_bottomnav ) {
  225. $mc_bottomnav = PHP_EOL . '<nav class="my-calendar-navigation" aria-label="' . __( 'Calendar (bottom)', 'my-calendar' ) . '">' . PHP_EOL . '<div class="mc_bottomnav my-calendar-footer">' . $mc_bottomnav . '</div>' . PHP_EOL . '</nav>' . PHP_EOL;
  226. }
  227. if ( $site ) {
  228. switch_to_blog( $restore );
  229. }
  230. return array(
  231. 'bottom' => $mc_bottomnav,
  232. 'top' => $mc_topnav,
  233. );
  234. }
  235. /**
  236. * Generate calendar navigation
  237. *
  238. * @param string $date Current date.
  239. * @param string $format Current format.
  240. * @param string $time Current time view.
  241. * @param int $show_months Num months to show.
  242. * @param string $id view ID.
  243. * @param int $site Optional. Site ID if not main site.
  244. *
  245. * @return string prev/next nav.
  246. */
  247. function mc_nav( $date, $format, $time, $show_months, $id, $site = false ) {
  248. $prev = my_calendar_prev_link( $date, $format, $time, $show_months );
  249. $next = my_calendar_next_link( $date, $format, $time, $show_months );
  250. $prev_link = '';
  251. $next_link = '';
  252. if ( $prev ) {
  253. $prev_link = mc_build_url(
  254. array(
  255. 'yr' => $prev['yr'],
  256. 'month' => $prev['month'],
  257. 'dy' => $prev['day'],
  258. 'cid' => $id,
  259. 'time' => $time,
  260. ),
  261. array()
  262. );
  263. $prev_link = mc_url_in_loop( $prev_link );
  264. /**
  265. * Filter HTML output for navigation 'prev' link.
  266. *
  267. * @hook mc_prev_link
  268. *
  269. * @param {string} $prev_link HTML output for link.
  270. * @param {array} $prev Previous link parameters.
  271. *
  272. * @return {string}
  273. */
  274. $prev_link = apply_filters( 'mc_previous_link', '<li class="my-calendar-prev"><a id="mc_previous_' . $id . '" href="' . $prev_link . '" rel="nofollow"><span class="mc-icon" aria-hidden="true"></span>' . wp_kses_post( $prev['label'] ) . '</a></li>', $prev );
  275. }
  276. if ( $next ) {
  277. $next_link = mc_build_url(
  278. array(
  279. 'yr' => $next['yr'],
  280. 'month' => $next['month'],
  281. 'dy' => $next['day'],
  282. 'cid' => $id,
  283. 'time' => $time,
  284. ),
  285. array()
  286. );
  287. $next_link = mc_url_in_loop( $next_link );
  288. /**
  289. * Filter HTML output for navigation 'next' link.
  290. *
  291. * @hook mc_next_link
  292. *
  293. * @param {string} $next_link HTML output for link.
  294. * @param {array} $next Next link parameters.
  295. *
  296. * @return {string}
  297. */
  298. $next_link = apply_filters( 'mc_next_link', '<li class="my-calendar-next"><a id="mc_next_' . $id . '" href="' . $next_link . '" rel="nofollow">' . wp_kses_post( $next['label'] ) . '<span class="mc-icon" aria-hidden="true"></span></a></li>', $next );
  299. }
  300. $today_text = ( '' === mc_get_option( 'today_events' ) ) ? __( 'Today', 'my-calendar' ) : mc_get_option( 'today_events' );
  301. $active = '';
  302. $current = '';
  303. if ( ! ( isset( $_GET['month'] ) || isset( $_GET['yr'] ) || isset( $_GET['dy'] ) ) ) {
  304. $active = ' mc-active';
  305. $current = ' aria-current="true"';
  306. }
  307. $today = mc_build_url(
  308. array(
  309. 'cid' => $id,
  310. ),
  311. array( 'yr', 'month', 'dy' )
  312. );
  313. $today_link = mc_url_in_loop( $today );
  314. /**
  315. * Filter HTML output for navigation 'today' link.
  316. *
  317. * @hook mc_today_link
  318. *
  319. * @param {string} $today_link HTML output for link.
  320. *
  321. * @return {string}
  322. */
  323. $today_link = apply_filters( 'mc_today_link', '<li class="my-calendar-today"><a id="mc_today_' . $id . '" href="' . $today . '" rel="nofollow" class="today' . $active . '"' . $current . '><span class="mc-icon" aria-hidden="true"></span>' . wp_kses_post( $today_text ) . '</a></li>' );
  324. $nav = '
  325. <div class="my-calendar-nav">
  326. <ul>
  327. ' . $prev_link . $today_link . $next_link . '
  328. </ul>
  329. </div>';
  330. return $nav;
  331. }
  332. /**
  333. * Show the list of categories on the calendar
  334. *
  335. * @param string $category The view-defined category or categories. Usually a comma-separated list of category IDs, but can be category names.
  336. * @param string $id Calendar view ID.
  337. *
  338. * @return string HTML for category key
  339. */
  340. function mc_category_key( $category, $id = '' ) {
  341. $mcdb = mc_is_remote_db();
  342. $url = plugin_dir_url( __FILE__ );
  343. $has_icons = ( 'true' === mc_get_option( 'hide_icons' ) ) ? false : true;
  344. $class = ( $has_icons ) ? 'has-icons' : 'no-icons';
  345. $key = '';
  346. $cat_limit = mc_select_category( $category, 'all', 'category' );
  347. $select_category = str_replace( 'AND', 'WHERE', ( isset( $cat_limit[1] ) ) ? $cat_limit[1] : '' );
  348. $sql = 'SELECT * FROM ' . my_calendar_categories_table() . " $select_category ORDER BY category_name ASC";
  349. $categories = $mcdb->get_results( $sql );
  350. /**
  351. * Filter the array of categories used to generate the category legend in My Calendar.
  352. *
  353. * @hook mc_category_key_array
  354. *
  355. * @param {array} $categories Array of category objects.
  356. * @param {string} $category The active categories in the view. Comma-separated string of IDs or category name.
  357. * @param {string} $id The calendar view ID.
  358. */
  359. $categories = apply_filters( 'mc_category_key_array', $categories, $category, $id );
  360. $key .= '<div class="category-key ' . $class . '"><h3 class="maybe-hide">' . __( 'Categories', 'my-calendar' ) . "</h3>\n<ul>\n";
  361. foreach ( $categories as $cat ) {
  362. $class = '';
  363. // Don't display private categories to public users.
  364. if ( mc_private_event( $cat ) ) {
  365. continue;
  366. }
  367. $hex = ( 0 !== strpos( $cat->category_color, '#' ) ) ? '#' : '';
  368. $class = mc_category_class( $cat, '' );
  369. $selected_categories = ( empty( $_GET['mcat'] ) ) ? array() : map_deep( explode( ',', wp_unslash( $_GET['mcat'] ) ), 'absint' );
  370. $category_id = (int) $cat->category_id;
  371. if ( in_array( $category_id, $selected_categories, true ) || $category === $category_id ) {
  372. $selected_categories = array_diff( $selected_categories, array( $category_id ) );
  373. $class .= ' current';
  374. $aria_current = 'aria-current="true"';
  375. } else {
  376. $selected_categories[] = $category_id;
  377. $aria_current = '';
  378. }
  379. $selectable_categories = implode( ',', $selected_categories );
  380. if ( '' === $selectable_categories ) {
  381. $url = remove_query_arg( 'mcat', mc_get_current_url() );
  382. } else {
  383. $raw_url = remove_query_arg( 'mcat', mc_get_current_url() );
  384. $url = mc_build_url( array( 'mcat' => $selectable_categories ), array( 'mcat' ) );
  385. }
  386. $url = mc_url_in_loop( $url );
  387. if ( 1 === (int) $cat->category_private ) {
  388. $class .= ' private';
  389. }
  390. $cat_name = wp_strip_all_tags( stripcslashes( $cat->category_name ) );
  391. $cat_name = ( '' === $cat_name ) ? '<span class="screen-reader-text">' . __( 'Untitled Category', 'my-calendar' ) . '</span>' : $cat_name;
  392. $cat_key = '';
  393. if ( '' !== $cat->category_icon && $has_icons ) {
  394. $image = mc_category_icon( $cat );
  395. $type = ( stripos( $image, 'svg' ) ) ? 'svg' : 'img';
  396. $back = ( 'background' === mc_get_option( 'apply_color' ) ) ? ' style="background:' . $hex . $cat->category_color . ';"' : '';
  397. $cat_key .= '<span class="category-color-sample ' . $type . '"' . $back . '>' . $image . '</span>' . $cat_name;
  398. } elseif ( 'default' !== mc_get_option( 'apply_color' ) ) {
  399. $cat_key .= ( ( '' !== $cat->category_color ) ? '<span class="category-color-sample no-icon" style="background:' . $hex . $cat->category_color . ';"> &nbsp; </span>' : '' ) . '<span class="mc-category-title">' . $cat_name . '</span>';
  400. } else {
  401. // If category colors are ignored, don't render HTML for them.
  402. $cat_key .= $cat_name;
  403. }
  404. $key .= '<li class="cat_' . $class . '"><a id="mc_cat_' . $category_id . '-' . $id . '" href="' . esc_url( $url ) . '" ' . $aria_current . ' rel="nofollow">' . $cat_key . '</a></li>';
  405. }
  406. /**
  407. * Filter text label for 'All Categories'.
  408. *
  409. * @hook mc_text_all_categories
  410. *
  411. * @param {string} $all Text for link to show all categories.
  412. *
  413. * @return {string}
  414. */
  415. $all = apply_filters( 'mc_text_all_categories', __( 'All Categories', 'my-calendar' ) );
  416. if ( isset( $_GET['mcat'] ) ) {
  417. $raw_url = remove_query_arg( 'mcat', mc_get_current_url() );
  418. $key .= "<li class='all-categories'><a id='mc_cat_all-$id' href='" . esc_url( mc_url_in_loop( mc_build_url( array(), array( 'mcat' ), $raw_url ) ) ) . "' rel='nofollow'><span>" . $all . '</span></a></li>';
  419. } else {
  420. $key .= "<li class='all-categories'><span class='mc-active' id='mc_cat_all-$id' tabindex='-1'>" . $all . '</span></li>';
  421. }
  422. $key .= '</ul></div>';
  423. /**
  424. * Filter the category key output in navigation.
  425. *
  426. * @hook mc_category_key
  427. *
  428. * @param {string} $key Key HTML output.
  429. * @param {array} $categories Categories in key.
  430. *
  431. * @return {string}
  432. */
  433. $key = apply_filters( 'mc_category_key', $key, $categories );
  434. return $key;
  435. }
  436. /**
  437. * Set up subscription links for calendar
  438. *
  439. * @return string HTML output for subscription links
  440. */
  441. function mc_sub_links() {
  442. $replace = 'webcals:';
  443. $search = array( 'http:', 'https:' );
  444. $google = str_replace( $search, $replace, get_feed_link( 'my-calendar-google' ) );
  445. $google = add_query_arg( 'cid', $google, 'https://www.google.com/calendar/render' );
  446. $ical = get_feed_link( 'my-calendar-ics' );
  447. $sub_google = "<li class='ics google'><a href='" . esc_url( $google ) . "' rel='nofollow'><span class='mc-icon' aria-hidden='true'></span>" . __( '<span class="maybe-hide">Subscribe in </span>Google', 'my-calendar' ) . '</a></li>';
  448. $sub_ical = "<li class='ics ical'><a href='" . esc_attr( str_replace( $search, $replace, esc_url( $ical ) ) ) . "' rel='nofollow'><span class='mc-icon' aria-hidden='true'></span>" . __( '<span class="maybe-hide">Subscribe in </span>iCal', 'my-calendar' ) . '</a></li>';
  449. $output = "<div class='mc-export mc-subscribe'>
  450. <ul>$sub_google$sub_ical</ul>
  451. </div>";
  452. return $output;
  453. }
  454. /**
  455. * Generate links to export current view's dates.
  456. *
  457. * @param string $y year.
  458. * @param string $m month.
  459. * @param array $next array of next view's dates.
  460. * @param array $add params to add to link.
  461. * @param array $subtract params to subtract from links.
  462. *
  463. * @return string HTML output for export links.
  464. */
  465. function mc_export_links( $y, $m, $next, $add, $subtract ) {
  466. $add['yr'] = $y;
  467. $add['month'] = $m;
  468. $add['nyr'] = ( is_array( $next ) ) ? $next['yr'] : '';
  469. $add['nmonth'] = ( is_array( $next ) ) ? $next['month'] : '';
  470. unset( $add['href'] );
  471. $ics = mc_build_url( $add, $subtract, get_feed_link( 'my-calendar-ics' ) );
  472. $ics = add_query_arg( 'cid', $ics, 'https://www.google.com/calendar/render' );
  473. $ics2 = mc_build_url( $add, $subtract, get_feed_link( 'my-calendar-ics' ) );
  474. $google = "<li class='ics google'><a href='" . $ics . "' rel='nofollow'><span class='mc-icon' aria-hidden='true'></span>" . __( '<span class="maybe-hide">Export to </span>Google', 'my-calendar' ) . '</a></li>';
  475. $ical = "<li class='ics ical'><a href='" . $ics2 . "' rel='nofollow'><span class='mc-icon' aria-hidden='true'></span>" . __( '<span class="maybe-hide">Export to </span>iCal', 'my-calendar' ) . '</a></li>';
  476. $output = "<div class='mc-export mc-download'>
  477. <ul>$google$ical</ul>
  478. </div>";
  479. return $output;
  480. }
  481. /**
  482. * Set up next link based on current view
  483. *
  484. * @param array $date Current date of view.
  485. * @param string $format of calendar.
  486. * @param string $time current time view.
  487. * @param int $months number of months shown in list views.
  488. * @param int $site Optional. Site ID if not main site.
  489. *
  490. * @return array of parameters for link
  491. */
  492. function my_calendar_next_link( $date, $format, $time = 'month', $months = 1, $site = false ) {
  493. $bounds = mc_get_date_bounds( $site );
  494. $cur_year = (int) $date['year'];
  495. $cur_month = (int) $date['month'];
  496. $cur_day = (int) $date['day'];
  497. $next_year = $cur_year + 1;
  498. $mc_next = mc_get_option( 'next_events' );
  499. $next_events = ( '' === $mc_next ) ? '<span class="maybe-hide">' . __( 'Next', 'my-calendar' ) . ' </span>' : stripslashes( $mc_next );
  500. if ( $months <= 1 || 'list' !== $format ) {
  501. if ( 12 === (int) $cur_month ) {
  502. $month = 1;
  503. $yr = $next_year;
  504. } else {
  505. $next_month = $cur_month + 1;
  506. $month = $next_month;
  507. $yr = $cur_year;
  508. }
  509. } else {
  510. $next_month = ( ( $cur_month + $months ) > 12 ) ? ( ( $cur_month + $months ) - 12 ) : ( $cur_month + $months );
  511. if ( $cur_month >= ( 13 - $months ) ) {
  512. $month = $next_month;
  513. $yr = $next_year;
  514. } else {
  515. $month = $next_month;
  516. $yr = $cur_year;
  517. }
  518. }
  519. $day = '';
  520. if ( (int) $yr !== (int) $cur_year ) {
  521. /**
  522. * Filter the date format used for next link if the next link is in a different year.
  523. *
  524. * @hook mc_month_format
  525. *
  526. * @param {string} $format PHP Date format string.
  527. * @param {array} $date Current date array.
  528. * @param {string} $format View format.
  529. * @param {string} $time View time frame.
  530. * @param {string} $month month used in navigation reference (next month.)
  531. *
  532. * @return {string}
  533. */
  534. $format = apply_filters( 'mc_month_year_format', 'F, Y', $date, $format, $time, $month );
  535. } else {
  536. /**
  537. * Filter the date format used for next link if the next link is in the same year.
  538. *
  539. * @hook mc_month_format
  540. *
  541. * @param {string} $format PHP Date format string.
  542. * @param {array} $date Current date array.
  543. * @param {string} $format View format.
  544. * @param {string} $time View time frame.
  545. * @param {string} $month month used in navigation reference (next month.)
  546. *
  547. * @return {string}
  548. */
  549. $format = apply_filters( 'mc_month_format', 'F', $date, $format, $time, $month );
  550. }
  551. $date = date_i18n( $format, mktime( 0, 0, 0, $month, 1, $yr ) );
  552. if ( 'week' === $time ) {
  553. $nextdate = strtotime( "$cur_year-$cur_month-$cur_day" . '+ 7 days' );
  554. $day = mc_date( 'd', $nextdate, false );
  555. $yr = mc_date( 'Y', $nextdate, false );
  556. $month = mc_date( 'm', $nextdate, false );
  557. if ( (int) $yr !== (int) $cur_year ) {
  558. $format = 'F j, Y';
  559. } else {
  560. $format = 'F j';
  561. }
  562. // Translators: Current formatted date.
  563. $date = sprintf( __( 'Week of %s', 'my-calendar' ), date_i18n( $format, mktime( 0, 0, 0, $month, $day, $yr ) ) );
  564. }
  565. if ( 'day' === $time ) {
  566. $nextdate = strtotime( "$cur_year-$cur_month-$cur_day" . '+ 1 days' );
  567. $day = mc_date( 'd', $nextdate, false );
  568. $yr = mc_date( 'Y', $nextdate, false );
  569. $month = mc_date( 'm', $nextdate, false );
  570. if ( (int) $yr !== (int) $cur_year ) {
  571. $format = 'F j, Y';
  572. } else {
  573. $format = 'F j';
  574. }
  575. $date = date_i18n( $format, mktime( 0, 0, 0, $month, $day, $yr ) );
  576. }
  577. $next_events = str_replace( '{date}', $date, $next_events );
  578. $test_date = ( $day ) ? "$yr-$month-$day" : "$yr-" . str_pad( $month, 2, 0, STR_PAD_LEFT ) . '-01';
  579. if ( strtotime( $bounds['last'] ) < strtotime( $test_date ) ) {
  580. $output = false;
  581. } else {
  582. $output = array(
  583. 'month' => $month,
  584. 'yr' => $yr,
  585. 'day' => $day,
  586. 'label' => $next_events,
  587. );
  588. }
  589. return $output;
  590. }
  591. /**
  592. * Set up prev link based on current view
  593. *
  594. * @param array $date Current date of view.
  595. * @param string $format of calendar.
  596. * @param string $time current time view.
  597. * @param int $months number of months shown in list views.
  598. * @param int $site Optional. Site ID if not main site.
  599. *
  600. * @return array of parameters for link
  601. */
  602. function my_calendar_prev_link( $date, $format, $time = 'month', $months = 1, $site = false ) {
  603. $bounds = mc_get_date_bounds( $site );
  604. $cur_year = (int) $date['year'];
  605. $cur_month = (int) $date['month'];
  606. $cur_day = (int) $date['day'];
  607. $last_year = $cur_year - 1;
  608. $mc_previous = mc_get_option( 'previous_events' );
  609. $previous_events = ( '' === $mc_previous ) ? '<span class="maybe-hide">' . __( 'Previous', 'my-calendar' ) . ' </span>' : stripslashes( $mc_previous );
  610. if ( $months <= 1 || 'list' !== $format ) {
  611. if ( 1 === (int) $cur_month ) {
  612. $month = 12;
  613. $yr = $last_year;
  614. } else {
  615. $next_month = $cur_month - 1;
  616. $month = $next_month;
  617. $yr = $cur_year;
  618. }
  619. } else {
  620. $next_month = ( $cur_month > $months ) ? ( $cur_month - $months ) : ( ( $cur_month - $months ) + 12 );
  621. if ( $cur_month <= $months ) {
  622. $month = $next_month;
  623. $yr = $last_year;
  624. } else {
  625. $month = $next_month;
  626. $yr = $cur_year;
  627. }
  628. }
  629. if ( (int) $yr !== (int) $cur_year ) {
  630. /**
  631. * Filter the date format used for previous link if the prev link is in a different year.
  632. *
  633. * @hook mc_month_year_format
  634. *
  635. * @param {string} $format PHP Date format string.
  636. * @param {array} $date Current date array.
  637. * @param {string} $format View format.
  638. * @param {string} $time View time frame.
  639. * @param {string} $month month used in navigation reference (previous month.)
  640. *
  641. * @return {string}
  642. */
  643. $format = apply_filters( 'mc_month_year_format', 'F, Y', $date, $format, $time, $month );
  644. } else {
  645. /**
  646. * Filter the date format used for previous link if the previous link is in the same year.
  647. *
  648. * @hook mc_month_format
  649. *
  650. * @param {string} $format PHP Date format string.
  651. * @param {array} $date Current date array.
  652. * @param {string} $format View format.
  653. * @param {string} $time View time frame.
  654. * @param {string} $month month used in navigation reference (previous month, generally.)
  655. *
  656. * @return {string}
  657. */
  658. $format = apply_filters( 'mc_month_format', 'F', $date, $format, $time, $month );
  659. }
  660. $date = date_i18n( $format, mktime( 0, 0, 0, $month, 1, $yr ) );
  661. $day = '';
  662. if ( 'week' === $time ) {
  663. $prevdate = strtotime( "$cur_year-$cur_month-$cur_day" . '- 7 days' );
  664. $day = mc_date( 'd', $prevdate, false );
  665. $yr = mc_date( 'Y', $prevdate, false );
  666. $month = mc_date( 'm', $prevdate, false );
  667. if ( (int) $yr !== (int) $cur_year ) {
  668. $format = 'F j, Y';
  669. } else {
  670. $format = 'F j';
  671. }
  672. $date = __( 'Week of ', 'my-calendar' ) . date_i18n( $format, mktime( 0, 0, 0, $month, $day, $yr ) );
  673. }
  674. if ( 'day' === $time ) {
  675. $prevdate = strtotime( "$cur_year-$cur_month-$cur_day" . '- 1 days' );
  676. $day = mc_date( 'd', $prevdate, false );
  677. $yr = mc_date( 'Y', $prevdate, false );
  678. $month = mc_date( 'm', $prevdate, false );
  679. if ( (int) $yr !== (int) $cur_year ) {
  680. $format = 'F j, Y';
  681. } else {
  682. $format = 'F j';
  683. }
  684. $date = date_i18n( $format, mktime( 0, 0, 0, $month, $day, $yr ) );
  685. }
  686. $previous_events = str_replace( '{date}', $date, $previous_events );
  687. $test_date = ( $day ) ? "$yr-$month-$day" : "$yr-" . str_pad( $month, 2, 0, STR_PAD_LEFT ) . '-' . mc_date( 't', strtotime( "$yr-$month" ) );
  688. if ( strtotime( $bounds['first'] ) > strtotime( $test_date ) ) {
  689. $output = false;
  690. } else {
  691. $output = array(
  692. 'month' => $month,
  693. 'yr' => $yr,
  694. 'day' => $day,
  695. 'label' => $previous_events,
  696. );
  697. }
  698. return $output;
  699. }
  700. /**
  701. * Generate filters form to limit calendar events.
  702. *
  703. * @param array $args can include 'categories', 'locations' and 'access' to define individual filters.
  704. * @param string $target_url Where to send queries.
  705. * @param string $ltype Which type of location data to show in form. Default ID.
  706. * @param array $options Array of values to include in the form.
  707. *
  708. * @return string HTML output of form
  709. */
  710. function mc_filters( $args, $target_url, $ltype = 'id', $options = array() ) {
  711. $id = ( isset( $args['id'] ) ) ? esc_attr( $args['id'] ) : 'mc_filters';
  712. if ( isset( $args['id'] ) ) {
  713. unset( $args['id'] );
  714. }
  715. if ( ! is_array( $args ) ) {
  716. $fields = explode( ',', $args );
  717. } else {
  718. $fields = $args;
  719. }
  720. if ( empty( $fields ) ) {
  721. return '';
  722. }
  723. $has_multiple = ( count( $fields ) > 1 ) ? true : false;
  724. $return = false;
  725. $current_url = mc_get_uri();
  726. $current_url = ( '' !== $target_url && esc_url( $target_url ) ) ? $target_url : $current_url;
  727. $class = ( $has_multiple ) ? 'mc-filters-form' : 'mc-' . esc_attr( $fields[0] ) . '-switcher';
  728. $form = "
  729. <div id='$id' class='mc_filters'>
  730. <form action='" . esc_url( $current_url ) . "' method='get' class='$class'>\n";
  731. $qsa = array();
  732. if ( isset( $_SERVER['QUERY_STRING'] ) ) {
  733. parse_str( map_deep( wp_unslash( $_SERVER['QUERY_STRING'] ), 'sanitize_text_field' ), $qsa );
  734. }
  735. if ( ! isset( $_GET['cid'] ) ) {
  736. $form .= '<input type="hidden" name="cid" value="all" />';
  737. }
  738. foreach ( $qsa as $name => $argument ) {
  739. $name = wp_strip_all_tags( $name );
  740. if ( ! ( 'access' === $name || 'mcat' === $name || 'loc' === $name || 'ltype' === $name || 'mc_id' === $name || 'legacy-widget-preview' === $name ) ) {
  741. $argument = ( ! is_string( $argument ) ) ? (string) $argument : $argument;
  742. $argument = wp_strip_all_tags( $argument );
  743. $form .= '<input type="hidden" name="' . esc_attr( $name ) . '" value="' . esc_attr( $argument ) . '" />' . "\n";
  744. }
  745. }
  746. $multiple = __( 'Events', 'my-calendar' );
  747. $key = '';
  748. foreach ( $fields as $show ) {
  749. $show = trim( $show );
  750. switch ( $show ) {
  751. case 'categories':
  752. $cats = my_calendar_categories_list( 'form', 'public', 'group', '', $options );
  753. $form .= '<div class="mc-category-filter">' . $cats . '</div>';
  754. $return = ( $cats || $return ) ? true : false;
  755. $key = __( 'Categories', 'my-calendar' );
  756. break;
  757. case 'locations':
  758. $locs = my_calendar_locations_list( 'form', $ltype, 'group' );
  759. $form .= '<div class="mc-location-filter">' . $locs . '</div>';
  760. $return = ( $locs || $return ) ? true : false;
  761. $key = __( 'Locations', 'my-calendar' );
  762. break;
  763. case 'access':
  764. $access = mc_access_list( 'form', 'group' );
  765. $form .= '<div class="mc-access-filter">' . $access . '</div>';
  766. $return = ( $access || $return ) ? true : false;
  767. $key = __( 'Accessibility Services', 'my-calendar' );
  768. break;
  769. }
  770. }
  771. $key = ( $has_multiple ) ? $multiple : $key;
  772. // Translators: Type of filter shown. Events, Categories, Locations, or Accessibility Services.
  773. $label = sprintf( __( 'Filter %s', 'my-calendar' ), '<span class="screen-reader-text"> ' . $key . '</span>' );
  774. $form .= '<p><button id="mc_filter_' . $show . '-' . $id . '" class="button" data-href="' . esc_url( $current_url ) . '">' . $label . '</button></p>
  775. </form></div>';
  776. if ( $return ) {
  777. return $form;
  778. }
  779. return '';
  780. }
  781. /**
  782. * Generate select form of categories for filters.
  783. *
  784. * @param string $show type of view.
  785. * @param string $context Public or admin.
  786. * @param string $group single form or part of a field group.
  787. * @param string $target_url Where to post form to.
  788. * @param array $options Categories to include in form.
  789. *
  790. * @return string HTML
  791. */
  792. function my_calendar_categories_list( $show = 'list', $context = 'public', $group = 'single', $target_url = '', $options = array() ) {
  793. $mcdb = mc_is_remote_db();
  794. $output = '';
  795. $current_url = mc_get_uri();
  796. $current_url = ( '' !== $target_url && esc_url( $target_url ) ) ? $target_url : $current_url;
  797. $name = ( 'public' === $context ) ? 'mcat' : 'category';
  798. $admin_fields = ( 'public' === $context ) ? ' name="' . $name . '"' : ' multiple="multiple" size="5" name="' . $name . '[]" ';
  799. $admin_label = ( 'public' === $context ) ? '' : __( '(select to include)', 'my-calendar' );
  800. $form = ( 'single' === $group ) ? '<form action="' . esc_url( $current_url ) . '" method="get">
  801. <div>' : '';
  802. if ( 'single' === $group ) {
  803. $qsa = array();
  804. if ( isset( $_SERVER['QUERY_STRING'] ) ) {
  805. parse_str( map_deep( wp_unslash( $_SERVER['QUERY_STRING'] ), 'sanitize_text_field' ), $qsa );
  806. }
  807. if ( ! isset( $_GET['cid'] ) ) {
  808. $form .= '<input type="hidden" name="cid" value="all" />';
  809. }
  810. foreach ( $qsa as $name => $argument ) {
  811. if ( ! ( 'mcat' === $name || 'mc_id' === $name ) ) {
  812. $form .= '<input type="hidden" name="' . esc_attr( wp_strip_all_tags( $name ) ) . '" value="' . esc_attr( wp_strip_all_tags( $argument ) ) . '" />' . "\n";
  813. }
  814. }
  815. }
  816. $form .= ( 'list' === $show || 'group' === $group ) ? '' : '
  817. </div><p>';
  818. $public_form = ( 'public' === $context ) ? $form : '';
  819. if ( ! is_user_logged_in() ) {
  820. $categories = $mcdb->get_results( 'SELECT * FROM ' . my_calendar_categories_table() . ' WHERE category_private = 0 ORDER BY category_name ASC' );
  821. } else {
  822. $categories = $mcdb->get_results( 'SELECT * FROM ' . my_calendar_categories_table() . ' ORDER BY category_name ASC' );
  823. }
  824. if ( ! empty( $categories ) && count( $categories ) >= 1 ) {
  825. $output = ( 'single' === $group ) ? "<div id='mc_categories'>\n" : '';
  826. $url = mc_build_url( array( 'mcat' => 'all' ), array() );
  827. $output .= ( 'list' === $show ) ? "
  828. <ul>
  829. <li><a href='$url' rel='nofollow'>" . __( 'All Categories', 'my-calendar' ) . '</a></li>' : $public_form . '
  830. <label for="category">' . __( 'Categories', 'my-calendar' ) . ' ' . $admin_label . '</label>
  831. <select' . $admin_fields . ' id="category">
  832. <option value="all">' . __( 'All Categories', 'my-calendar' ) . '</option>' . "\n";
  833. foreach ( $categories as $category ) {
  834. $category_name = strip_tags( stripcslashes( $category->category_name ), mc_strip_tags() );
  835. $mcat = ( empty( $_GET['mcat'] ) ) ? '' : (int) $_GET['mcat'];
  836. $category_id = (int) $category->category_id;
  837. if ( ! empty( $options ) ) {
  838. if ( ! in_array( $category_id, $options, true ) ) {
  839. continue;
  840. }
  841. }
  842. if ( 'list' === $show ) {
  843. $this_url = mc_build_url( array( 'mcat' => $category->category_id ), array() );
  844. $selected = ( $category_id === $mcat ) ? ' class="selected"' : '';
  845. $output .= " <li$selected><a rel='nofollow' href='$this_url'>$category_name</a></li>";
  846. } else {
  847. $selected = ( $category_id === $mcat ) ? ' selected="selected"' : '';
  848. $output .= " <option$selected value='$category_id'>$category_name</option>\n";
  849. }
  850. }
  851. $output .= ( 'list' === $show ) ? '</ul>' : '</select>';
  852. if ( 'admin' !== $context && 'list' !== $show ) {
  853. if ( 'single' === $group ) {
  854. $output .= '<input type="submit" class="button" value="' . __( 'Submit', 'my-calendar' ) . '" /></p></form>';
  855. }
  856. }
  857. $output .= ( 'single' === $group ) ? '</div>' : '';
  858. }
  859. /**
  860. * Filter the HTML for the category filter dropdown in navigation elements.
  861. *
  862. * @hook mc_category_selector
  863. *
  864. * @param {string} $toggle HTML output for control.
  865. * @param {array} $categories Available categories.
  866. *
  867. * @return {string}
  868. */
  869. $output = apply_filters( 'mc_category_selector', $output, $categories );
  870. return $output;
  871. }
  872. /**
  873. * Show set of filters to limit by accessibility features.
  874. *
  875. * @param string $show type of view.
  876. * @param string $group single or multiple.
  877. * @param string $target_url Where to post form to.
  878. *
  879. * @return string HTML
  880. */
  881. function mc_access_list( $show = 'list', $group = 'single', $target_url = '' ) {
  882. $output = '';
  883. $current_url = mc_get_uri();
  884. $current_url = ( '' !== $target_url && esc_url( $target_url ) ) ? $target_url : $current_url;
  885. $form = ( 'single' === $group ) ? "<form action='" . esc_url( $current_url ) . "' method='get'><div>" : '';
  886. if ( 'single' === $group ) {
  887. $qsa = array();
  888. if ( isset( $_SERVER['QUERY_STRING'] ) ) {
  889. parse_str( $_SERVER['QUERY_STRING'], $qsa );
  890. }
  891. if ( ! isset( $_GET['cid'] ) ) {
  892. $form .= '<input type="hidden" name="cid" value="all" />';
  893. }
  894. foreach ( $qsa as $name => $argument ) {
  895. if ( ! ( 'access' === $name || 'mc_id' === $name ) ) {
  896. $form .= '<input type="hidden" name="' . esc_attr( wp_strip_all_tags( $name ) ) . '" value="' . esc_attr( wp_strip_all_tags( $argument ) ) . '" />' . "\n";
  897. }
  898. }
  899. }
  900. $form .= ( 'list' === $show || 'group' === $group ) ? '' : '</div><p>';
  901. $access_options = mc_event_access();
  902. if ( ! empty( $access_options ) && count( $access_options ) >= 1 ) {
  903. $output = ( 'single' === $group ) ? "<div id='mc_access'>\n" : '';
  904. $url = mc_build_url( array( 'access' => 'all' ), array() );
  905. $not_selected = ( ! isset( $_GET['access'] ) ) ? ' selected="selected"' : '';
  906. $output .= ( 'list' === $show ) ? "
  907. <ul>
  908. <li><a href='$url'>" . __( 'Accessibility Services', 'my-calendar' ) . '</a></li>' : $form . '
  909. <label for="access">' . __( 'Accessibility Services', 'my-calendar' ) . '</label>
  910. <select name="access" id="access">
  911. <option value="all"' . $not_selected . '>' . __( 'All Services', 'my-calendar' ) . '</option>' . "\n";
  912. foreach ( $access_options as $key => $access ) {
  913. $access_name = $access;
  914. $this_access = ( empty( $_GET['access'] ) ) ? '' : (int) $_GET['access'];
  915. if ( 'list' === $show ) {
  916. $this_url = mc_build_url( array( 'access' => $key ), array() );
  917. $selected = ( $key === $this_access ) ? ' class="selected"' : '';
  918. $output .= " <li$selected><a rel='nofollow' href='$this_url'>$access_name</a></li>";
  919. } else {
  920. $selected = ( $this_access === $key ) ? ' selected="selected"' : '';
  921. $output .= " <option$selected value='" . esc_attr( $key ) . "'>" . esc_html( $access_name ) . "</option>\n";
  922. }
  923. }
  924. $output .= ( 'list' === $show ) ? '</ul>' : '</select>';
  925. $output .= ( 'list' !== $show && 'single' === $group ) ? '<p><input type="submit" class="button" value="' . __( 'Limit by Access', 'my-calendar' ) . '" /></p></form>' : '';
  926. $output .= ( 'single' === $group ) ? "\n</div>" : '';
  927. }
  928. /**
  929. * Filter the HTML for the accessibility feature filter in navigation elements.
  930. *
  931. * @hook mc_access_selector
  932. *
  933. * @param {string} $output HTML output for control.
  934. * @param {array} $access_options Available accessibility options.
  935. *
  936. * @return {string}
  937. */
  938. $output = apply_filters( 'mc_access_selector', $output, $access_options );
  939. return $output;
  940. }
  941. /**
  942. * Build date switcher
  943. *
  944. * @param string $type Current view being shown.
  945. * @param string $cid ID of current view.
  946. * @param string $time Current time view.
  947. * @param array $date current date array (month, year, day).
  948. * @param int $site Optional. Site ID if not current site.
  949. *
  950. * @return string HTML output.
  951. */
  952. function mc_date_switcher( $type = 'calendar', $cid = 'all', $time = 'month', $date = array(), $site = false ) {
  953. if ( 'week' === $time ) {
  954. return '';
  955. }
  956. $c_month = isset( $date['month'] ) ? $date['month'] : current_time( 'n' );
  957. $c_year = isset( $date['year'] ) ? $date['year'] : current_time( 'Y' );
  958. $c_day = isset( $date['day'] ) ? $date['day'] : current_time( 'j' );
  959. $current_url = mc_get_current_url();
  960. $date_switcher = '';
  961. $date_switcher .= '<div class="my-calendar-date-switcher"><form class="mc-date-switcher" action="' . esc_url( $current_url ) . '" method="get"><div>';
  962. $qsa = array();
  963. if ( isset( $_SERVER['QUERY_STRING'] ) ) {
  964. parse_str( $_SERVER['QUERY_STRING'], $qsa );
  965. }
  966. if ( ! isset( $_GET['cid'] ) ) {
  967. $date_switcher .= '<input type="hidden" name="cid" value="' . esc_attr( $cid ) . '" />';
  968. }
  969. $data_href = $current_url;
  970. foreach ( $qsa as $name => $argument ) {
  971. $name = esc_attr( wp_strip_all_tags( $name ) );
  972. if ( is_array( $argument ) ) {
  973. $argument = '';
  974. } else {
  975. $argument = esc_attr( wp_strip_all_tags( $argument ) );
  976. }
  977. if ( 'month' !== $name && 'yr' !== $name && 'dy' !== $name ) {
  978. $date_switcher .= '<input type="hidden" name="' . $name . '" value="' . $argument . '" />';
  979. $data_href = add_query_arg( $name, $argument, $data_href );
  980. }
  981. }
  982. $day_switcher = '';
  983. if ( 'day' === $time ) {
  984. $day_switcher = ' <label class="maybe-hide" for="' . $cid . '-day">' . __( 'Day', 'my-calendar' ) . '</label> <select id="' . $cid . '-day" name="dy">' . "\n";
  985. for ( $i = 1; $i <= 31; $i++ ) {
  986. $day_switcher .= "<option value='$i'" . selected( $i, $c_day, false ) . '>' . $i . '</option>' . "\n";
  987. }
  988. $day_switcher .= '</select>';
  989. }
  990. // We build the months in the switcher.
  991. $date_switcher .= ' <label class="maybe-hide" for="' . $cid . '-month">' . __( 'Month', 'my-calendar' ) . '</label> <select id="' . $cid . '-month" name="month">' . "\n";
  992. for ( $i = 1; $i <= 12; $i++ ) {
  993. $test = str_pad( $i, 2, '0', STR_PAD_LEFT );
  994. $c_month = str_pad( $c_month, 2, '0', STR_PAD_LEFT );
  995. $date_switcher .= "<option value='$i'" . selected( $test, $c_month, false ) . '>' . date_i18n( 'F', mktime( 0, 0, 0, $i, 1 ) ) . '</option>' . "\n";
  996. }
  997. $date_switcher .= '</select>' . "\n" . $day_switcher . ' <label class="maybe-hide" for="' . $cid . '-year">' . __( 'Year', 'my-calendar' ) . '</label> <select id="' . $cid . '-year" name="yr">' . "\n";
  998. // Check first start date in the database.
  999. $bounds = mc_get_date_bounds( $site );
  1000. $first = $bounds['first'];
  1001. $first = ( '1970-01-01 00:00:00' === $first ) ? '2000-01-01' : $first;
  1002. $year1 = (int) mc_date( 'Y', strtotime( $first, false ) );
  1003. $diff1 = (int) mc_date( 'Y' ) - $year1;
  1004. $past = $diff1;
  1005. // Check last end date.
  1006. $last = $bounds['last'];
  1007. $year2 = (int) mc_date( 'Y', strtotime( $last, false ) );
  1008. $diff2 = $year2 - (int) mc_date( 'Y' );
  1009. $future = $diff2;
  1010. /**
  1011. * How many years into the future should be shown in the navigation jumpbox. Default '5'.
  1012. *
  1013. * @hook mc_jumpbox_future_years
  1014. *
  1015. * @param {int} $future Number of years ahead.
  1016. * @param {string} $cid Current calendar ID. '' when running in the shortcode generator.
  1017. *
  1018. * @return {int}
  1019. */
  1020. $future = apply_filters( 'mc_jumpbox_future_years', $future, $cid );
  1021. $fut = 1;
  1022. $f = '';
  1023. $p = '';
  1024. $time = (int) current_time( 'Y' );
  1025. while ( $past > 0 ) {
  1026. $p .= '<option value="';
  1027. $p .= $time - $past;
  1028. $p .= '"' . selected( $time - $past, $c_year, false ) . '>';
  1029. $p .= $time - $past . "</option>\n";
  1030. $past = $past - 1;
  1031. }
  1032. while ( $fut <= $future ) {
  1033. $f .= '<option value="';
  1034. $f .= $time + $fut;
  1035. $f .= '"' . selected( $time + $fut, $c_year, false ) . '>';
  1036. $f .= $time + $fut . "</option>\n";
  1037. $fut = $fut + 1;
  1038. }
  1039. $date_switcher .= $p;
  1040. $date_switcher .= '<option value="' . $time . '"' . selected( $time, $c_year, false ) . '>' . $time . "</option>\n";
  1041. $date_switcher .= $f;
  1042. $date_switcher .= '</select> <input type="submit" class="button" data-href="' . esc_attr( $data_href ) . '" value="' . __( 'Go', 'my-calendar' ) . '" /></div></form></div>';
  1043. /**
  1044. * Filter the HTML for the date jumpbox controls.
  1045. *
  1046. * @hook mc_jumpbox
  1047. *
  1048. * @param {string} $date_switcher HTML output for control.
  1049. * @param {string} $type Current view format.
  1050. * @param {string} $time Current time frame.
  1051. *
  1052. * @return {string}
  1053. */
  1054. $date_switcher = apply_filters( 'mc_jumpbox', $date_switcher, $type, $time );
  1055. return $date_switcher;
  1056. }
  1057. /**
  1058. * Generate toggle between list and grid views
  1059. *
  1060. * @param string $format currently shown.
  1061. * @param string $toggle whether to show.
  1062. * @param string $time Current time view.
  1063. * @param string $id Calendar ID.
  1064. *
  1065. * @return string HTML output
  1066. */
  1067. function mc_format_toggle( $format, $toggle, $time, $id ) {
  1068. $enabled = mc_get_option( 'views' );
  1069. foreach ( $enabled as $key => $type ) {
  1070. if ( 'mini' === $type ) {
  1071. unset( $enabled[ $key ] );
  1072. }
  1073. }
  1074. // If there is only one format enabled, don't show format toggle.
  1075. if ( count( $enabled ) < 2 ) {
  1076. return '';
  1077. }
  1078. if ( 'mini' !== $format && 'yes' === $toggle ) {
  1079. if ( '1' !== mc_get_option( 'ajax_javascript' ) ) {
  1080. $is_grid = ( 'calendar' === $format ) ? ' aria-pressed="true"' : '';
  1081. $is_list = ( 'list' === $format ) ? ' aria-pressed="true"' : '';
  1082. $is_card = ( 'card' === $format ) ? ' aria-pressed="true"' : '';
  1083. } else {
  1084. $is_grid = ( 'calendar' === $format ) ? ' aria-current="true"' : '';
  1085. $is_list = ( 'list' === $format ) ? ' aria-current="true"' : '';
  1086. $is_card = ( 'card' === $format ) ? ' aria-current="true"' : '';
  1087. }
  1088. $grid_active = ( 'calendar' === $format ) ? ' mc-active' : '';
  1089. $list_active = ( 'list' === $format ) ? ' mc-active' : '';
  1090. $card_active = ( 'card' === $format ) ? ' mc-active' : '';
  1091. $toggle = "<div class='mc-format'>
  1092. <ul>";
  1093. if ( in_array( 'calendar', $enabled, true ) ) {
  1094. $url = mc_build_url( array( 'format' => 'calendar' ), array() );
  1095. $url = mc_url_in_loop( $url );
  1096. $toggle .= "<li><a id='mc_grid-$id' href='$url'" . $is_grid . " class='mc-grid-option$grid_active' rel='nofollow'><span class='mc-icon' aria-hidden='true'></span>" . __( '<span class="maybe-hide">View as </span>Grid', 'my-calendar' ) . '</a></li>';
  1097. }
  1098. if ( in_array( 'card', $enabled, true ) ) {
  1099. $url = mc_build_url( array( 'format' => 'card' ), array() );
  1100. $url = mc_url_in_loop( $url );
  1101. $toggle .= "<li><a id='mc_card-$id' href='$url'" . $is_card . " class='mc-card-option$card_active' rel='nofollow'><span class='mc-icon' aria-hidden='true'></span>" . __( '<span class="maybe-hide">View as </span>Cards', 'my-calendar' ) . '</a></li>';
  1102. }
  1103. if ( in_array( 'list', $enabled, true ) ) {
  1104. $url = mc_build_url( array( 'format' => 'list' ), array() );
  1105. $url = mc_url_in_loop( $url );
  1106. $toggle .= "<li><a id='mc_list-$id' href='$url'" . $is_list . " class='mc-list-option$list_active' rel='nofollow'><span class='mc-icon' aria-hidden='true'></span>" . __( '<span class="maybe-hide">View as </span>List', 'my-calendar' ) . '</a></li>';
  1107. }
  1108. $toggle .= '</ul>
  1109. </div>';
  1110. } else {
  1111. $toggle = '';
  1112. }
  1113. if ( 'day' === $time ) {
  1114. $toggle = "<div class='mc-format'><span class='mc-active list'>" . __( '<span class="maybe-hide">View as </span>List', 'my-calendar' ) . '</span></div>';
  1115. }
  1116. if ( ( 'true' === mc_get_option( 'convert' ) || 'mini' === mc_get_option( 'convert' ) ) && mc_is_mobile() ) {
  1117. $toggle = '';
  1118. }
  1119. /**
  1120. * Filter the HTML for the list/grid/card format switcher in navigation elements.
  1121. *
  1122. * @hook mc_format_toggle_html
  1123. *
  1124. * @param {string} $toggle HTML output for control.
  1125. * @param {string} $format Current view format.
  1126. * @param {string} $time Current time frame.
  1127. *
  1128. * @return {string}
  1129. */
  1130. return apply_filters( 'mc_format_toggle_html', $toggle, $format, $time );
  1131. }
  1132. /**
  1133. * Generate toggle for time views between day month & week
  1134. *
  1135. * @param string $format of current view.
  1136. * @param string $time timespan of current view.
  1137. * @param string|int $month Numeric value ofcurrent month.
  1138. * @param string|int $year current year.
  1139. * @param string $current Current date.
  1140. * @param int $start_of_week Day week starts on.
  1141. * @param string $from Date started from.
  1142. * @param string $id Current view ID.
  1143. *
  1144. * @return string HTML output
  1145. */
  1146. function mc_time_toggle( $format, $time, $month, $year, $current, $start_of_week, $from, $id ) {
  1147. // if dy parameter not set, use today's date instead of first day of month.
  1148. $aria = ( '1' !== mc_get_option( 'ajax_javascript' ) ) ? 'pressed' : 'current';
  1149. $month = (int) $month;
  1150. $year = (int) $year;
  1151. $weeks_day = mc_first_day_of_week( $current );
  1152. $adjusted = false;
  1153. if ( isset( $_GET['dy'] ) ) {
  1154. if ( '' === $_GET['dy'] ) {
  1155. $current_day = $weeks_day[0];
  1156. if ( -1 === (int) $weeks_day[1] ) {
  1157. $adjusted = true;
  1158. $month = $month - 1;
  1159. }
  1160. } else {
  1161. $current_day = absint( $_GET['dy'] );
  1162. }
  1163. $current_set = mktime( 0, 0, 0, $month, $current_day, $year );
  1164. if ( (int) mc_date( 'N', $current_set, false ) === $start_of_week ) {
  1165. $weeks_day = mc_first_day_of_week( $current_set );
  1166. }
  1167. } else {
  1168. $weeks_day = mc_first_day_of_week();
  1169. }
  1170. $day = $weeks_day[0];
  1171. if ( isset( $_GET['time'] ) && 'day' === $_GET['time'] ) {
  1172. // don't adjust day if viewing day format.
  1173. } else {
  1174. // if the current date is displayed and the week beginning day is greater than 20 in the month.
  1175. if ( ! isset( $_GET['dy'] ) && $day > 20 ) {
  1176. $day = mc_date( 'j', strtotime( "$from + 1 week" ), false );
  1177. }
  1178. }
  1179. $adjust = ( isset( $weeks_day[1] ) ) ? $weeks_day[1] : 0;
  1180. $toggle = '';
  1181. if ( 'mini' !== $format ) {
  1182. $toggle = "<div class='mc-time'><ul>";
  1183. if ( -1 === (int) $adjust && ! $adjusted ) {
  1184. $wmonth = ( 1 !== (int) $month ) ? $month - 1 : 12;
  1185. } else {
  1186. $wmonth = $month;
  1187. }
  1188. $month_url = mc_build_url( array( 'time' => 'month' ), array( 'mc_id' ) );
  1189. $week_url = mc_build_url(
  1190. array(
  1191. 'time' => 'week',
  1192. 'dy' => $day,
  1193. 'month' => $wmonth,
  1194. 'yr' => $year,
  1195. ),
  1196. array( 'dy', 'month', 'mc_id' )
  1197. );
  1198. $day_url = mc_build_url(
  1199. array(
  1200. 'time' => 'day',
  1201. 'dy' => $day,
  1202. ),
  1203. array( 'dy', 'mc_id' )
  1204. );
  1205. $month_active = ( 'month' === $time ) ? ' mc-active' : '';
  1206. $week_active = ( 'week' === $time ) ? ' mc-active' : '';
  1207. $day_active = ( 'day' === $time ) ? ' mc-active' : '';
  1208. $aria_month = ( 'month' === $time ) ? " aria-$aria='true'" : '';
  1209. $aria_week = ( 'week' === $time ) ? " aria-$aria='true'" : '';
  1210. $aria_day = ( 'day' === $time ) ? " aria-$aria='true'" : '';
  1211. $toggle .= "<li><a rel='nofollow' id='mc_month-$id' href='" . mc_url_in_loop( $month_url ) . "' class='month$month_active'$aria_month>" . __( 'Month', 'my-calendar' ) . '</a></li>';
  1212. $toggle .= "<li><a rel='nofollow' id='mc_week-$id' href='" . mc_url_in_loop( $week_url ) . "' class='week$week_active'$aria_week>" . __( 'Week', 'my-calendar' ) . '</a></li>';
  1213. $toggle .= "<li><a rel='nofollow' id='mc_day-$id' href='" . mc_url_in_loop( $day_url ) . "' class='day$day_active'$aria_day>" . __( 'Day', 'my-calendar' ) . '</a><li>';
  1214. $toggle .= '</ul></div>';
  1215. } else {
  1216. $toggle = '';
  1217. }
  1218. /**
  1219. * Filter the HTML for the time format switcher in navigation elements.
  1220. *
  1221. * @hook mc_time_toggle_html
  1222. *
  1223. * @param {string} $toggle HTML output for control.
  1224. * @param {string} $format Current view format.
  1225. * @param {string} $time Current time frame.
  1226. *
  1227. * @return {string}
  1228. */
  1229. return apply_filters( 'mc_time_toggle_html', $toggle, $format, $time );
  1230. }