functions.php 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878
  1. <?php
  2. function booked_is_timeslot_disabled( $date = false, $timeslot = false, $calendar_id = false ){
  3. if ( !$date || !$timeslot )
  4. return false;
  5. $disabled_timeslots = get_option( 'booked_disabled_timeslots', array() );
  6. $formatted_date = date( 'Y-m-d', strtotime( $date ) );
  7. if ( $calendar_id ):
  8. if ( isset( $disabled_timeslots[$calendar_id][$formatted_date][$timeslot] ) ):
  9. return true;
  10. endif;
  11. else:
  12. if ( isset( $disabled_timeslots[0][$formatted_date][$timeslot] ) ):
  13. return true;
  14. endif;
  15. endif;
  16. return false;
  17. }
  18. function booked_get_kb_article( $id ) {
  19. $kb_article = get_transient( 'booked_kb_article_' . $id );
  20. if (empty($kb_article)):
  21. $kb_article = json_decode(file_get_contents('https://api.ticksy.com/v1/boxystudio/1f45cd6a663dd7d0ea726c93430a0c32/article.json/' . $id), true);
  22. set_transient( 'booked_kb_article_' . $id, $kb_article, 86400 );
  23. endif;
  24. $output = '<a href="https://boxystudio.ticksy.com/article/' . $id . '/" target="_blank" class="welcome-icon welcome-learn-more">' . esc_html( $kb_article['article-data']['article_title'] ) . '&nbsp;&nbsp;<i class="booked-icon booked-icon-sign-out"></i></a>';
  25. return $output;
  26. }
  27. function booked_appointments_available( $year = false, $month = false, $day = false, $calendar_id = false, $return_array = false, $include_past = false ){
  28. $prevent_before = apply_filters('booked_prevent_appointments_before',get_option('booked_prevent_appointments_before',false));
  29. $prevent_after = apply_filters('booked_prevent_appointments_after',get_option('booked_prevent_appointments_after',false));
  30. $buffer = get_option('booked_appointment_buffer',0);
  31. $buffer_string = apply_filters('booked_appointment_buffer_string','+'.$buffer.' hours');
  32. $disabled_timeslots = get_option( 'booked_disabled_timeslots',array() );
  33. if ( !$include_past && $buffer ):
  34. $buffered_timestamp = strtotime( date_i18n( 'Y-m-d H:i:s' ) . $buffer_string );
  35. else:
  36. $buffered_timestamp = false;
  37. endif;
  38. if ( !$include_past && $prevent_before ):
  39. $prevent_before = date_i18n('Ymd',strtotime($prevent_before));
  40. endif;
  41. if ( !$include_past && $prevent_after ):
  42. $prevent_after = date_i18n('Ymd',strtotime($prevent_after));
  43. endif;
  44. if ( !$day ):
  45. $month = date_i18n('m',strtotime($year.'-'.$month));
  46. $local_time = current_time('timestamp');
  47. $current_month = date_i18n('Ym',$local_time);
  48. if (!$include_past && $year.$month < $current_month):
  49. return 0;
  50. elseif (!$include_past && $year.$month > $current_month):
  51. $check_timestamp = strtotime(date_i18n('Y-m-d H:i:s',$local_time).' '.$buffer_string);
  52. $start_timestamp = strtotime($year.'-'.$month.'-01 00:00:00');
  53. if ($check_timestamp > $start_timestamp):
  54. $hours_between = $check_timestamp - $start_timestamp;
  55. $hours_between = $hours_between / 3600;
  56. else:
  57. $hours_between = 0;
  58. endif;
  59. $start_timestamp = strtotime(date_i18n('Y-m-d H:i:s',$start_timestamp).' +'.floor($hours_between).' hours');
  60. $first_day = date_i18n('j',$start_timestamp);
  61. $last_day = date_i18n('t',strtotime($year.'-'.$month.'-01'));
  62. $end_timestamp = strtotime($year.'-'.$month.'-'.$last_day.' 23:59:59');
  63. elseif(!$include_past):
  64. $start_timestamp = strtotime($year.'-'.$month.'-'.date_i18n('d H:i:s',$local_time).' '.$buffer_string);
  65. $first_day = date_i18n('j',$start_timestamp);
  66. $last_day = date_i18n('t',strtotime($year.'-'.$month.'-01'));
  67. $end_timestamp = strtotime($year.'-'.$month.'-'.$last_day.' 23:59:59');
  68. else:
  69. $start_timestamp = strtotime($year.'-'.$month.'-01 '.$buffer_string);
  70. $first_day = date_i18n('j',$start_timestamp);
  71. $last_day = date_i18n('t',strtotime($year.'-'.$month.'-01'));
  72. $end_timestamp = strtotime($year.'-'.$month.'-'.$last_day.' 23:59:59');
  73. endif;
  74. $start_month = date_i18n('m',$start_timestamp);
  75. if (!$include_past && $start_month > $month):
  76. return 0;
  77. endif;
  78. else:
  79. $day = date_i18n('d',strtotime($year.'-'.$month.'-'.$day));
  80. $local_time = current_time('timestamp');
  81. $current_day = date_i18n('Ymd',$local_time);
  82. if (!$include_past && $year.$month.$day < $current_day):
  83. return 0;
  84. elseif (!$include_past && $year.$month.$day > $current_day):
  85. $check_timestamp = strtotime(date_i18n('Y-m-d H:i:s',$local_time).' '.$buffer_string);
  86. $start_timestamp = strtotime($year.'-'.$month.'-'.$day.' 23:59:59');
  87. if ($check_timestamp > $start_timestamp):
  88. $hours_between = $check_timestamp - $start_timestamp;
  89. $hours_between = floor( $hours_between / 3600 );
  90. else:
  91. $hours_between = 0;
  92. endif;
  93. $start_timestamp = strtotime(date_i18n('Y-m-d',$start_timestamp).' +'.$hours_between.' hours');
  94. $first_day = date_i18n('j',$start_timestamp);
  95. $last_day = date_i18n('j',$start_timestamp);
  96. $end_timestamp = strtotime($year.'-'.$month.'-'.$day.' 23:59:59');
  97. elseif(!$include_past):
  98. $start_timestamp = strtotime($year.'-'.$month.'-'.date_i18n('d H:i:s',$local_time).' '.$buffer_string);
  99. $first_day = date_i18n('j',$start_timestamp);
  100. $last_day = date_i18n('j',$start_timestamp);
  101. $end_timestamp = strtotime($year.'-'.$month.'-'.$day.' 23:59:59');
  102. else:
  103. $start_timestamp = strtotime( $year . '-' . $month . '-' . $day . ' 00:00:00' );
  104. $first_day = date_i18n('j',$start_timestamp);
  105. $last_day = date_i18n('j',$start_timestamp);
  106. $end_timestamp = strtotime( $year . '-' . $month . '-' . $day . ' 23:59:59' );
  107. endif;
  108. $start_day = date_i18n('d',$start_timestamp);
  109. if (!$include_past && $start_day > $day):
  110. return 0;
  111. endif;
  112. endif;
  113. $args = array(
  114. 'post_type' => 'booked_appointments',
  115. 'posts_per_page' => -1,
  116. 'post_status' => 'any',
  117. 'meta_query' => array(
  118. array(
  119. 'key' => '_appointment_timestamp',
  120. 'value' => array( strtotime( date_i18n('Y-m-d',$start_timestamp).' 00:00:00'), $end_timestamp ),
  121. 'compare' => 'BETWEEN',
  122. )
  123. )
  124. );
  125. if ($calendar_id):
  126. $args['tax_query'] = array(
  127. array(
  128. 'taxonomy' => 'booked_custom_calendars',
  129. 'field' => 'term_id',
  130. 'terms' => $calendar_id,
  131. )
  132. );
  133. endif;
  134. $appointments_array = array();
  135. $appointments_booked = array();
  136. $available_timeslots_array = array();
  137. $bookedAppointments = new WP_Query($args);
  138. if($bookedAppointments->have_posts()):
  139. while ($bookedAppointments->have_posts()):
  140. $bookedAppointments->the_post();
  141. global $post;
  142. $timestamp = get_post_meta($post->ID, '_appointment_timestamp',true);
  143. $timeslot = get_post_meta($post->ID, '_appointment_timeslot',true);
  144. $this_day = date_i18n('d',$timestamp);
  145. $this_month = date_i18n('m',$timestamp);
  146. $appointments_booked[$year.$this_month.$this_day.'_'.$timeslot] = (isset($appointments_booked[$year.$this_month.$this_day.'_'.$timeslot]) ? $appointments_booked[$year.$this_month.$this_day.'_'.$timeslot] + 1 : 1);
  147. endwhile;
  148. endif;
  149. $appointments_booked = apply_filters('booked_appointments_booked_array', $appointments_booked);
  150. if ($calendar_id):
  151. $booked_defaults = get_option('booked_defaults_'.$calendar_id);
  152. if (!$booked_defaults):
  153. $booked_defaults = get_option('booked_defaults');
  154. endif;
  155. else :
  156. $booked_defaults = get_option('booked_defaults');
  157. endif;
  158. $booked_defaults = booked_apply_custom_timeslots_filter($booked_defaults,$calendar_id);
  159. $current_timestamp = $start_timestamp;
  160. $available_timeslots = 0;
  161. for($i = $first_day; $i <= $last_day; $i++){
  162. $day_name = date('D',strtotime($year.'-'.$month.'-'.$i));
  163. $date_string = date_i18n('Ymd',strtotime($year.'-'.$month.'-'.$i));
  164. if (isset($booked_defaults[$date_string]) && empty($booked_defaults[$date_string])):
  165. continue;
  166. endif;
  167. $this_date_compare = date_i18n('Ymd',strtotime($year.'-'.$month.'-'.$i));
  168. if (!$include_past && $prevent_before && $prevent_before > $this_date_compare || !$include_past && $prevent_after && $this_date_compare > $prevent_after):
  169. continue;
  170. endif;
  171. if (isset($booked_defaults[$date_string]) && !empty($booked_defaults[$date_string])):
  172. if (!is_array($booked_defaults[$date_string])):
  173. $booked_defaults[$date_string] = json_decode($booked_defaults[$date_string],true);
  174. endif;
  175. foreach($booked_defaults[$date_string] as $timeslot => $count):
  176. $date_check = date_i18n('Y-m-d',strtotime($date_string));
  177. $disabled_date_check = date('Y-m-d',strtotime($date_string));
  178. if ( $calendar_id && isset($disabled_timeslots[$calendar_id][$disabled_date_check][$timeslot]) || !$calendar_id && isset($disabled_timeslots[0][$disabled_date_check][$timeslot]) ):
  179. continue;
  180. endif;
  181. $timeslot_array = explode('-',$timeslot);
  182. $this_timeslot_startstamp = strtotime($year.'-'.$month.'-'.$i.' '.$timeslot_array[0]);
  183. if ( !$include_past || $include_past && $current_timestamp <= $this_timeslot_startstamp && apply_filters('booked_check_timeslot_startstamp',$this_timeslot_startstamp) ):
  184. if ( !$include_past && $buffered_timestamp <= $this_timeslot_startstamp ):
  185. $available_timeslots_array[$date_check][$timeslot] = ( isset($available_timeslots_array[$date_check][$timeslot]) ? $available_timeslots_array[$date_check][$timeslot] + $count : $count );
  186. $available_timeslots = $available_timeslots + $count;
  187. endif;
  188. endif;
  189. if (isset($appointments_booked[$date_string.'_'.$timeslot])):
  190. $available_timeslots = $available_timeslots - $appointments_booked[$date_string.'_'.$timeslot];
  191. $available_timeslots_array[$date_check][$timeslot] = ( isset($available_timeslots_array[$date_check][$timeslot]) ? $available_timeslots_array[$date_check][$timeslot] - $appointments_booked[$date_string.'_'.$timeslot] : 0 );
  192. if ($available_timeslots < 0): $available_timeslots = 0; endif;
  193. if ( isset($available_timeslots_array[$date_check][$timeslot]) && $available_timeslots_array[$date_check][$timeslot] < 0): $available_timeslots_array[$date_check][$timeslot] = 0; endif;
  194. endif;
  195. endforeach;
  196. elseif (isset($booked_defaults[$day_name]) && !empty($booked_defaults[$day_name])):
  197. if (!is_array($booked_defaults[$day_name])):
  198. $booked_defaults[$day_name] = json_decode($booked_defaults[$day_name],true);
  199. endif;
  200. foreach($booked_defaults[$day_name] as $timeslot => $count):
  201. $timeslot_array = explode('-',$timeslot);
  202. $this_timeslot_startstamp = strtotime($year.'-'.$month.'-'.$i.' '.$timeslot_array[0]);
  203. $date_check = date_i18n('Y-m-d',strtotime($date_string));
  204. $disabled_date_check = date('Y-m-d',strtotime($date_string));
  205. if ( $calendar_id && isset($disabled_timeslots[$calendar_id][$disabled_date_check][$timeslot]) || !$calendar_id && isset($disabled_timeslots[0][$disabled_date_check][$timeslot]) ):
  206. continue;
  207. endif;
  208. if ( $include_past || !$include_past && $current_timestamp <= $this_timeslot_startstamp && apply_filters('booked_check_timeslot_startstamp',$this_timeslot_startstamp)):
  209. if ( $include_past || !$include_past && $buffered_timestamp <= $this_timeslot_startstamp ):
  210. $available_timeslots_array[$date_check][$timeslot] = ( isset($available_timeslots_array[$date_check][$timeslot]) ? $available_timeslots_array[$date_check][$timeslot] + $count : $count );
  211. $available_timeslots = $available_timeslots + $count;
  212. endif;
  213. endif;
  214. if (isset($appointments_booked[$date_string.'_'.$timeslot])):
  215. $available_timeslots = $available_timeslots - $appointments_booked[$date_string.'_'.$timeslot];
  216. $available_timeslots_array[$date_check][$timeslot] = ( isset($available_timeslots_array[$date_check][$timeslot]) ? $available_timeslots_array[$date_check][$timeslot] - $appointments_booked[$date_string.'_'.$timeslot] : 0 );
  217. if ($available_timeslots < 0): $available_timeslots = 0; endif;
  218. if ( isset($available_timeslots_array[$date_check][$timeslot]) && $available_timeslots_array[$date_check][$timeslot] < 0): $available_timeslots_array[$date_check][$timeslot] = 0; endif;
  219. endif;
  220. endforeach;
  221. endif;
  222. }
  223. if ( $available_timeslots < 0 ):
  224. return 0;
  225. else:
  226. if ( $return_array ):
  227. return $available_timeslots_array;
  228. else:
  229. return $available_timeslots;
  230. endif;
  231. endif;
  232. }
  233. // Booked Front-End Calendar
  234. function booked_fe_calendar($year = false,$month = false,$calendar_id = false,$force_calendar = false){
  235. do_action('booked_fe_calendar_before');
  236. $prevent_before = apply_filters('booked_prevent_appointments_before',get_option('booked_prevent_appointments_before',false));
  237. $prevent_after = apply_filters('booked_prevent_appointments_after',get_option('booked_prevent_appointments_after',false));
  238. if ($prevent_before):
  239. $prevent_before = date_i18n('Ymd',strtotime($prevent_before));
  240. endif;
  241. if ($prevent_after):
  242. $prevent_after = date_i18n('Ymd',strtotime($prevent_after));
  243. endif;
  244. $initial_month = $month;
  245. $initial_year = $year;
  246. $local_time = current_time('timestamp');
  247. if ($calendar_id == 'undefined'): $calendar_id = 0; endif;
  248. $year = ($year ? $year : date_i18n('Y',$local_time));
  249. $month = ($month ? $month : date_i18n('m',$local_time));
  250. $today = date_i18n('j',$local_time);
  251. $currentMonth = date_i18n('Y-m-01',$local_time);
  252. if (!$force_calendar):
  253. $saved_month = $month;
  254. $saved_year = $year;
  255. $counter = 0;
  256. do {
  257. $appointments_available = booked_appointments_available($year,$month,false,$calendar_id);
  258. if (!$appointments_available):
  259. if ($month == '12'):
  260. $month = '01';
  261. $year = $year + 1;
  262. else:
  263. $month = date_i18n('m',strtotime($year.'-'.$month.'-01 +1 month'));
  264. endif;
  265. else:
  266. break;
  267. endif;
  268. $counter++;
  269. } while (!$appointments_available && $counter <= 12);
  270. if ($counter > 12): $month = $saved_month; $year = $saved_year; endif;
  271. $currentMonth = date_i18n('Y-m-01',strtotime($year.'-'.$month.'-01'));
  272. else:
  273. $currentMonth = $force_calendar;
  274. endif;
  275. $last_day = date_i18n('t',strtotime($year.'-'.$month));
  276. $monthShown = date_i18n('Y-m-01',strtotime($year.'-'.$month.'-01'));
  277. $first_day_of_week = (get_option('start_of_week') == 0 ? 7 : 1); // 1 = Monday, 7 = Sunday, Get from WordPress Settings
  278. $start_timestamp = strtotime($year.'-'.$month.'-01 00:00:00 -7 days');
  279. $end_timestamp = strtotime($year.'-'.$month.'-'.$last_day.' 23:59:59 +7 days');
  280. $args = array(
  281. 'post_type' => 'booked_appointments',
  282. 'posts_per_page' => -1,
  283. 'post_status' => 'any',
  284. 'meta_query' => array(
  285. array(
  286. 'key' => '_appointment_timestamp',
  287. 'value' => array( $start_timestamp, $end_timestamp ),
  288. 'compare' => 'BETWEEN',
  289. )
  290. )
  291. );
  292. if ($calendar_id):
  293. $args['tax_query'] = array(
  294. array(
  295. 'taxonomy' => 'booked_custom_calendars',
  296. 'field' => 'term_id',
  297. 'terms' => $calendar_id,
  298. )
  299. );
  300. endif;
  301. $appointments_array = array();
  302. $bookedAppointments = new WP_Query($args);
  303. if($bookedAppointments->have_posts()):
  304. while ($bookedAppointments->have_posts()):
  305. $bookedAppointments->the_post();
  306. global $post;
  307. $timestamp = get_post_meta($post->ID, '_appointment_timestamp',true);
  308. $timeslot = get_post_meta($post->ID, '_appointment_timeslot',true);
  309. $this_day = date_i18n('j',$timestamp);
  310. $this_month = date_i18n('m',$timestamp);
  311. $this_year = date_i18n('Y',$timestamp);
  312. $appointments_array[$this_year.$this_month.$this_day][$post->ID]['timeslot'] = $timeslot;
  313. $appointments_array[$this_year.$this_month.$this_day][$post->ID]['timestamp'] = $timestamp;
  314. $appointments_array[$this_year.$this_month.$this_day][$post->ID]['status'] = $post->post_status;
  315. endwhile;
  316. endif;
  317. $appointments_array = apply_filters( 'booked_appointments_date_array', $appointments_array );
  318. $hide_weekends = get_option('booked_hide_weekends',false);
  319. $hide_available_count = get_option('booked_hide_available_timeslots',false);
  320. $booked_pa_active = get_option('booked_public_appointments',false);
  321. // Appointments Array
  322. // [DAY] => [POST_ID] => [TIMESTAMP/STATUS]
  323. ?><table class="booked-calendar<?php echo ($booked_pa_active ? ' booked-pa-active' : ''); ?>"<?php echo ($calendar_id ? ' data-calendar-id="'.$calendar_id.'"' : ''); ?><?php echo (!$force_calendar ? ' data-calendar-date="'.$currentMonth.'"' : ''); ?>>
  324. <thead>
  325. <?php
  326. $next_month = date_i18n('Y-m-01', strtotime("+1 month", strtotime($year.'-'.$month.'-01')));
  327. $prev_month = date_i18n('Y-m-01', strtotime("-1 month", strtotime($year.'-'.$month.'-01')));
  328. $next_month_compare = date_i18n('Ymd',strtotime($next_month));
  329. if ($prevent_after && $next_month_compare > $prevent_after): $no_next_link = true; else: $no_next_link = false; endif;
  330. ?>
  331. <tr>
  332. <th colspan="<?php if (!$hide_weekends): ?>7<?php else: ?>5<?php endif; ?>">
  333. <?php if ($monthShown != $currentMonth): ?><a href="#" data-goto="<?php echo $prev_month; ?>" class="page-left"><i class="booked-icon booked-icon-arrow-left"></i></a><?php endif; ?>
  334. <span class="calendarSavingState">
  335. <i class="booked-icon booked-icon-spinner-clock booked-icon-spin"></i>
  336. </span>
  337. <span class="monthName">
  338. <?php echo date_i18n("F Y", strtotime($year.'-'.$month.'-01')); ?>
  339. <?php if ($monthShown != $currentMonth): ?>
  340. <a href="#" class="backToMonth" data-goto="<?php echo $currentMonth; ?>"><?php esc_html_e('Back to','booked'); ?> <?php echo date_i18n('F',strtotime($currentMonth)); ?></a>
  341. <?php endif; ?>
  342. </span>
  343. <?php if (!$no_next_link): ?><a href="#" data-goto="<?php echo $next_month; ?>" class="page-right"><i class="booked-icon booked-icon-arrow-right"></i></a><?php endif; ?>
  344. </th>
  345. </tr>
  346. <tr class="days">
  347. <?php if ($first_day_of_week == 7 && !$hide_weekends): echo '<th>' . date_i18n( 'D', strtotime('Sunday') ) . '</th>'; endif; ?>
  348. <th><?php echo date_i18n( 'D', strtotime('Monday') ); ?></th>
  349. <th><?php echo date_i18n( 'D', strtotime('Tuesday') ); ?></th>
  350. <th><?php echo date_i18n( 'D', strtotime('Wednesday') ); ?></th>
  351. <th><?php echo date_i18n( 'D', strtotime('Thursday') ); ?></th>
  352. <th><?php echo date_i18n( 'D', strtotime('Friday') ); ?></th>
  353. <?php if (!$hide_weekends): ?><th><?php echo date_i18n( 'D', strtotime('Saturday') ); ?></th><?php endif; ?>
  354. <?php if ($first_day_of_week == 1 && !$hide_weekends): echo '<th>'. date_i18n( 'D', strtotime('Sunday') ) .'</th>'; endif; ?>
  355. </tr>
  356. </thead>
  357. <tbody><?php
  358. $today_date = date_i18n('Y',$local_time).'-'.date_i18n('m',$local_time).'-'.date_i18n('j',$local_time);
  359. $days = date_i18n("t",strtotime($year.'-'.$month.'-01')); // Days in current month
  360. $lastmonth = date_i18n("t", mktime(0,0,0,$month-1,1,$year)); // Days in previous month
  361. $start = date_i18n("N", mktime(0,0,0,$month,1,$year)); // Starting day of current month
  362. if ($first_day_of_week == 7): $start = $start + 1; endif;
  363. if ($start > 7): $start = 1; endif;
  364. $finish = $days; // Finishing day of current month
  365. $laststart = $start - 1; // Days of previous month in calander
  366. $counter = 1;
  367. $nextMonthCounter = 1;
  368. if ($calendar_id):
  369. $booked_defaults = get_option('booked_defaults_'.$calendar_id);
  370. if (!$booked_defaults):
  371. $booked_defaults = get_option('booked_defaults');
  372. endif;
  373. else :
  374. $booked_defaults = get_option('booked_defaults');
  375. endif;
  376. $booked_defaults = booked_apply_custom_timeslots_filter($booked_defaults,$calendar_id);
  377. $buffer = get_option('booked_appointment_buffer',0);
  378. $buffer_string = apply_filters('booked_appointment_buffer_string','+'.$buffer.' hours');
  379. if($start > 5){ $rows = 6; } else { $rows = 5; }
  380. for($i = 1; $i <= $rows; $i++){
  381. echo '<tr class="week">';
  382. $day_count = 0;
  383. for($x = 1; $x <= 7; $x++){
  384. $classes = array();
  385. $appointments_count = 0;
  386. $check_month = $month;
  387. if(($counter - $start) < 0){
  388. $date = (($lastmonth - $laststart) + $counter);
  389. $classes[] = 'prev-month';
  390. $check_month = $month - 1;
  391. if (strlen($check_month) < 2): $check_month = '0'.$check_month; endif;
  392. $day_name = date('D',strtotime($year.'-'.$check_month.'-'.$date));
  393. } else {
  394. if(($counter - $start) >= $days){
  395. $date = ($nextMonthCounter);
  396. $nextMonthCounter++;
  397. $classes[] = 'next-month';
  398. $check_month = $month + 1;
  399. if (strlen($check_month) < 2): $check_month = '0'.$check_month; endif;
  400. $day_name = date('D',strtotime($year.'-'.$check_month.'-'.$date));
  401. if ($day_count == 0): break; endif;
  402. } else {
  403. $date = ($counter - $start + 1);
  404. if($today == $counter - $start + 1){
  405. if ($today_date == $year.'-'.$month.'-'.$date):
  406. $classes[] = 'today';
  407. endif;
  408. }
  409. $day_name = date('D',strtotime($year.'-'.$month.'-'.$date));
  410. }
  411. }
  412. if ($buffer):
  413. $current_timestamp = $local_time;
  414. $buffered_timestamp = strtotime($buffer_string,$current_timestamp);
  415. $date_to_compare = $buffered_timestamp;
  416. $currentTime = date_i18n('H:i:s',$buffered_timestamp);
  417. else:
  418. $date_to_compare = $local_time;
  419. $currentTime = date_i18n('H:i:s');
  420. endif;
  421. $formatted_date = date_i18n('Ymd',strtotime($year.'-'.$check_month.'-'.$date));
  422. if (isset($booked_defaults[$formatted_date]) && !empty($booked_defaults[$formatted_date])):
  423. $full_count = (is_array($booked_defaults[$formatted_date]) ? $booked_defaults[$formatted_date] : json_decode($booked_defaults[$formatted_date],true));
  424. elseif (isset($booked_defaults[$formatted_date]) && empty($booked_defaults[$formatted_date])):
  425. $full_count = false;
  426. elseif (isset($booked_defaults[$day_name]) && !empty($booked_defaults[$day_name])):
  427. $full_count = $booked_defaults[$day_name];
  428. else :
  429. $full_count = false;
  430. endif;
  431. $total_full_count = 0;
  432. if ($full_count):
  433. foreach($full_count as $full_counter){
  434. $total_full_count = $total_full_count + $full_counter;
  435. }
  436. endif;
  437. if (isset($booked_defaults[$formatted_date]) && !is_array($booked_defaults[$formatted_date])):
  438. $booked_defaults[$formatted_date] = json_decode($booked_defaults[$formatted_date],true);
  439. endif;
  440. $appointments_count = 0;
  441. if (isset($appointments_array[$year.$check_month.$date]) && !empty($appointments_array[$year.$check_month.$date])):
  442. foreach($appointments_array[$year.$check_month.$date] as $appt):
  443. if (isset($booked_defaults[$formatted_date][$appt['timeslot']])):
  444. $appointments_count++;
  445. elseif (!isset($booked_defaults[$formatted_date]) && isset($booked_defaults[$day_name]) && !empty($booked_defaults[$day_name]) && isset($booked_defaults[$day_name][$appt['timeslot']])):
  446. $appointments_count = $appointments_count + 1;
  447. endif;
  448. endforeach;
  449. endif;
  450. $this_date_compare = date_i18n('Ymd',strtotime($year.'-'.$check_month.'-'.$date));
  451. if ($appointments_count >= $total_full_count && $total_full_count > 0):
  452. if ($prevent_before && $prevent_before > $this_date_compare || $prevent_after && $this_date_compare > $prevent_after):
  453. // No Booked Class added.
  454. else:
  455. $classes[] = 'booked';
  456. endif;
  457. endif;
  458. if (
  459. strtotime($year.'-'.$check_month.'-'.$date.' '.$currentTime) < $date_to_compare
  460. || $prevent_before && $this_date_compare < $prevent_before
  461. || $prevent_after && $this_date_compare > $prevent_after
  462. || $appointments_count >= $total_full_count && strtotime($year.'-'.$check_month.'-'.$date.' '.$currentTime) < $date_to_compare
  463. || $appointments_count >= $total_full_count && $total_full_count < 1
  464. || $appointments_count >= $total_full_count && $prevent_before && $prevent_before > $this_date_compare
  465. || $appointments_count >= $total_full_count && $prevent_after && $this_date_compare > $prevent_after):
  466. $classes[] = 'prev-date';
  467. endif;
  468. $check_year = $year;
  469. if ($check_month == 0):
  470. $check_month = 12;
  471. $check_year = $year - 1;
  472. elseif ($check_month == 13):
  473. $check_month = 1;
  474. $check_year = $year + 1;
  475. endif;
  476. $check_month = date_i18n('m',strtotime($year.'-'.$check_month.'-'.$date));
  477. $appointments_left = booked_appointments_available($year,$check_month,$date,$calendar_id);
  478. if (!$appointments_left):
  479. if (!$booked_pa_active):
  480. if (!in_array('prev-date',$classes)):
  481. $classes[] = 'prev-date';
  482. endif;
  483. endif;
  484. endif;
  485. $day_of_week = date_i18n('N',strtotime($check_year.'-'.$check_month.'-'.$date));
  486. if ($hide_weekends && $day_of_week == 6 || $hide_weekends && $day_of_week == 7):
  487. $html = '';
  488. else:
  489. $day_count++;
  490. $html = '<td data-date="'.$check_year.'-'.$check_month.'-'.$date.'" class="'.implode(' ',$classes).'">';
  491. $html .= '<span class="date'.(!$hide_available_count && $appointments_left > 0 && !in_array('prev-date',$classes) && !in_array('blur',$classes) ? ' tooltipster" title="'.sprintf( _n('%d Available','%d Available',$appointments_left,'booked'),$appointments_left) : (!$hide_available_count && !$appointments_left && $booked_pa_active && !in_array('prev-date',$classes) && !in_array('blur',$classes) ? ' tooltipster" title="'.esc_html__('None Available','booked').'"' : '')).'"><span class="number">'. $date .'</span></span>';
  492. $html .= '</td>';
  493. $combined_date = $year.'-'.$check_month.'-'.$date;
  494. echo apply_filters('booked_fe_single_date',$html,$combined_date,$classes);
  495. endif;
  496. $counter++;
  497. $class = '';
  498. }
  499. echo '</tr>';
  500. } ?>
  501. </tbody>
  502. </table><?php
  503. do_action('booked_fe_calendar_after');
  504. }
  505. function booked_fe_calendar_date_content($date,$calendar_id = false){
  506. do_action('booked_fe_calendar_date_before');
  507. $hide_unavailable_timeslots = get_option('booked_hide_unavailable_timeslots',false);
  508. $hide_available_count = get_option('booked_hide_available_timeslots',false);
  509. $public_appointments = get_option('booked_public_appointments',false);
  510. $total_available = 0;
  511. echo '<div class="booked-appt-list">';
  512. /*
  513. Set some variables
  514. */
  515. $local_time = current_time('timestamp');
  516. $year = date_i18n('Y',strtotime($date));
  517. $month = date_i18n('m',strtotime($date));
  518. $day = date_i18n('d',strtotime($date));
  519. $start_timestamp = strtotime($year.'-'.$month.'-'.$day.' 00:00:00');
  520. $end_timestamp = strtotime($year.'-'.$month.'-'.$day.' 23:59:59');
  521. $date_format = get_option('date_format');
  522. $time_format = get_option('time_format');
  523. $date_display = date_i18n($date_format,strtotime($date));
  524. $day_name = date('D',strtotime($date));
  525. /*
  526. Grab all of the appointments for this day
  527. */
  528. $args = array(
  529. 'post_type' => 'booked_appointments',
  530. 'posts_per_page' => -1,
  531. 'post_status' => 'any',
  532. 'meta_query' => array(
  533. array(
  534. 'key' => '_appointment_timestamp',
  535. 'value' => array( $start_timestamp, $end_timestamp ),
  536. 'compare' => 'BETWEEN'
  537. )
  538. )
  539. );
  540. if ($calendar_id):
  541. $args['tax_query'] = array(
  542. array(
  543. 'taxonomy' => 'booked_custom_calendars',
  544. 'field' => 'term_id',
  545. 'terms' => $calendar_id,
  546. )
  547. );
  548. endif;
  549. $appointments_array = array();
  550. $bookedAppointments = new WP_Query( apply_filters('booked_fe_date_content_query',$args) );
  551. if($bookedAppointments->have_posts()):
  552. while ($bookedAppointments->have_posts()):
  553. $bookedAppointments->the_post();
  554. global $post;
  555. $timestamp = get_post_meta($post->ID, '_appointment_timestamp',true);
  556. $timeslot = get_post_meta($post->ID, '_appointment_timeslot',true);
  557. $user_id = get_post_meta($post->ID, '_appointment_user',true);
  558. $day = date_i18n('d',$timestamp);
  559. $appointments_array[$post->ID]['post_id'] = $post->ID;
  560. $appointments_array[$post->ID]['timestamp'] = $timestamp;
  561. $appointments_array[$post->ID]['timeslot'] = $timeslot;
  562. $appointments_array[$post->ID]['status'] = $post->post_status;
  563. $appointments_array[$post->ID]['user'] = $user_id;
  564. endwhile;
  565. endif;
  566. $appointments_array = apply_filters('booked_appointments_array', $appointments_array);
  567. ob_start();
  568. if ($calendar_id):
  569. $booked_defaults = get_option('booked_defaults_'.$calendar_id);
  570. if (!$booked_defaults):
  571. $booked_defaults = get_option('booked_defaults');
  572. endif;
  573. else :
  574. $booked_defaults = get_option('booked_defaults');
  575. endif;
  576. $formatted_date = date_i18n('Ymd',strtotime($date));
  577. $disabled_formatted_date = date( 'Y-m-d', strtotime( $date ) );
  578. $booked_defaults = booked_apply_custom_timeslots_details_filter($booked_defaults,$calendar_id);
  579. if (isset($booked_defaults[$formatted_date]) && !empty($booked_defaults[$formatted_date])):
  580. $todays_defaults = (is_array($booked_defaults[$formatted_date]) ? $booked_defaults[$formatted_date] : json_decode($booked_defaults[$formatted_date],true));
  581. $todays_defaults_details = (is_array($booked_defaults[$formatted_date.'-details']) ? $booked_defaults[$formatted_date.'-details'] : json_decode($booked_defaults[$formatted_date.'-details'],true));
  582. elseif (isset($booked_defaults[$formatted_date]) && empty($booked_defaults[$formatted_date])):
  583. $todays_defaults = false;
  584. $todays_defaults_details = false;
  585. elseif (isset($booked_defaults[$day_name]) && !empty($booked_defaults[$day_name])):
  586. $todays_defaults = $booked_defaults[$day_name];
  587. $todays_defaults_details = ( isset($booked_defaults[$day_name]) ? $booked_defaults[$day_name.'-details'] : false );
  588. else :
  589. $todays_defaults = false;
  590. $todays_defaults_details = false;
  591. endif;
  592. /*
  593. There are timeslots available, let's loop through them
  594. */
  595. if ($todays_defaults){
  596. ksort($todays_defaults);
  597. $temp_count = 0;
  598. foreach($todays_defaults as $timeslot => $count):
  599. $appts_in_this_timeslot = array();
  600. /*
  601. Are there any appointments in this particular timeslot?
  602. If so, let's create an array of them.
  603. */
  604. foreach($appointments_array as $post_id => $appointment):
  605. if ($appointment['timeslot'] == $timeslot):
  606. $appts_in_this_timeslot[] = $post_id;
  607. endif;
  608. endforeach;
  609. /*
  610. Calculate the number of spots available based on total minus the appointments booked
  611. */
  612. $spots_available = $count - count($appts_in_this_timeslot);
  613. $spots_available = ($spots_available < 0 ? 0 : $spots_available);
  614. /*
  615. Display the timeslot
  616. */
  617. $disabled_timeslots = get_option( 'booked_disabled_timeslots', array() );
  618. $timeslot_parts = explode('-',$timeslot);
  619. $buffer = get_option('booked_appointment_buffer',0);
  620. $buffer_string = apply_filters('booked_appointment_buffer_string','+'.$buffer.' hours');
  621. if ($buffer):
  622. $current_timestamp = $local_time;
  623. $buffered_timestamp = strtotime($buffer_string,$current_timestamp);
  624. $current_timestamp = $buffered_timestamp;
  625. else:
  626. $current_timestamp = $local_time;
  627. endif;
  628. $this_timeslot_timestamp = strtotime($year.'-'.$month.'-'.$day.' '.$timeslot_parts[0]);
  629. $spots_available = apply_filters('booked_spots_available', $spots_available, $this_timeslot_timestamp);
  630. if ($current_timestamp < $this_timeslot_timestamp){
  631. $available = true;
  632. } else {
  633. $available = false;
  634. }
  635. if ( $calendar_id && isset($disabled_timeslots[$calendar_id][$disabled_formatted_date][$timeslot]) || !$calendar_id && isset($disabled_timeslots[0][$disabled_formatted_date][$timeslot]) ):
  636. continue;
  637. endif;
  638. if ($spots_available && $available || !$hide_unavailable_timeslots):
  639. $total_available = $total_available + $spots_available;
  640. $temp_count++;
  641. if ($timeslot_parts[0] == '0000' && $timeslot_parts[1] == '2400'):
  642. $timeslotText = esc_html__('All day','booked');
  643. else :
  644. $timeslotText = date_i18n($time_format,strtotime($timeslot_parts[0])) . (!get_option('booked_hide_end_times') ? ' &ndash; '.date_i18n($time_format,strtotime($timeslot_parts[1])) : '');
  645. endif;
  646. $only_titles = get_option('booked_show_only_titles',false);
  647. $title = '';
  648. if ( !empty( $todays_defaults_details[$timeslot] ) ) {
  649. $title = !empty($todays_defaults_details[$timeslot]['title']) ? $todays_defaults_details[$timeslot]['title'] : '';
  650. }
  651. if ($hide_unavailable_timeslots && !$available):
  652. $html = '';
  653. else:
  654. $button_text = (!$spots_available || !$available ? esc_html__('Unavailable','booked') : esc_html__('Book Appointment','booked'));
  655. $html = '<div class="timeslot bookedClearFix'.($title && $only_titles == true ? ' booked-hide-time' : '').($hide_available_count || !$available ? ' timeslot-count-hidden' : '').(!$available ? ' timeslot-unavailable' : '').($title ? ' has-title ' : '').'">';
  656. $html .= '<span class="timeslot-time'.($public_appointments ? ' booked-public-appointments' : '').'">';
  657. $html .= apply_filters('booked_fe_calendar_timeslot_before','',$this_timeslot_timestamp,$timeslot,$calendar_id);
  658. if ( $title ) {
  659. $html .= '<span class="timeslot-title">' . esc_html($title) . '</span>';
  660. }
  661. $html .= '<span class="timeslot-range"><i class="booked-icon booked-icon-clock"></i>&nbsp;&nbsp;' . $timeslotText . '</span>';
  662. if (!$hide_available_count):
  663. $html .= '<span class="spots-available'.($spots_available == 0 ? ' empty' : '').'">';
  664. $html .= sprintf( _n( '%d space available', '%d spaces available', $spots_available, 'booked' ), $spots_available );
  665. $html .= '</span>';
  666. endif;
  667. if ($public_appointments && !empty($appts_in_this_timeslot)):
  668. $html .= '<span class="booked-public-appointment-title">'._n('Appointments in this time slot:','Appointments in this time slot:',count($appts_in_this_timeslot),'booked').'</span>';
  669. $html .= '<ul class="booked-public-appointment-list">';
  670. foreach($appts_in_this_timeslot as $appt_id):
  671. $user_id = get_post_meta($appt_id, '_appointment_user',true);
  672. $guest_name = get_post_meta($appt_id, '_appointment_guest_name',true);
  673. $guest_surname = get_post_meta($appt_id, '_appointment_guest_surname',true);
  674. $guest_email = get_post_meta($appt_id, '_appointment_guest_email',true);
  675. $post_status = get_post_status($appt_id);
  676. $post_status = ( $post_status == 'future' ? $post_status = 'publish' : $post_status = $post_status );
  677. if ($user_id):
  678. $html .= '<li>'.booked_get_name($user_id).($post_status != 'publish' ? ' <span class="booked-public-pending">(pending)</span>' : '').'</li>';
  679. elseif($guest_name):
  680. $html .= '<li>'.$guest_name.' '.$guest_surname.($post_status != 'publish' ? ' <span class="booked-public-pending">(pending)</span>' : '').'</li>';
  681. endif;
  682. endforeach;
  683. $html .= '</ul>';
  684. endif;
  685. $html .= apply_filters('booked_fe_calendar_timeslot_after','',$this_timeslot_timestamp,$timeslot,$calendar_id);
  686. $html .= '</span>';
  687. $html .= '<span class="timeslot-people"><button data-calendar-id="'.$calendar_id.'" data-title="'.esc_attr($title).'" data-timeslot="'.$timeslot.'" data-date="'.$date.'" class="new-appt button"'.(!$spots_available || !$available ? ' disabled' : '').'>'.( $title ? '<span class="timeslot-mobile-title">'.esc_html($title).'</span>' : '' ).'<span class="button-timeslot">'.apply_filters('booked_fe_mobile_timeslot_button',$timeslotText,$this_timeslot_timestamp,$timeslot,$calendar_id).'</span>'.apply_filters('booked_button_book_appointment', '<span class="button-text">' . $button_text . '</span>' . ( !$hide_available_count ? '<span class="spots-available' . ( $spots_available == 0 ? ' empty' : '' ) . '">' . sprintf( esc_html( _n( '%d space available', '%d spaces available', $spots_available, 'booked' ) ), $spots_available ) . '</span>' : '' ) ).'</button></span>';
  688. $html .= '</div>';
  689. endif;
  690. echo apply_filters('booked_fe_calendar_date_appointments',$html,$time_format,$timeslot_parts,$spots_available,$available,$timeslot,$date);
  691. endif;
  692. endforeach;
  693. if (!$temp_count):
  694. echo '<p>'.esc_html__('There are no appointment time slots available for this day.','booked').'</p>';
  695. endif;
  696. /*
  697. There are no default timeslots and no appointments booked for this particular day.
  698. */
  699. } else {
  700. echo '<p>'.esc_html__('There are no appointment time slots available for this day.','booked').'</p>';
  701. }
  702. $appt_list_html = ob_get_clean();
  703. echo '<h2><span>'.sprintf( _n( esc_html__( 'Available Appointment on %s', 'booked' ), esc_html__( 'Available Appointments on %s', 'booked' ), $total_available ), '</span><strong>'.$date_display.'</strong><span>') . '</span></h2>';
  704. echo $appt_list_html;
  705. echo '</div>';
  706. do_action('booked_fe_calendar_date_after');
  707. }
  708. function booked_fe_appointment_list_content($date,$calendar_id = false,$force_day = false){
  709. $local_time = current_time('timestamp');
  710. $current_day = date_i18n('Ymd',$local_time);
  711. $public_appointments = get_option('booked_public_appointments',false);
  712. $total_available = 0;
  713. $prevent_before = apply_filters('booked_prevent_appointments_before',get_option('booked_prevent_appointments_before',false));
  714. $prevent_after = apply_filters('booked_prevent_appointments_after',get_option('booked_prevent_appointments_after',false));
  715. if ($prevent_before):
  716. $prevent_before = date_i18n('Ymd',strtotime($prevent_before));
  717. endif;
  718. if ($prevent_after):
  719. $prevent_after = date_i18n('Ymd',strtotime($prevent_after));
  720. endif;
  721. $year = date_i18n('Y',$local_time);
  722. $month = date_i18n('m',$local_time);
  723. $day = date_i18n('d',$local_time);
  724. $saved_date = $date;
  725. $counter = 0;
  726. do {
  727. $appointments_available = booked_appointments_available($year,$month,$day,$calendar_id);
  728. if (!$appointments_available):
  729. $new_date = strtotime($year.'-'.$month.'-'.$day.' +1 day');
  730. $year = date_i18n('Y',$new_date);
  731. $month = date_i18n('m',$new_date);
  732. $day = date_i18n('j',$new_date);
  733. else:
  734. break;
  735. endif;
  736. $counter++;
  737. } while (!$appointments_available && $counter <= 365);
  738. if ($counter >= 365): $day = date_i18n('d',strtotime($saved_date)); $month = date_i18n('m',strtotime($saved_date)); $year = date_i18n('Y',strtotime($saved_date)); endif;
  739. $earliest_date = $year.'-'.$month.'-'.$day;
  740. if (!$force_day):
  741. $date = date_i18n('Y-m-d',strtotime($year.'-'.$month.'-'.$day));
  742. $showing_earliest = true;
  743. else:
  744. $date = date_i18n('Y-m-d',strtotime($saved_date));
  745. $force_day_date = date_i18n('Ymd',strtotime($saved_date));
  746. if ($saved_date == $earliest_date): $showing_earliest = true; else: $showing_earliest = false; endif;
  747. endif;
  748. $prev_day = date_i18n('Ymd',strtotime($date.' -1 day'));
  749. $next_day = date_i18n('Ymd',strtotime($date.' +1 day'));
  750. $new_earliest_date = $earliest_date;
  751. if (isset($force_day_date) && $prev_day < $force_day_date):
  752. $new_earliest_date = date_i18n('Y-m-d',strtotime($force_day_date));
  753. $showing_earliest = true;
  754. endif;
  755. if ($prev_day >= $saved_date && $prev_day >= date_i18n('Ymd',strtotime($earliest_date))):
  756. $new_earliest_date = $earliest_date;
  757. $showing_earliest = false;
  758. endif;
  759. if ($prev_day >= date_i18n('Ymd',strtotime($earliest_date))):
  760. $new_earliest_date = $earliest_date;
  761. $showing_earliest = false;
  762. endif;
  763. $earliest_date = $new_earliest_date;
  764. do_action('booked_fe_calendar_date_before');
  765. echo '<div class="booked-appt-list" data-list-date="'.$date.'" data-min-date="'.($prevent_before ? date_i18n('Y-m-d',strtotime($prevent_before)) : $earliest_date).'" data-max-date="'.($prevent_after ? date_i18n('Y-m-d',strtotime($prevent_after)) : false).'">';
  766. /*
  767. Set some variables
  768. */
  769. $year = date_i18n('Y',strtotime($date));
  770. $month = date_i18n('m',strtotime($date));
  771. $day = date_i18n('d',strtotime($date));
  772. $start_timestamp = strtotime($year.'-'.$month.'-'.$day.' 00:00:00');
  773. $end_timestamp = strtotime($year.'-'.$month.'-'.$day.' 23:59:59');
  774. $date_format = get_option('date_format');
  775. $time_format = get_option('time_format');
  776. $date_display = date_i18n($date_format,strtotime($date));
  777. $day_name = date('D',strtotime($date));
  778. /*
  779. Grab all of the appointments for this day
  780. */
  781. $args = array(
  782. 'post_type' => 'booked_appointments',
  783. 'posts_per_page' => -1,
  784. 'post_status' => 'any',
  785. 'meta_query' => array(
  786. array(
  787. 'key' => '_appointment_timestamp',
  788. 'value' => array( $start_timestamp, $end_timestamp ),
  789. 'compare' => 'BETWEEN'
  790. )
  791. )
  792. );
  793. if ($calendar_id):
  794. $args['tax_query'] = array(
  795. array(
  796. 'taxonomy' => 'booked_custom_calendars',
  797. 'field' => 'term_id',
  798. 'terms' => $calendar_id,
  799. )
  800. );
  801. endif;
  802. $appointments_array = array();
  803. $bookedAppointments = new WP_Query( apply_filters('booked_fe_date_content_query',$args) );
  804. if($bookedAppointments->have_posts()):
  805. while ($bookedAppointments->have_posts()):
  806. $bookedAppointments->the_post();
  807. global $post;
  808. $timestamp = get_post_meta($post->ID, '_appointment_timestamp',true);
  809. $timeslot = get_post_meta($post->ID, '_appointment_timeslot',true);
  810. $user_id = get_post_meta($post->ID, '_appointment_user',true);
  811. $day = date_i18n('d',$timestamp);
  812. $appointments_array[$post->ID]['post_id'] = $post->ID;
  813. $appointments_array[$post->ID]['timestamp'] = $timestamp;
  814. $appointments_array[$post->ID]['timeslot'] = $timeslot;
  815. $appointments_array[$post->ID]['status'] = $post->post_status;
  816. $appointments_array[$post->ID]['user'] = $user_id;
  817. endwhile;
  818. endif;
  819. $appointments_array = apply_filters('booked_appointments_array', $appointments_array);
  820. /*
  821. Start the list
  822. */
  823. $this_date = date_i18n('Ymd',strtotime($date));
  824. if ($prevent_before && $this_date > $prevent_before || isset($current_day) && $prev_day >= $current_day && !$showing_earliest): $showing_prev = true; else: $showing_prev = false; endif;
  825. if ($prevent_after && $this_date >= $prevent_after): $showing_next = false; else: $showing_next = true; endif;
  826. ob_start();
  827. echo '<div class="booked-list-view-nav" data-calendar-id="'.$calendar_id.'">';
  828. if ($showing_prev):
  829. echo '<button data-date="'.date_i18n('Y-m-d',strtotime($prev_day)).'" class="booked-list-view-date-prev bb-small"><i class="booked-icon booked-icon-arrow-left"></i>&nbsp;&nbsp;'.esc_html__('Previous','booked').'</button>';
  830. endif;
  831. if ($showing_next):
  832. echo '<button data-date="'.date_i18n('Y-m-d',strtotime($next_day)).'" class="booked-list-view-date-next bb-small">'.esc_html__('Next','booked').'&nbsp;&nbsp;<i class="booked-icon booked-icon-arrow-right"></i></button>';
  833. endif;
  834. echo '<span class="booked-datepicker-wrap"><input data-min-date="'.$earliest_date.'" class="booked_list_date_picker" value="'.date_i18n('Y-m-d',strtotime($date)).'" type="hidden"><a href="#" class="booked_list_date_picker_trigger"><i class="booked-icon booked-icon-calendar"></i></a></span>';
  835. echo '</div>';
  836. /*
  837. Get today's default timeslots
  838. */
  839. if ($calendar_id):
  840. $booked_defaults = get_option('booked_defaults_'.$calendar_id);
  841. if (!$booked_defaults):
  842. $booked_defaults = get_option('booked_defaults');
  843. endif;
  844. else :
  845. $booked_defaults = get_option('booked_defaults');
  846. endif;
  847. $formatted_date = date_i18n('Ymd',strtotime($date));
  848. $disabled_formatted_date = date('Y-m-d',strtotime($date));
  849. $booked_defaults = booked_apply_custom_timeslots_details_filter($booked_defaults,$calendar_id);
  850. if (isset($booked_defaults[$formatted_date]) && !empty($booked_defaults[$formatted_date])):
  851. $todays_defaults = (is_array($booked_defaults[$formatted_date]) ? $booked_defaults[$formatted_date] : json_decode($booked_defaults[$formatted_date],true));
  852. $todays_defaults_details = (is_array($booked_defaults[$formatted_date.'-details']) ? $booked_defaults[$formatted_date.'-details'] : json_decode($booked_defaults[$formatted_date.'-details'],true));
  853. elseif (isset($booked_defaults[$formatted_date]) && empty($booked_defaults[$formatted_date])):
  854. $todays_defaults = false;
  855. $todays_defaults_details = false;
  856. elseif (isset($booked_defaults[$day_name]) && !empty($booked_defaults[$day_name])):
  857. $todays_defaults = $booked_defaults[$day_name];
  858. $todays_defaults_details = isset( $booked_defaults[$day_name.'-details'] ) ? $booked_defaults[$day_name.'-details'] : false;
  859. else :
  860. $todays_defaults = false;
  861. $todays_defaults_details = false;
  862. endif;
  863. /*
  864. There are timeslots available, let's loop through them
  865. */
  866. if ($todays_defaults){
  867. ksort($todays_defaults);
  868. $temp_count = 0;
  869. foreach($todays_defaults as $timeslot => $count):
  870. $appts_in_this_timeslot = array();
  871. /*
  872. Are there any appointments in this particular timeslot?
  873. If so, let's create an array of them.
  874. */
  875. foreach($appointments_array as $post_id => $appointment):
  876. if ($appointment['timeslot'] == $timeslot):
  877. $appts_in_this_timeslot[] = $post_id;
  878. endif;
  879. endforeach;
  880. /*
  881. Calculate the number of spots available based on total minus the appointments booked
  882. */
  883. $spots_available = $count - count($appts_in_this_timeslot);
  884. $spots_available = ($spots_available < 0 ? 0 : $spots_available);
  885. /*
  886. Display the timeslot
  887. */
  888. $disabled_timeslots = get_option( 'booked_disabled_timeslots', array() );
  889. $timeslot_parts = explode('-',$timeslot);
  890. $buffer = get_option('booked_appointment_buffer',0);
  891. $buffer_string = apply_filters('booked_appointment_buffer_string','+'.$buffer.' hours');
  892. if ($buffer):
  893. $current_timestamp = $local_time;
  894. $buffered_timestamp = strtotime($buffer_string,$current_timestamp);
  895. $current_timestamp = $buffered_timestamp;
  896. else:
  897. $current_timestamp = $local_time;
  898. endif;
  899. $this_timeslot_timestamp = strtotime($year.'-'.$month.'-'.$day.' '.$timeslot_parts[0]);
  900. $spots_available = apply_filters('booked_spots_available', $spots_available, $this_timeslot_timestamp);
  901. if ($current_timestamp < $this_timeslot_timestamp){
  902. $available = true;
  903. } else {
  904. $available = false;
  905. }
  906. if ( $calendar_id && isset($disabled_timeslots[$calendar_id][$disabled_formatted_date][$timeslot]) || !$calendar_id && isset($disabled_timeslots[0][$disabled_formatted_date][$timeslot]) ):
  907. continue;
  908. endif;
  909. $hide_unavailable_timeslots = get_option('booked_hide_unavailable_timeslots',false);
  910. $hide_available_count = get_option('booked_hide_available_timeslots',false);
  911. if ($spots_available && $available || !$hide_unavailable_timeslots):
  912. $total_available = $total_available + $spots_available;
  913. $temp_count++;
  914. if ($timeslot_parts[0] == '0000' && $timeslot_parts[1] == '2400'):
  915. $timeslotText = esc_html__('All day','booked');
  916. else :
  917. $timeslotText = date_i18n($time_format,strtotime($timeslot_parts[0])) . (!get_option('booked_hide_end_times') ? ' &ndash; '.date_i18n($time_format,strtotime($timeslot_parts[1])) : '');
  918. endif;
  919. $title = '';
  920. if ( !empty( $todays_defaults_details[$timeslot] ) ) {
  921. $title = !empty($todays_defaults_details[$timeslot]['title']) ? $todays_defaults_details[$timeslot]['title'] : '';
  922. }
  923. $only_titles = get_option('booked_show_only_titles',false);
  924. if ($hide_unavailable_timeslots && !$available):
  925. $html = '';
  926. else:
  927. $button_text = (!$spots_available || !$available ? esc_html__('Unavailable','booked') : esc_html__('Book Appointment','booked'));
  928. $html = '<div class="timeslot bookedClearFix'.($title && $only_titles == true ? ' booked-hide-time' : '').($hide_available_count || !$available ? ' timeslot-count-hidden' : '').(!$available ? ' timeslot-unavailable' : '').($title ? ' has-title ' : '').'">';
  929. $html .= '<span class="timeslot-time'.($public_appointments ? ' booked-public-appointments' : '').'">';
  930. $html .= apply_filters('booked_fe_calendar_timeslot_before','',$this_timeslot_timestamp,$timeslot,$calendar_id);
  931. if ( $title ) {
  932. $html .= '<span class="timeslot-title">' . esc_html($title) . '</span>';
  933. }
  934. $html .= '<span class="timeslot-range"><i class="booked-icon booked-icon-clock"></i>&nbsp;&nbsp;' . $timeslotText . '</span>';
  935. if (!$hide_available_count): $html .= '<span class="spots-available'.($spots_available == 0 ? ' empty' : '').'">'.sprintf(_n('%d space available','%d spaces available',$spots_available,'booked'),$spots_available).'</span>'; endif;
  936. if ($public_appointments && !empty($appts_in_this_timeslot)):
  937. $html .= '<span class="booked-public-appointment-title">'._n('Appointments in this time slot:','Appointments in this time slot:',count($appts_in_this_timeslot),'booked').'</span>';
  938. $html .= '<ul class="booked-public-appointment-list">';
  939. foreach($appts_in_this_timeslot as $appt_id):
  940. $user_id = get_post_meta($appt_id, '_appointment_user',true);
  941. $html .= '<li>'.booked_get_name($user_id).'</li>';
  942. endforeach;
  943. $html .= '</ul>';
  944. endif;
  945. $html .= apply_filters('booked_fe_calendar_timeslot_after','',$this_timeslot_timestamp,$timeslot,$calendar_id);
  946. $html .= '</span>';
  947. $html .= '<span class="timeslot-people"><button data-calendar-id="'.$calendar_id.'" data-title="'.esc_attr($title).'" data-timeslot="'.$timeslot.'" data-date="'.$date.'" class="new-appt button"'.(!$spots_available || !$available ? ' disabled' : '').'>'.( $title ? '<span class="timeslot-mobile-title">'.esc_html($title).'</span>' : '' ).'<span class="button-timeslot">'.apply_filters('booked_fe_mobile_timeslot_button',$timeslotText,$this_timeslot_timestamp,$timeslot,$calendar_id).'</span>'.apply_filters('booked_button_book_appointment', '<span class="button-text">'.$button_text.'</span>').'</button></span>';
  948. $html .= '</div>';
  949. endif;
  950. echo apply_filters('booked_fe_calendar_date_appointments',$html,$time_format,$timeslot_parts,$spots_available,$available,$timeslot,$date);
  951. endif;
  952. endforeach;
  953. if (!$temp_count):
  954. echo '<p>'.esc_html__('There are no appointment time slots available for this day.','booked').'</p>';
  955. endif;
  956. /*
  957. There are no default timeslots and no appointments booked for this particular day.
  958. */
  959. } else {
  960. echo '<p>'.esc_html__('There are no appointment time slots available for this day.','booked').'</p>';
  961. }
  962. $appt_list_html = ob_get_clean();
  963. echo '<h2'.(!$showing_prev ? ' class="booked-no-prev"' : '').'><span>'.sprintf(_n('Available Appointments on %s','Available Appointments on %s',$total_available,'booked'),'</span><strong>'.$date_display.'</strong>').'</h2>';
  964. echo $appt_list_html;
  965. echo '</div>';
  966. do_action('booked_fe_calendar_date_after');
  967. }
  968. function booked_reset_password($user_login){
  969. global $wpdb, $wp_hasher;
  970. $user_login = sanitize_text_field( $user_login );
  971. if ( empty( $user_login) ) {
  972. return false;
  973. } else if ( is_email( $user_login ) ) {
  974. $user_data = get_user_by( 'email', trim( $user_login ) );
  975. if ( empty( $user_data ) ):
  976. return false;
  977. endif;
  978. } else {
  979. $login = trim($user_login);
  980. $user_data = get_user_by('login', $login);
  981. }
  982. do_action('lostpassword_post');
  983. if ( !$user_data ) return false;
  984. // redefining user_login ensures we return the right case in the email
  985. $user_login = $user_data->user_login;
  986. $user_email = $user_data->user_email;
  987. do_action( 'retrieve_password', $user_login );
  988. $allow = apply_filters( 'allow_password_reset', true, $user_data->ID );
  989. if ( ! $allow ):
  990. return false;
  991. elseif ( is_wp_error($allow) ):
  992. return false;
  993. endif;
  994. $key = wp_generate_password( 20, false );
  995. do_action( 'retrieve_password_key', $user_login, $key );
  996. if ( empty( $wp_hasher ) ) {
  997. require_once ABSPATH . 'wp-includes/class-phpass.php';
  998. $wp_hasher = new PasswordHash( 8, true );
  999. }
  1000. $hashed = $wp_hasher->HashPassword( $key );
  1001. $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user_login ) );
  1002. $message = esc_html__('Someone requested that the password be reset for the following account:','booked') . "\r\n\r\n";
  1003. $message .= network_home_url( '/' ) . "\r\n\r\n";
  1004. $message .= sprintf(esc_html__('Username: %s','booked'), $user_login) . "\r\n\r\n";
  1005. $message .= esc_html__('If this was a mistake, just ignore this email and nothing will happen.','booked') . "\r\n\r\n";
  1006. $message .= esc_html__('To reset your password, visit the following address:','booked') . "\r\n\r\n";
  1007. $message .= '<' . network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . ">\r\n";
  1008. if ( is_multisite() ):
  1009. $blogname = $GLOBALS['current_site']->site_name;
  1010. else:
  1011. $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
  1012. endif;
  1013. $title = sprintf( esc_html__('[%s] Password Reset','booked'), $blogname );
  1014. $title = apply_filters('retrieve_password_title', $title);
  1015. $message = apply_filters('retrieve_password_message', $message, $key);
  1016. if ( $message && !wp_mail($user_email, $title, $message) ):
  1017. return false;
  1018. endif;
  1019. return true;
  1020. }
  1021. function booked_appt_is_available($date,$timeslot,$calendar_id = false){
  1022. $year = date_i18n('Y',strtotime($date));
  1023. $month = date_i18n('m',strtotime($date));
  1024. $day = date_i18n('d',strtotime($date));
  1025. $start_timestamp = strtotime($year.'-'.$month.'-'.$day.' 00:00:00');
  1026. $end_timestamp = strtotime($year.'-'.$month.'-'.$day.' 23:59:59');
  1027. $date_format = get_option('date_format');
  1028. $time_format = get_option('time_format');
  1029. $date_display = date_i18n($date_format,strtotime($date));
  1030. $day_name = date('D',strtotime($date));
  1031. $args = array(
  1032. 'post_type' => 'booked_appointments',
  1033. 'posts_per_page' => -1,
  1034. 'post_status' => 'any',
  1035. 'meta_query' => array(
  1036. array(
  1037. 'key' => '_appointment_timestamp',
  1038. 'value' => array( $start_timestamp, $end_timestamp ),
  1039. 'compare' => 'BETWEEN'
  1040. )
  1041. )
  1042. );
  1043. if ($calendar_id):
  1044. $args['tax_query'] = array(
  1045. array(
  1046. 'taxonomy' => 'booked_custom_calendars',
  1047. 'field' => 'term_id',
  1048. 'terms' => $calendar_id,
  1049. )
  1050. );
  1051. endif;
  1052. $appointments_array = array();
  1053. $bookedAppointments = new WP_Query( apply_filters('booked_fe_date_content_query',$args) );
  1054. if($bookedAppointments->have_posts()):
  1055. while ($bookedAppointments->have_posts()):
  1056. $bookedAppointments->the_post();
  1057. global $post;
  1058. $appt_timestamp = get_post_meta($post->ID, '_appointment_timestamp',true);
  1059. $appt_timeslot = get_post_meta($post->ID, '_appointment_timeslot',true);
  1060. $appt_user_id = get_post_meta($post->ID, '_appointment_user',true);
  1061. $appt_day = date_i18n('d',$appt_timestamp);
  1062. $appointments_array[$post->ID]['post_id'] = $post->ID;
  1063. $appointments_array[$post->ID]['timestamp'] = $appt_timestamp;
  1064. $appointments_array[$post->ID]['timeslot'] = $appt_timeslot;
  1065. $appointments_array[$post->ID]['status'] = $post->post_status;
  1066. $appointments_array[$post->ID]['user'] = $appt_user_id;
  1067. endwhile;
  1068. endif;
  1069. $appointments_array = apply_filters('booked_appointments_array', $appointments_array);
  1070. if ($calendar_id):
  1071. $booked_defaults = get_option('booked_defaults_'.$calendar_id);
  1072. if (!$booked_defaults):
  1073. $booked_defaults = get_option('booked_defaults');
  1074. endif;
  1075. else :
  1076. $booked_defaults = get_option('booked_defaults');
  1077. endif;
  1078. $formatted_date = date_i18n('Ymd',strtotime($date));
  1079. $booked_defaults = booked_apply_custom_timeslots_filter($booked_defaults,$calendar_id);
  1080. if (isset($booked_defaults[$formatted_date]) && !empty($booked_defaults[$formatted_date])):
  1081. $todays_defaults = (is_array($booked_defaults[$formatted_date]) ? $booked_defaults[$formatted_date] : json_decode($booked_defaults[$formatted_date],true));
  1082. elseif (isset($booked_defaults[$formatted_date]) && empty($booked_defaults[$formatted_date])):
  1083. $todays_defaults = false;
  1084. elseif (isset($booked_defaults[$day_name]) && !empty($booked_defaults[$day_name])):
  1085. $todays_defaults = $booked_defaults[$day_name];
  1086. else :
  1087. $todays_defaults = false;
  1088. endif;
  1089. $total_available = isset($todays_defaults[$timeslot]) ? $todays_defaults[$timeslot] : 0;
  1090. foreach($appointments_array as $appt):
  1091. if ($timeslot == $appt['timeslot'] && isset($todays_defaults[$appt['timeslot']])):
  1092. $total_available--;
  1093. endif;
  1094. endforeach;
  1095. if ($total_available < 0): $total_available = 0; endif;
  1096. return $total_available;
  1097. }
  1098. function booked_custom_fields($calendar_id = false){
  1099. if ($calendar_id):
  1100. $custom_fields = json_decode(stripslashes(get_option('booked_custom_fields_'.$calendar_id)),true);
  1101. if (empty($custom_fields)): $custom_fields = json_decode(stripslashes(get_option('booked_custom_fields')),true); endif;
  1102. else:
  1103. $custom_fields = json_decode(stripslashes(get_option('booked_custom_fields')),true);
  1104. endif;
  1105. if (!empty($custom_fields)):
  1106. echo '<div class="cf-block">';
  1107. $look_for_subs = false;
  1108. $temp_count = 0;
  1109. $data_attributes = ' data-calendar-id="' . intval($calendar_id) . '" ';
  1110. foreach($custom_fields as $field):
  1111. $temp_count++;
  1112. $field_parts = explode('---',$field['name']);
  1113. $field_type = $field_parts[0];
  1114. $end_of_string = explode('___',$field_parts[1]);
  1115. $numbers_only = $end_of_string[0];
  1116. $is_required = (isset($end_of_string[1]) ? true : false);
  1117. if ($look_for_subs):
  1118. if ($field_type == 'single-checkbox'):
  1119. ?><span class="checkbox-radio-block"><input <?php echo $data_attributes ?> type="checkbox" name="<?php echo $field['name']; ?>[]" id="booked-checkbox-<?php echo $field['name'].'-'.$temp_count; ?>" value="<?php echo htmlentities($field['value'], ENT_QUOTES | ENT_IGNORE, "UTF-8"); ?>"> <label for="booked-checkbox-<?php echo $field['name'].'-'.$temp_count; ?>"><?php echo $field['value']; ?></label></span><?php
  1120. elseif ($field_type == 'single-radio-button'):
  1121. ?><span class="checkbox-radio-block"><input <?php echo $data_attributes ?> type="radio" name="<?php echo $field['name']; ?>[]" id="booked-radio-<?php echo $field['name'].'-'.$temp_count; ?>" value="<?php echo htmlentities($field['value'], ENT_QUOTES | ENT_IGNORE, "UTF-8"); ?>"> <label for="booked-radio-<?php echo $field['name'].'-'.$temp_count; ?>"><?php echo $field['value']; ?></label></span><?php
  1122. elseif ($field_type == 'single-drop-down'):
  1123. ?><option value="<?php echo htmlentities($field['value'], ENT_QUOTES | ENT_IGNORE, "UTF-8"); ?>"><?php echo htmlentities($field['value'], ENT_QUOTES | ENT_IGNORE, "UTF-8"); ?></option><?php
  1124. else :
  1125. if ($look_for_subs == 'checkboxes'):
  1126. ?></div><?php
  1127. elseif ($look_for_subs == 'radio-buttons'):
  1128. ?></div><?php
  1129. elseif ($look_for_subs == 'dropdowns'):
  1130. ?></select></div><?php
  1131. endif;
  1132. $reset_subs = apply_filters(
  1133. 'booked_custom_fields_add_template_subs',
  1134. $field_type,
  1135. $field['name'],
  1136. $field['value'],
  1137. $is_required,
  1138. $look_for_subs,
  1139. $numbers_only,
  1140. $data_attributes
  1141. );
  1142. if ( $reset_subs ) {
  1143. $look_for_subs = false;
  1144. }
  1145. endif;
  1146. endif;
  1147. switch($field_type):
  1148. case 'single-line-text-label' :
  1149. ?><div class="field">
  1150. <label class="field-label"><?php echo $field['value']; ?><?php if ($is_required): ?><i class="required-asterisk booked-icon booked-icon-required"></i><?php endif; ?></label>
  1151. <input id="booked-textfield-<?php echo esc_attr($field['name']); ?>" <?php echo $data_attributes ?> <?php if ($is_required): echo ' required="required"'; endif; ?> type="text" name="<?php echo esc_attr($field['name']); ?>" value="" class="large textfield" />
  1152. </div><?php
  1153. break;
  1154. case 'paragraph-text-label' :
  1155. ?><div class="field">
  1156. <label class="field-label"><?php echo $field['value']; ?><?php if ($is_required): ?><i class="required-asterisk booked-icon booked-icon-required"></i><?php endif; ?></label>
  1157. <textarea id="booked-textarea-<?php echo esc_attr($field['name']); ?>" <?php echo $data_attributes ?> <?php if ($is_required): echo ' required="required"'; endif; ?> name="<?php echo esc_attr($field['name']); ?>"></textarea>
  1158. </div><?php
  1159. break;
  1160. case 'checkboxes-label' :
  1161. ?><div class="field">
  1162. <label class="field-label"><?php echo $field['value']; ?><?php if ($is_required): ?><i class="required-asterisk booked-icon booked-icon-required"></i><?php endif; ?></label>
  1163. <input id="booked-checkbox-label-<?php echo esc_attr($field['name']); ?>" <?php echo $data_attributes ?> <?php if ($is_required): echo ' required="required"'; endif; ?> type="hidden" name="<?php echo esc_attr($field['name']); ?>" /><?php
  1164. $look_for_subs = 'checkboxes';
  1165. break;
  1166. case 'radio-buttons-label' :
  1167. ?><div class="field">
  1168. <label class="field-label"><?php echo $field['value']; ?><?php if ($is_required): ?><i class="required-asterisk booked-icon booked-icon-required"></i><?php endif; ?></label>
  1169. <input id="booked-radio-label-<?php echo esc_attr($field['name']); ?>" <?php echo $data_attributes ?> <?php if ($is_required): echo ' required="required"'; endif; ?> type="hidden" name="<?php echo esc_attr($field['name']); ?>" /><?php
  1170. $look_for_subs = 'radio-buttons';
  1171. break;
  1172. case 'drop-down-label' :
  1173. ?><div class="field">
  1174. <label class="field-label"><?php echo $field['value']; ?><?php if ($is_required): ?><i class="required-asterisk booked-icon booked-icon-required"></i><?php endif; ?></label>
  1175. <input id="booked-select-label-<?php echo esc_attr($field['name']); ?>" type="hidden" name="<?php echo esc_attr($field['name']); ?>" />
  1176. <select id="booked-select-<?php echo esc_attr($field['name']); ?>" <?php echo $data_attributes ?> <?php if ($is_required): echo ' required="required"'; endif; ?> name="<?php echo esc_attr($field['name']); ?>"><option value=""><?php esc_html_e('Choose...','booked'); ?></option><?php
  1177. $look_for_subs = 'dropdowns';
  1178. break;
  1179. case 'plain-text-content' :
  1180. ?><div id="booked-text-<?php echo $field['name']; ?>" class="field booked-text-content">
  1181. <?php echo wpautop($field['value']); ?>
  1182. </div><?php
  1183. break;
  1184. default:
  1185. $look_for_subs_action = apply_filters(
  1186. 'booked_custom_fields_add_template_main',
  1187. false, // default value to return when there is no addon plugin to hook on it
  1188. $field_type,
  1189. $field['name'],
  1190. $field['value'],
  1191. $is_required,
  1192. $look_for_subs,
  1193. $numbers_only,
  1194. $data_attributes
  1195. );
  1196. $look_for_subs = $look_for_subs_action ? $look_for_subs_action : $look_for_subs;
  1197. break;
  1198. endswitch;
  1199. endforeach;
  1200. if ($look_for_subs):
  1201. do_action('booked_custom_fields_add_template_subs_end', $field_type, $look_for_subs);
  1202. if ($look_for_subs == 'checkboxes'):
  1203. ?></div><?php
  1204. elseif ($look_for_subs == 'radio-buttons'):
  1205. ?></div><?php
  1206. elseif ($look_for_subs == 'dropdowns'):
  1207. ?></select></div><?php
  1208. endif;
  1209. endif;
  1210. echo '</div>';
  1211. endif;
  1212. }
  1213. add_action( 'wp_login_failed', 'booked_fe_login_fail' ); // hook failed login
  1214. function booked_fe_login_fail( $username ) {
  1215. if (isset($_SERVER['HTTP_REFERER'])):
  1216. $referrer = $_SERVER['HTTP_REFERER'];
  1217. $referrer = explode('?',$referrer);
  1218. $referrer = $referrer[0];
  1219. if ( !isset($_REQUEST['woocommerce-login-nonce']) && !empty($referrer) && !strstr($referrer,'wp-login') && !strstr($referrer,'wp-admin') ) {
  1220. wp_redirect( $referrer . '?loginfailed' );
  1221. exit;
  1222. }
  1223. endif;
  1224. }
  1225. function booked_send_user_approved_email($appt_id){
  1226. $email_content = get_option('booked_approval_email_content');
  1227. $email_subject = get_option('booked_approval_email_subject');
  1228. if ($email_content && $email_subject):
  1229. $token_replacements = booked_get_appointment_tokens( $appt_id );
  1230. $email_content = booked_token_replacement( $email_content,$token_replacements );
  1231. $email_subject = booked_token_replacement( $email_subject,$token_replacements );
  1232. do_action( 'booked_approved_email', $token_replacements['email'], $email_subject, $email_content );
  1233. endif;
  1234. }
  1235. function booked_user_appointments($user_id,$only_count = false,$time_format = false,$date_format = false,$historic = false){
  1236. if (!$date_format || !$time_format){
  1237. $time_format = get_option('time_format');
  1238. $date_format = get_option('date_format');
  1239. }
  1240. $order = $historic ? 'DESC' : 'ASC';
  1241. $count = $historic ? 50 : -1;
  1242. $args = array(
  1243. 'post_type' => 'booked_appointments',
  1244. 'posts_per_page' => $count,
  1245. 'post_status' => 'any',
  1246. 'author' => $user_id,
  1247. 'meta_key' => '_appointment_timestamp',
  1248. 'orderby' => 'meta_value_num',
  1249. 'order' => $order
  1250. );
  1251. $appointments_array = array();
  1252. $bookedAppointments = new WP_Query($args);
  1253. if($bookedAppointments->have_posts()):
  1254. while ($bookedAppointments->have_posts()):
  1255. $bookedAppointments->the_post();
  1256. global $post;
  1257. $appt_date_value = date_i18n('Y-m-d',get_post_meta($post->ID, '_appointment_timestamp',true));
  1258. $appt_timeslot = get_post_meta($post->ID, '_appointment_timeslot',true);
  1259. $appt_timeslots = explode('-',$appt_timeslot);
  1260. $appt_time_start = date_i18n('H:i:s',strtotime($appt_timeslots[0]));
  1261. $appt_timestamp = strtotime($appt_date_value.' '.$appt_time_start);
  1262. $current_timestamp = current_time('timestamp');
  1263. $day = date_i18n('d',$appt_timestamp);
  1264. $calendar_id = wp_get_post_terms( $post->ID, 'booked_custom_calendars' );
  1265. if (!$historic && $appt_timestamp >= $current_timestamp || $historic && $appt_timestamp < $current_timestamp){
  1266. $appointments_array[$post->ID]['post_id'] = $post->ID;
  1267. $appointments_array[$post->ID]['timestamp'] = $appt_timestamp;
  1268. $appointments_array[$post->ID]['timeslot'] = $appt_timeslot;
  1269. $appointments_array[$post->ID]['calendar_id'] = $calendar_id;
  1270. $appointments_array[$post->ID]['status'] = $post->post_status;
  1271. }
  1272. endwhile;
  1273. endif;
  1274. $appointments_array = apply_filters('booked_appointments_array', $appointments_array);
  1275. wp_reset_postdata();
  1276. if ($only_count):
  1277. return count($appointments_array);
  1278. else :
  1279. return $appointments_array;
  1280. endif;
  1281. }
  1282. function booked_profile_update_submit(){
  1283. if (is_user_logged_in()):
  1284. global $error,$post;
  1285. $booked_current_user = wp_get_current_user();
  1286. $error = array();
  1287. if ( 'POST' == $_SERVER['REQUEST_METHOD'] && !empty( $_POST['action'] ) && $_POST['action'] == 'update-user' ) {
  1288. /* Update user password. */
  1289. if (isset($_POST['pass1']) && isset($_POST['pass2']) && $_POST['pass1'] && $_POST['pass2'] ) {
  1290. if ( $_POST['pass1'] == $_POST['pass2'] )
  1291. wp_update_user( array( 'ID' => $booked_current_user->ID, 'user_pass' => esc_attr( $_POST['pass1'] ) ) );
  1292. else
  1293. $error[] = esc_html__('The passwords you entered do not match. Your password was not updated.', 'profile');
  1294. }
  1295. /* Update user information. */
  1296. if ( isset( $_POST['url'] ) )
  1297. wp_update_user( array( 'ID' => $booked_current_user->ID, 'user_url' => esc_url( $_POST['url'] ) ) );
  1298. if ( isset( $_POST['email'] ) ){
  1299. $email_exists = email_exists(esc_attr( $_POST['email'] ));
  1300. if (!is_email(esc_attr( $_POST['email'] )))
  1301. $error[] = esc_html__('The Email you entered is not valid. please try again.', 'profile');
  1302. elseif( $email_exists && $email_exists != $booked_current_user->ID )
  1303. $error[] = esc_html__('This email is already used by another user. try a different one.', 'profile');
  1304. else{
  1305. wp_update_user( array ('ID' => $booked_current_user->ID, 'user_email' => esc_attr( $_POST['email'] )));
  1306. }
  1307. }
  1308. if ( isset( $_POST['nickname'] ) ):
  1309. update_user_meta( $booked_current_user->ID, 'nickname', esc_attr( $_POST['nickname'] ) );
  1310. wp_update_user( array ('ID' => $booked_current_user->ID, 'display_name' => esc_attr( $_POST['nickname'] )));
  1311. endif;
  1312. // Avatar Upload
  1313. if (isset($_FILES['avatar']) && $_FILES['avatar']['error'] == 0):
  1314. $avatar = isset($_FILES['avatar']) && $_FILES['avatar'] ? $_FILES['avatar'] : false;
  1315. if (isset($avatar,$_POST['avatar_nonce']) && $avatar && wp_verify_nonce( $_POST['avatar_nonce'], 'avatar_upload' )) {
  1316. require_once( ABSPATH . 'wp-admin/includes/image.php' );
  1317. require_once( ABSPATH . 'wp-admin/includes/file.php' );
  1318. require_once( ABSPATH . 'wp-admin/includes/media.php' );
  1319. $attachment_id = media_handle_upload( 'avatar', 0 );
  1320. if ( is_wp_error( $attachment_id ) ) {
  1321. $error[] = esc_html__('Error uploading avatar.','booked');
  1322. } else {
  1323. update_user_meta( $booked_current_user->ID, 'avatar', $attachment_id );
  1324. }
  1325. } else {
  1326. $error[] = esc_html__('Avatar uploader security check failed.','booked');
  1327. }
  1328. endif;
  1329. // END AVATAR
  1330. /* Redirect so the page will show updated info.*/
  1331. if ( count($error) == 0 ) {
  1332. //action hook for plugins and extra fields saving
  1333. do_action('edit_user_profile_update', $booked_current_user->ID);
  1334. wp_redirect( get_permalink($post->ID) );
  1335. exit;
  1336. }
  1337. }
  1338. endif;
  1339. }
  1340. add_action('template_redirect','booked_profile_update_submit');
  1341. function booked_wpml_ajax(){
  1342. if ( isset( $_GET['wpml_lang'] ) && $_GET['wpml_lang'] ):
  1343. do_action( 'wpml_switch_language', esc_html( $_GET['wpml_lang'] ) );
  1344. endif;
  1345. }
  1346. function booked_profile_content_appointments(){
  1347. $home_url = booked_home_url();
  1348. ?>
  1349. <div id="data-ajax-url"><?php echo $home_url; ?>/</div>
  1350. <?php if (isset($_SESSION['appt_requested']) && isset($_SESSION['new_account'])){
  1351. $_SESSION['appt_requested'] = null;
  1352. $_SESSION['new_account'] = null;
  1353. echo '<p class="booked-form-notice">'.esc_html__('Your appointment has been requested! We have also set up an account for you. Your login information has been sent via email. When logged in, you can view your upcoming appointments below. Be sure to change your password to something more memorable by using the Edit Profile tab above.','booked').'</p>';
  1354. } else if (isset($_SESSION['appt_requested'])){
  1355. $_SESSION['appt_requested'] = null;
  1356. $appointment_default_status = get_option('booked_new_appointment_default','draft');
  1357. if ($appointment_default_status == 'draft'):
  1358. echo '<p class="booked-form-notice">'.esc_html__('Your appointment has been requested! It will be updated below if approved.','booked').'</p>';
  1359. else :
  1360. echo '<p class="booked-form-notice">'.esc_html__('Your appointment has been added to our calendar!','booked').'</p>';
  1361. endif;
  1362. }
  1363. ?>
  1364. <?php echo do_shortcode('[booked-appointments remove_wrapper=1]');
  1365. }
  1366. function booked_profile_content_history(){
  1367. echo do_shortcode('[booked-appointments remove_wrapper=1 historic=1]');
  1368. }
  1369. function booked_profile_content_edit(){
  1370. $booked_current_user = wp_get_current_user();
  1371. echo '<h4><i class="booked-icon booked-icon-edit" style="position:relative; top:-1px;"></i>&nbsp;&nbsp;'.esc_html__('Edit Profile','booked').'</h4>'; ?>
  1372. <form method="post" enctype="multipart/form-data" id="booked-page-form" action="<?php the_permalink(); ?>">
  1373. <div class="bookedClearFix">
  1374. <p class="form-avatar">
  1375. <label for="avatar"><?php esc_html_e('Update Avatar', 'booked'); ?><?php if (BOOKED_DEMO_MODE): ?> <span class="not-bold"><?php esc_html_e('(disabled in demo)', 'cooked'); ?></span><?php endif; ?></label><br>
  1376. <span class="booked-upload-wrap"><span><?php esc_html_e('Choose image ...','booked'); ?></span><input<?php if (BOOKED_DEMO_MODE): ?> disabled<?php endif; ?> class="field" name="avatar" type="file" id="avatar" value="" /></span>
  1377. <?php wp_nonce_field( 'avatar_upload', 'avatar_nonce' ); ?>
  1378. <span class="hint-p"><?php esc_html_e('Recommended size: 100px by 100px or larger', 'booked'); ?></span>
  1379. </p><!-- .form-nickname -->
  1380. </div>
  1381. <div class="bookedClearFix">
  1382. <p class="form-nickname">
  1383. <label for="nickname"><?php esc_html_e('Display Name', 'booked'); ?><?php if (BOOKED_DEMO_MODE): ?> <span class="not-bold"><?php esc_html_e('(disabled in demo)', 'cooked'); ?></span><?php endif; ?></label>
  1384. <input<?php if (BOOKED_DEMO_MODE): ?> disabled<?php endif; ?> class="text-input" name="nickname" type="text" id="nickname" value="<?php the_author_meta( 'nickname', $booked_current_user->ID ); ?>" />
  1385. </p><!-- .form-nickname -->
  1386. <p class="form-email">
  1387. <label for="email"><?php esc_html_e('E-mail *', 'booked'); ?><?php if (BOOKED_DEMO_MODE): ?> <span class="not-bold"><?php esc_html_e('(disabled in demo)', 'cooked'); ?></span><?php endif; ?></label>
  1388. <input<?php if (BOOKED_DEMO_MODE): ?> disabled<?php endif; ?> class="text-input" name="email" type="text" id="email" value="<?php the_author_meta( 'user_email', $booked_current_user->ID ); ?>" />
  1389. </p><!-- .form-email -->
  1390. </div>
  1391. <div class="bookedClearFix">
  1392. <p class="form-password">
  1393. <label for="pass1"><?php esc_html_e('Change Password', 'booked'); ?><?php if (BOOKED_DEMO_MODE): ?> <span class="not-bold"><?php esc_html_e('(disabled in demo)', 'cooked'); ?></span><?php endif; ?></label>
  1394. <input<?php if (BOOKED_DEMO_MODE): ?> disabled<?php endif; ?> class="text-input" name="pass1" type="password" id="pass1" />
  1395. </p><!-- .form-password -->
  1396. <p class="form-password last">
  1397. <label for="pass2"><?php esc_html_e('Repeat Password', 'booked'); ?><?php if (BOOKED_DEMO_MODE): ?> <span class="not-bold"><?php esc_html_e('(disabled in demo)', 'cooked'); ?></span><?php endif; ?></label>
  1398. <input<?php if (BOOKED_DEMO_MODE): ?> disabled<?php endif; ?> class="text-input" name="pass2" type="password" id="pass2" />
  1399. </p><!-- .form-password -->
  1400. </div>
  1401. <?php
  1402. //action hook for plugin and extra fields
  1403. do_action('edit_user_profile',$booked_current_user);
  1404. ?>
  1405. <p class="form-submit">
  1406. <input name="updateuser" type="submit" id="updateuser" class="submit button button-primary" value="<?php esc_html_e('Update', 'booked'); ?>" />
  1407. <?php wp_nonce_field( 'update-user' ) ?>
  1408. <input name="action" type="hidden" id="action" value="update-user" />
  1409. </p><!-- .form-submit -->
  1410. </form><!-- #adduser --><?php
  1411. }