Coupon::PT, 'request_key' => 'daytidy', 'nonce_name' => Coupon::NONCE, ]); } public function init(): void { parent::init(); // Sortable Columns add_filter('manage_edit-' . $this->PT . '_sortable_columns', [$this, 'sortable']); add_action('pre_get_posts', [$this, 'filterQuery']); // Details Metabox (new DetailsMetabox($this))->init(); } public function args(): array { return apply_filters('DayTidy/F__DayTidy/Posts/Coupon__args/args', [ 'labels' => $this->labels( esc_html__('Coupon', 'daytidy'), esc_html__('Coupons', 'daytidy') ), 'public' => false, 'show_ui' => true, 'show_in_menu' => false, 'show_in_rest' => false, 'show_in_admin_bar' => false, 'has_archive' => false, 'exclude_from_search' => true, 'publicly_queryable' => false, 'supports' => ['title'], 'menu_icon' => 'dashicons-text-page', 'menu_position' => 28, 'capabilities' => Capabilities::postTypeCapabilities(Capabilities::MANAGE_BOOKINGS), 'map_meta_cap' => false, ]); } public function columns(array $columns): array { unset($columns['title']); unset($columns['date']); unset($columns['author']); $columns['title'] = esc_html__('Code', 'daytidy'); $columns['discount'] = esc_html__('Discount', 'daytidy'); $columns['deduction'] = esc_html__('Deduction', 'daytidy'); $columns['limit'] = esc_html__('Usage Limit', 'daytidy'); $columns['period'] = esc_html__('Availability', 'daytidy'); $columns['usage'] = esc_html__('Used Times', 'daytidy'); return $columns; } public function content(string $column_name, int $post_id): void { // Coupon Entity $coupon = $this->entity($post_id); if ($column_name === 'discount') { echo esc_html((string) $coupon->getDiscount('display')); } else if ($column_name === 'deduction') { echo esc_html((string) $coupon->getDeduction('display')); } else if ($column_name === 'limit') { echo esc_html((string) $coupon->getLimit('display')); } else if ($column_name === 'period') { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- DayTidy Kses preserves the rendered date separator markup. echo Kses::element($coupon->getPeriod('display')); } else if ($column_name === 'usage') { echo esc_html((string) $coupon->getUsage()); } } /** * @param mixed[] $columns * @return mixed[] */ public function sortable(array $columns): array { $columns['discount'] = 'daytidy_discount'; $columns['deduction'] = 'daytidy_deduction'; return $columns; } /** * @param WP_Query $query */ public function filterQuery(WP_Query $query): void { if (!is_admin() || !$query->is_main_query() || $query->get('post_type') !== $this->PT) return; // Request $req = $_REQUEST; /** * Order */ $orderby = $query->get('orderby'); if ($orderby === 'daytidy_discount') { $query->set('meta_key', 'daytidy_discount'); $query->set('orderby', 'daytidy_discount'); $order = $query->get('order'); $query->set('order', $order ?: 'desc'); } else if ($orderby === 'daytidy_deduction') { $query->set('meta_key', 'daytidy_deduction'); $query->set('orderby', 'daytidy_deduction'); $order = $query->get('order'); $query->set('order', $order ?: 'desc'); } } public function store(Post $entity, array $data): void { $discount = $this->amount($data['discount'] ?? 0, 100); $deduction = $this->amount($data['deduction'] ?? 0); $limit = isset($data['limit']) && is_scalar($data['limit']) && preg_match('/^\d+$/', (string) $data['limit']) ? absint($data['limit']) : ''; $period = isset($data['period']) && is_scalar($data['period']) ? sanitize_text_field((string) $data['period']) : ''; if ($period !== '' && !$this->validPeriod($period)) $period = (string) $entity->meta_get('daytidy_period', ''); // Coupon $entity->meta_store([ 'daytidy_discount' => $discount, 'daytidy_deduction' => $deduction, 'daytidy_limit' => $limit, 'daytidy_period' => $period, ]); // Modules & Third Parties do_action('DayTidy/A__DayTidy/Posts/Coupon__store/data', $entity, $data, $this); } private function validPeriod(string $period): bool { $parts = explode(' - ', $period); if (count($parts) !== 2) return false; $dates = []; foreach ($parts as $part) { $date = DateTimeImmutable::createFromFormat('!Y/m/d H:i', $part); if (!$date || $date->format('Y/m/d H:i') !== $part) return false; $dates[] = $date; } return $dates[0] <= $dates[1]; } /** * @param mixed $value */ private function amount($value, float $maximum = PHP_FLOAT_MAX): float { if (!is_scalar($value) || !is_numeric($value)) return 0.0; $amount = (float) $value; return is_finite($amount) ? min($maximum, max(0.0, $amount)) : 0.0; } public function entity(int $id): CouponEntity { return new CouponEntity($id); } }