* * @since 0.1.0 * @return void */ add_action('wp_ajax_wprsrv_flush_reservable_cache', function () { if (!isset($_POST) || !isset($_POST['post_id'])) { echo 1; exit; } $post = $_POST; $postId = $post['post_id']; if (!$postId) { echo 1; exit; } $reservable = new Reservable($postId); $reservable->flushCache(); echo 0; exit; }); /** * AJAX * Get a reservation calendar for a certain month and reservable. * * @since 0.4.0 * @return void */ add_action('wp_ajax_wprsrv_get_reservation_calendar_view', function () { if (!isset($_POST) || !isset($_POST['reservable_id'])) { echo 1; exit;
/** * Gather all reservations. * * @since 0.2.0 * @access protected * @return \Wprsrv\PostTypes\Objects\Reservation[] */ protected function getReservations() { $reservations = []; $rargs = ['post_type' => 'reservation', 'post_status' => ['reservation_pending', 'reservation_accepted', 'reservation_declined'], 'posts_per_page' => -1, 'nopaging' => 1, 'no_found_rows' => true, 'meta_key' => '_wprsrv_reservable_id']; if ($this->reservable) { $reservations = $this->reservable->getReservations(); } else { $reservationsQuery = new \WP_Query($rargs); foreach ($reservationsQuery->posts as $rpost) { $reservations[] = new Reservation($rpost); } } return $reservations; }
/** * Render the form. The included template has $this available. * * The rendered template file can be overridden by themes by making a theme * directory `wprsrv` and creating a file named `reservation-form.php` inside it. * * The template file can be filtered to pick any other file which is needed. * * @since 0.1.0 * @return void */ public function render() { if (!$this->reservable->isActive()) { $this->reservationDisabledNotice(); return; } if (!is_user_logged_in() && $this->reservable->isLoginRequired()) { $this->reservationRestrictedNotice(); return; } try { $this->formFieldMarkup = $this->generateFormFieldsMarkup(); } catch (\Exception $e) { \Wprsrv\wprsrv()->logger->critical('Cannot render reservation form: {msg}', ['msg' => $e->getMessage()]); return; } $themeTemplateFile = get_stylesheet_directory() . RDS . 'wprsrv' . 'reservation-form.php'; $pluginTemplateFile = \Wprsrv\wprsrv()->templateDirectory . RDS . 'frontend' . RDS . 'reservation-form.php'; // If a theme overrides the template file, load it. Otherwise use the plugin's own template. if (file_exists($themeTemplateFile)) { $templateFile = $themeTemplateFile; } else { $templateFile = $pluginTemplateFile; } /** * Filter the reservation form template file absolute path. * * @since 0.1.0 * * @param String $templateFile Absolute path to template file. */ $templateFile = apply_filters('wprsrv/reservation_form/template_file', $templateFile); include $templateFile; }
/** * Generate a table cell for a single day. * * @todo Validate reservations are shown correctly for overlapping * reservation dates. * * @since 0.1.0 * @access protected * * @param \DateTime $date Datetime for the day to generate. * * @return String */ protected function generateDayCell(\DateTime $date, $weekdayNum) { $day = $date->format('d'); $dayReserved = $this->reservable->isDayReserved($date, false); if (!$dayReserved) { return '<td class="single-day"><span class="day-num">' . $day . '</span></td>'; } $reservations = $this->reservable->getReservationsForDate($date); $reservationLabel = $this->generateDayCellReservationsData($reservations, $date, $weekdayNum); $dayNum = sprintf('<span class="day-num">%s</span>', $day); $tdClasses[] = 'single-day'; return sprintf('<td class="%s">%s %s</td>', implode(' ', $tdClasses), $dayNum, $reservationLabel); }
/** * Validate given metadata for a new reservation. * * @static * @since 0.1.0 * @todo Make this more usable for other parts of the plugin maybe? * * @param mixed[] $meta Metadata to validate. * * @return mixed[] */ protected static function validateMeta($meta) { $required = ['reserver_email' => ['email', _x('email address', 'validation error label', 'wprsrv')], 'start_date' => ['date', _x('starting date or time', 'validation error label', 'wprsrv')], 'end_date' => ['date', _x('ending date or time', 'validation error label', 'wprsrv')]]; $errors = []; foreach ($required as $key => $type) { if (!array_key_exists($key, $meta)) { $errors[] = sprintf(_x('Missing field: %s', 'validation error', 'wprsrv'), $type[1]); } $value = $meta[$key]; switch ($type) { case 'integer': if (!preg_match('%^[0-9]+$%', $value)) { $errors[] = sprintf(_x('Invalid number value for %s', 'validation error', 'wprsrv'), $type[1]); } break; case 'date': if (!is_numeric(strtotime($value)) || strtotime($value) < 1000) { $errors[] = sprintf(_x('Invalid date or time value for %s', 'validation error', 'wprsrv'), $type[1]); } break; case 'email': if (!is_email($value)) { $errors[] = sprintf(_x('Invalid email value for %s', 'validation error', 'wprsrv'), $type[1]); } break; } } $reservable = new Reservable($meta['reservable_id']); $dayOverlapErrorMessage = _x('Given reservation date range contains a date that has already been reserved', 'validation error', 'wprsrv'); if (!$reservable->allowsOverlappingReservations()) { if ($reservable->hasReservationInDateRange($meta['start_date'], $meta['end_date'])) { $errors[] = $dayOverlapErrorMessage; } } else { if (!$reservable->canReserveOverlapping($meta['start_date'], $meta['end_date'])) { $errors[] = $dayOverlapErrorMessage; } } return $errors; }
/** * Fired on WP plugin deactivation hook. No output allowed. * * @todo Refactor plugin cache flushing to a separate method, or maybe even a * class. * @static * @since 0.1.0 * @return void */ public static function deactivate() { // Begin output buffering. ob_start(); $self = new self(false); $self->logger->notice('Deactivating wprsrv plugin...'); $reservables = new \WP_Query(['post_type' => 'reservable', 'post_status' => 'all', 'posts_per_page' => -1, 'no_found_rows' => 1, 'nopaging' => 1, 'fields' => 'ids']); if ($reservables->have_posts()) { foreach ($reservables->posts as $post_id) { $reservable = new Reservable($post_id); $reservable->flushCache(); } } // Flush rewrite rules. flush_rewrite_rules(); // Get rid of buffer. ob_end_clean(); }
<?php namespace Wprsrv; use Wprsrv\PostTypes\Objects\Reservable; if (!$reservable && !empty($post)) { $reservable = $post; } if (!$reservable instanceof Reservable) { $reservable = new Reservable($reservable); } if ($reservable->hasReservations()) { $calDate = new \DateTime('now'); $cal = new \Wprsrv\Admin\ReservableCalendar($reservable, $calDate); //FIXME $flushed = $reservable->calendarCacheFlushed(); $cal->render(true); if (!!$flushed) { $reservable->clearCalendarFlush(); } } else { printf('<p class="empty-notice">%s</p>', __('This reservable has no reservations.', 'wprsrv')); }
<?php namespace Wprsrv; use Wprsrv\PostTypes\Objects\Reservable; if (!$reservable && !empty($post)) { $reservable = $post; } if (!$reservable instanceof Reservable) { $reservable = new Reservable($reservable); } $weekdays = ['monday' => __('Monday'), 'tuesday' => __('Tuesday'), 'wednesday' => __('Wednesday'), 'thursday' => __('Thursday'), 'friday' => __('Friday'), 'saturday' => __('Saturday'), 'sunday' => __('Sunday')]; ?> <table summary="Reservable settings"> <tbody> <tr> <th class="wprsrv-mainlabel" scope="row"> <label for=""><?php _ex('Reservable active', 'reservable metabox form', 'wprsrv'); ?> </label> <em><?php _e('If the reservable is not active, it will be visible in the frontend but no reservation form will be shown.', 'wprsrv'); ?> </em> </th> <td> <label for="wprsrv-reservable-active"> <input type="checkbox" name="wprsrv[reservable_active]" <?php
/** * Custom saving logic for reservables. * * @see self::addHooks() * @see:wphook save_post * @since 0.1.0 * @todo Make this method simpler and extract some parts elsewhere. * * @param Integer $post_id Post ID being saved. * @param \WP_Post $post Post being saved. * @param Boolean $update Is this an update? * * @return void */ public function saveReservable($post_id, $post, $update) { if (wp_is_post_revision($post_id)) { return; } if (get_post_type($post_id) !== 'reservable') { return; } $postData = $_POST; if (!isset($postData['wprsrv'])) { return; } $wprsrvData = $postData['wprsrv']; $reservable = new ReservableObj($post); $keysAvailable = ['reservable_active', 'reservable_singleday', 'reservable_disabled_days', 'reservable_disabled_weekdays', 'reservable_loggedin_only', 'reservable_overlapping_days']; // Set null values if not given on update. foreach ($keysAvailable as $key) { if (array_key_exists($key, $wprsrvData)) { continue; } switch ($key) { case 'reservable_active': $reservable->setActive(false); break; case 'reservable_singleday': $reservable->setSingleDay(false); break; case 'reservable_disabled_days': $reservable->setDisabledDaysAdminData(false); break; case 'reservable_disabled_weekdays': $reservable->setDisabledWeekdaysData(false); break; case 'reservable_loggedin_only': $reservable->setLoginRequired(false); break; case 'reservable_overlapping_days': $reservable->setAllowOverlappingReservations(false); break; } } // Update values with given POST. foreach ($wprsrvData as $key => $value) { switch ($key) { case 'reservable_active': $reservable->setActive($value === 'on' ? true : false); break; case 'reservable_singleday': $reservable->setSingleDay($value === 'on' ? true : false); break; case 'reservable_disabled_days': $disabled = []; for ($i = 0; $i < count($value['start']); $i++) { if (empty($value['start'][$i])) { continue; } $range = ['start' => $value['start'][$i], 'end' => $value['end'][$i], 'reservation_id' => 0]; $disabled[] = $range; } $reservable->setDisabledDaysAdminData($disabled); break; case 'reservable_disabled_weekdays': $wdays = array_map(function ($item) { return preg_replace('%[^a-zöäå]%', '', $item); }, $value); $reservable->setDisabledWeekdaysData($wdays); break; case 'reservable_loggedin_only': $reservable->setLoginRequired($value === 'on' ? true : false); break; case 'reservable_overlapping_days': $reservable->setAllowOverlappingReservations($value === 'on' ? true : false); break; } } // Flush caches on save. if ($update) { $reservable->flushCache(); } /** * Hook fired when a reservable is saved to the database. * * Allows doing additional saving logic for reservables. * * @since 0.1.0 * * @param Integer $id The reservable post ID. * @param ReservableObj $reservable The reservable object. * @param Boolean $update Is this an update or a new reservable? */ do_action('wprsrv/reservable/save', $reservable->ID, $reservable, $update); }