| @@ -3,10 +3,13 @@ | ||
| 3 | 3 | declare(strict_types=1); |
| 4 | 4 | |
| 5 | 5 | namespace Yatra\Services; |
| 6 | 6 | |
| 7 | +use Yatra\Helpers\TripListingFilterBuilder; | |
| 8 | +use Yatra\Repositories\TripRepository; | |
| 7 | 9 | use Yatra\Shortcodes\ActivityShortcode; |
| 8 | 10 | use Yatra\Shortcodes\DestinationShortcode; |
| 11 | +use Yatra\Shortcodes\TripCategoryShortcode; | |
| 9 | 12 | |
| 10 | 13 | /** |
| 11 | 14 | * Block Data Service |
| 12 | 15 | * |
| @@ -30,16 +33,55 @@ | ||
| 30 | 33 | { |
| 31 | 34 | return [ |
| 32 | 35 | 'order' => 'desc', |
| 33 | 36 | 'featured' => false, |
| 37 | + 'featured_priority' => '', | |
| 38 | + 'featuredPriority' => '', | |
| 34 | 39 | 'per_page' => 10, |
| 35 | 40 | 'columns' => 3, |
| 36 | 41 | 'title' => 'Our Trips', |
| 37 | 42 | 'show_pagination' => true, |
| 43 | + // Per-instance card layout. 'inherit' = use the site-wide setting. | |
| 44 | + 'card_layout' => 'inherit', | |
| 45 | + 'cardLayout' => '', | |
| 46 | + 'destinationIds' => [], | |
| 47 | + 'activityIds' => [], | |
| 48 | + 'categoryIds' => [], | |
| 49 | + 'difficultyIds' => [], | |
| 50 | + 'destination' => '', | |
| 51 | + 'activity' => '', | |
| 52 | + 'category' => '', | |
| 53 | + 'destination_ids' => '', | |
| 54 | + 'activity_ids' => '', | |
| 55 | + 'category_ids' => '', | |
| 56 | + 'difficulty' => '', | |
| 57 | + 'price_min' => '', | |
| 58 | + 'price_max' => '', | |
| 59 | + 'duration_min' => '', | |
| 60 | + 'duration_max' => '', | |
| 61 | + 'search' => '', | |
| 38 | 62 | ]; |
| 39 | 63 | } |
| 40 | 64 | |
| 65 | + /** Allowed values for the trip "Featured Priority" filter (matches admin TripForm). */ | |
| 66 | + private const FEATURED_PRIORITY_VALUES = ['featured', 'new', 'limited']; | |
| 67 | + | |
| 41 | 68 | /** |
| 69 | + * Trip listing for shortcodes, AJAX pagination, and programmatic use. | |
| 70 | + * | |
| 71 | + * @param array<string, mixed> $rawAtts | |
| 72 | + * | |
| 73 | + * @return array{trips: \Yatra\Models\Trip[], max_pages: int, current_page: int, total_found: int} | |
| 74 | + */ | |
| 75 | + public static function getTripListingForShortcode(array $rawAtts): array | |
| 76 | + { | |
| 77 | + $atts = wp_parse_args(is_array($rawAtts) ? $rawAtts : [], self::defaultTourBlockAttributes()); | |
| 78 | + self::normalizeTripShortcodeAttributes($atts); | |
| 79 | + | |
| 80 | + return self::queryTripsForAtts($atts); | |
| 81 | + } | |
| 82 | + | |
| 83 | + /** | |
| 42 | 84 | * @return array<string, mixed> |
| 43 | 85 | */ |
| 44 | 86 | private static function defaultActivityBlockAttributes(): array |
| 45 | 87 | { |
| @@ -48,8 +90,15 @@ | ||
| 48 | 90 | 'columns' => 3, |
| 49 | 91 | 'per_page' => 10, |
| 50 | 92 | 'title' => 'Activity Listings', |
| 51 | 93 | 'show_pagination' => true, |
| 94 | + 'activityIds' => [], | |
| 95 | + 'activity' => '', | |
| 96 | + 'activity_ids' => '', | |
| 97 | + 'show_trip_count' => true, | |
| 98 | + 'show_description' => true, | |
| 99 | + 'show_image' => true, | |
| 100 | + 'hide_empty' => false, | |
| 52 | 101 | ]; |
| 53 | 102 | } |
| 54 | 103 | |
| 55 | 104 | /** |
| @@ -62,12 +111,42 @@ | ||
| 62 | 111 | 'columns' => 3, |
| 63 | 112 | 'per_page' => 10, |
| 64 | 113 | 'title' => 'Destination Showcase', |
| 65 | 114 | 'show_pagination' => true, |
| 115 | + 'destinationIds' => [], | |
| 116 | + 'destination' => '', | |
| 117 | + 'destination_ids' => '', | |
| 118 | + 'show_trip_count' => true, | |
| 119 | + 'show_description' => true, | |
| 120 | + 'show_image' => true, | |
| 121 | + 'hide_empty' => false, | |
| 122 | + 'featured_only' => false, | |
| 66 | 123 | ]; |
| 67 | 124 | } |
| 68 | 125 | |
| 69 | 126 | /** |
| 127 | + * @return array<string, mixed> | |
| 128 | + */ | |
| 129 | + private static function defaultTripCategoryBlockAttributes(): array | |
| 130 | + { | |
| 131 | + return [ | |
| 132 | + 'order' => 'desc', | |
| 133 | + 'columns' => 3, | |
| 134 | + 'per_page' => 10, | |
| 135 | + 'title' => 'Trip Categories', | |
| 136 | + 'show_pagination' => true, | |
| 137 | + 'category' => '', | |
| 138 | + 'show_trip_count' => true, | |
| 139 | + 'show_description' => true, | |
| 140 | + 'show_image' => true, | |
| 141 | + 'hide_empty' => false, | |
| 142 | + 'featured_only' => false, | |
| 143 | + 'categoryIds' => [], | |
| 144 | + 'category_ids' => '', | |
| 145 | + ]; | |
| 146 | + } | |
| 147 | + | |
| 148 | + /** | |
| 70 | 149 | * Coerce REST/block booleans and legacy string values. |
| 71 | 150 | * |
| 72 | 151 | * @param mixed $value |
| 73 | 152 | */ |
| @@ -110,8 +189,39 @@ | ||
| 110 | 189 | |
| 111 | 190 | $atts['title'] = sanitize_text_field((string) ($atts['title'] ?? 'Our Trips')); |
| 112 | 191 | |
| 113 | 192 | $atts['show_pagination'] = self::coerceToBool($atts['show_pagination'] ?? true, true) ? 'yes' : 'no'; |
| 193 | + | |
| 194 | + // Card layout override. Accept camelCase (Gutenberg block: cardLayout) | |
| 195 | + // and snake_case (shortcode: card_layout). Unknown/empty/"inherit" keeps | |
| 196 | + // 'inherit' so the template falls back to the site-wide Design setting. | |
| 197 | + $cardLayoutRaw = ''; | |
| 198 | + if (isset($atts['cardLayout']) && is_string($atts['cardLayout']) && $atts['cardLayout'] !== '') { | |
| 199 | + $cardLayoutRaw = $atts['cardLayout']; | |
| 200 | + } elseif (isset($atts['card_layout']) && is_string($atts['card_layout']) && $atts['card_layout'] !== '') { | |
| 201 | + $cardLayoutRaw = $atts['card_layout']; | |
| 202 | + } | |
| 203 | + $cardLayoutRaw = strtolower(trim($cardLayoutRaw)); | |
| 204 | + $atts['card_layout'] = in_array($cardLayoutRaw, ['standard', 'compact_mobile', 'compact_all'], true) | |
| 205 | + ? $cardLayoutRaw | |
| 206 | + : 'inherit'; | |
| 207 | + | |
| 208 | + // Featured Priority (matches admin form: featured | new | limited; "none"/empty = no filter). | |
| 209 | + // Accept both snake_case (shortcode) and camelCase (Gutenberg block attribute). | |
| 210 | + $featuredPriorityRaw = ''; | |
| 211 | + if (isset($atts['featured_priority']) && is_string($atts['featured_priority']) && $atts['featured_priority'] !== '') { | |
| 212 | + $featuredPriorityRaw = $atts['featured_priority']; | |
| 213 | + } elseif (isset($atts['featuredPriority']) && is_string($atts['featuredPriority']) && $atts['featuredPriority'] !== '') { | |
| 214 | + $featuredPriorityRaw = $atts['featuredPriority']; | |
| 215 | + } | |
| 216 | + $featuredPriority = strtolower(trim((string) $featuredPriorityRaw)); | |
| 217 | + if ($featuredPriority === 'none') { | |
| 218 | + $featuredPriority = ''; | |
| 219 | + } | |
| 220 | + if ($featuredPriority !== '' && !in_array($featuredPriority, self::FEATURED_PRIORITY_VALUES, true)) { | |
| 221 | + $featuredPriority = ''; | |
| 222 | + } | |
| 223 | + $atts['featured_priority'] = $featuredPriority; | |
| 114 | 224 | } |
| 115 | 225 | |
| 116 | 226 | /** |
| 117 | 227 | * Render trip/tour - Shared method for both blocks and shortcodes |
| @@ -125,9 +235,9 @@ | ||
| 125 | 235 | $atts = wp_parse_args(is_array($attributes) ? $attributes : [], self::defaultTourBlockAttributes()); |
| 126 | 236 | self::normalizeTripShortcodeAttributes($atts); |
| 127 | 237 | |
| 128 | 238 | // Get trips using Yatra's service |
| 129 | - $trips_data = self::getTrips($atts); | |
| 239 | + $trips_data = self::queryTripsForAtts($atts); | |
| 130 | 240 | |
| 131 | 241 | $per_page = max(1, (int) ($atts['per_page'] ?? 10)); |
| 132 | 242 | $atts['per_page'] = $per_page; |
| 133 | 243 | |
| @@ -151,29 +261,16 @@ | ||
| 151 | 261 | self::enqueueTripAssets(); |
| 152 | 262 | |
| 153 | 263 | // Load template |
| 154 | 264 | $result = self::loadTemplate('shortcodes/trip.php', $data); |
| 265 | + | |
| 155 | 266 | |
| 156 | - if (defined('WP_DEBUG') && WP_DEBUG) { | |
| 157 | - error_log('Yatra BlockDataService: Render successful, result length: ' . strlen($result)); | |
| 158 | - } | |
| 159 | - | |
| 160 | 267 | return $result; |
| 161 | 268 | } catch (\Exception $e) { |
| 162 | - // Return error message for debugging | |
| 163 | - if (defined('WP_DEBUG') && WP_DEBUG) { | |
| 164 | - error_log('Yatra BlockDataService Exception: ' . $e->getMessage()); | |
| 165 | - error_log('Yatra BlockDataService Exception Trace: ' . $e->getTraceAsString()); | |
| 166 | - return '<div class="yatra-error">Trip rendering error: ' . esc_html($e->getMessage()) . ' in ' . esc_html($e->getFile()) . ':' . esc_html($e->getLine()) . '</div>'; | |
| 167 | - } | |
| 269 | + | |
| 168 | 270 | return '<div class="yatra-error">Trip rendering failed</div>'; |
| 169 | 271 | } catch (\Error $e) { |
| 170 | - // Catch fatal errors too | |
| 171 | - if (defined('WP_DEBUG') && WP_DEBUG) { | |
| 172 | - error_log('Yatra BlockDataService Error: ' . $e->getMessage()); | |
| 173 | - error_log('Yatra BlockDataService Error Trace: ' . $e->getTraceAsString()); | |
| 174 | - return '<div class="yatra-error">Trip rendering error: ' . esc_html($e->getMessage()) . ' in ' . esc_html($e->getFile()) . ':' . esc_html($e->getLine()) . '</div>'; | |
| 175 | - } | |
| 272 | + | |
| 176 | 273 | return '<div class="yatra-error">Trip rendering failed</div>'; |
| 177 | 274 | } |
| 178 | 275 | } |
| 179 | 276 | |
| @@ -192,10 +289,18 @@ | ||
| 192 | 289 | * Enqueue trip assets |
| 193 | 290 | */ |
| 194 | 291 | private static function enqueueTripAssets(): void |
| 195 | 292 | { |
| 196 | - wp_enqueue_style('yatra-trip-shortcode', \YATRA_PLUGIN_URL . 'assets/css/shortcodes/trip-shortcode.css', array(), '3.0.2.4'); | |
| 197 | - wp_enqueue_script('yatra-trip-shortcode', \YATRA_PLUGIN_URL . 'assets/js/trip-shortcode.js', array('jquery'), '3.0.2.4', true); | |
| 293 | + \Yatra\Providers\FrontendAssetsProvider::registerCoreFrontendStylesheets(); | |
| 294 | + $cssPath = \YATRA_PLUGIN_PATH . 'assets/css/shortcodes/trip-shortcode.css'; | |
| 295 | + $cssVer = is_readable($cssPath) ? \YATRA_VERSION . '.' . filemtime($cssPath) : \YATRA_VERSION; | |
| 296 | + wp_enqueue_style( | |
| 297 | + 'yatra-trip-shortcode', | |
| 298 | + \YATRA_PLUGIN_URL . 'assets/css/shortcodes/trip-shortcode.css', | |
| 299 | + \Yatra\Providers\FrontendAssetsProvider::shortcodeStyleDependencies(), | |
| 300 | + $cssVer | |
| 301 | + ); | |
| 302 | + wp_enqueue_script('yatra-trip-shortcode', \YATRA_PLUGIN_URL . 'assets/js/trip-shortcode.js', array('jquery'), \YATRA_VERSION, true); | |
| 198 | 303 | |
| 199 | 304 | // Localize script for AJAX |
| 200 | 305 | wp_localize_script('yatra-trip-shortcode', 'yatraTripShortcode', [ |
| 201 | 306 | 'ajaxurl' => admin_url('admin-ajax.php'), |
| @@ -230,98 +335,58 @@ | ||
| 230 | 335 | return ob_get_clean(); |
| 231 | 336 | } |
| 232 | 337 | |
| 233 | 338 | /** |
| 234 | - * Get trips data - copied from TripShortcode | |
| 339 | + * @param array<string, mixed> $atts | |
| 340 | + * | |
| 341 | + * @return array{trips: \Yatra\Models\Trip[], max_pages: int, current_page: int, total_found: int} | |
| 235 | 342 | */ |
| 236 | - private static function getTrips(array $atts): array | |
| 343 | + private static function queryTripsForAtts(array $atts): array | |
| 237 | 344 | { |
| 238 | 345 | try { |
| 239 | - $tripService = new \Yatra\Services\TripService(); | |
| 240 | - | |
| 241 | - // Get current page from query string or attributes (for AJAX) | |
| 242 | - $current_page = isset($atts['current_page']) ? (int) $atts['current_page'] : (isset($_GET['trip_page']) ? (int) $_GET['trip_page'] : 1); | |
| 243 | - $per_page = max(1, (int) ($atts['per_page'] ?? 10)); | |
| 244 | - $offset = ($current_page - 1) * $per_page; | |
| 346 | + $tripRepository = new TripRepository(); | |
| 245 | 347 | |
| 246 | - $order = strtolower((string) ($atts['order'] ?? 'desc')); | |
| 348 | + $current_page = isset($atts['current_page']) | |
| 349 | + ? (int) $atts['current_page'] | |
| 350 | + : (isset($_GET['trip_page']) ? (int) $_GET['trip_page'] : 1); | |
| 351 | + $current_page = max(1, $current_page); | |
| 247 | 352 | |
| 248 | - // Start with very basic arguments to ensure we get trips | |
| 249 | - $args = [ | |
| 250 | - 'limit' => $per_page, | |
| 251 | - 'offset' => $offset, | |
| 252 | - 'order_by' => 'created_at', | |
| 253 | - 'order' => $order === 'asc' ? 'ASC' : 'DESC', | |
| 254 | - ]; | |
| 353 | + $per_page = max(1, (int) ($atts['per_page'] ?? 10)); | |
| 255 | 354 | |
| 256 | - // Add featured filter if requested | |
| 257 | - $featured = (string) ($atts['featured'] ?? '0'); | |
| 258 | - if ($featured === '1') { | |
| 259 | - $args['where']['is_featured'] = 1; | |
| 260 | - } | |
| 355 | + $filters = TripListingFilterBuilder::buildFindWithFiltersArray($atts); | |
| 356 | + $result = $tripRepository->findWithFilters($filters, $current_page, $per_page); | |
| 261 | 357 | |
| 262 | - // Get total count for pagination | |
| 263 | - $count_args = $args; | |
| 264 | - unset($count_args['limit']); | |
| 265 | - unset($count_args['offset']); | |
| 266 | - $total_trips = $tripService->count($count_args); | |
| 267 | - | |
| 268 | - // Get trips using the service | |
| 269 | - $trips_data = $tripService->getActiveTrips($args); | |
| 270 | - | |
| 271 | - | |
| 272 | - | |
| 273 | 358 | $trips = []; |
| 274 | - foreach ($trips_data as $tripData) { | |
| 275 | - // Convert to Trip model | |
| 359 | + foreach (($result['trips'] ?? []) as $tripData) { | |
| 276 | 360 | $trip = \Yatra\Models\Trip::fromStdClass($tripData); |
| 277 | - | |
| 278 | - // Add basic data needed for the card | |
| 279 | - // Note: reviews are loaded elsewhere; bookings_count is attached below | |
| 361 | + if (isset($tripData->booking_count)) { | |
| 362 | + $trip->bookings_count = (int) $tripData->booking_count; | |
| 363 | + } | |
| 364 | + if (isset($tripData->review_count)) { | |
| 365 | + $trip->reviews_count = (int) $tripData->review_count; | |
| 366 | + } | |
| 367 | + if (isset($tripData->average_rating)) { | |
| 368 | + $ar = (float) $tripData->average_rating; | |
| 369 | + $trip->average_rating = $ar; | |
| 370 | + $trip->avg_rating = $ar; | |
| 371 | + } | |
| 280 | 372 | $trip->reviews = []; |
| 281 | - | |
| 373 | + | |
| 282 | 374 | $trips[] = $trip; |
| 283 | 375 | } |
| 284 | 376 | |
| 285 | - // Attach bookings_count (computed from bookings table) for just these trips | |
| 286 | - $tripIds = array_map(static function ($t) { | |
| 287 | - return isset($t->id) ? (int) $t->id : 0; | |
| 288 | - }, $trips); | |
| 289 | - $tripIds = array_values(array_filter($tripIds)); | |
| 290 | - if (!empty($tripIds)) { | |
| 291 | - $bookingsCountMap = $tripService->getBookingsCountMap($tripIds); | |
| 292 | - foreach ($trips as $t) { | |
| 293 | - $tId = isset($t->id) ? (int) $t->id : 0; | |
| 294 | - if ($tId > 0) { | |
| 295 | - $t->bookings_count = (int) ($bookingsCountMap[$tId] ?? 0); | |
| 296 | - } | |
| 297 | - } | |
| 298 | - } | |
| 299 | - | |
| 300 | - // Calculate pagination data | |
| 301 | - $max_pages = $per_page > 0 ? ceil($total_trips / $per_page) : 1; | |
| 302 | - | |
| 303 | 377 | return [ |
| 304 | 378 | 'trips' => $trips, |
| 305 | - 'max_pages' => $max_pages, | |
| 306 | - 'current_page' => $current_page, | |
| 307 | - 'total_found' => $total_trips, | |
| 308 | - 'debug_info' => [ | |
| 309 | - 'args_used' => $args, | |
| 310 | - 'raw_count' => count($trips_data) | |
| 311 | - ] | |
| 379 | + 'max_pages' => max(1, (int) ($result['pages'] ?? 1)), | |
| 380 | + 'current_page' => max(1, (int) ($result['page'] ?? $current_page)), | |
| 381 | + 'total_found' => (int) ($result['total'] ?? 0), | |
| 312 | 382 | ]; |
| 313 | - | |
| 314 | 383 | } catch (\Exception $e) { |
| 315 | - if (defined('WP_DEBUG') && WP_DEBUG) { | |
| 316 | - error_log('Yatra BlockDataService Trip Error: ' . $e->getMessage()); | |
| 317 | - } | |
| 318 | - | |
| 319 | 384 | return [ |
| 320 | 385 | 'trips' => [], |
| 321 | 386 | 'max_pages' => 1, |
| 322 | 387 | 'current_page' => 1, |
| 323 | - 'total_found' => 0 | |
| 388 | + 'total_found' => 0, | |
| 324 | 389 | ]; |
| 325 | 390 | } |
| 326 | 391 | } |
| 327 | 392 | |
| @@ -359,8 +424,35 @@ | ||
| 359 | 424 | return $shortcode->render(self::mapDestinationAttributes($merged)); |
| 360 | 425 | } |
| 361 | 426 | |
| 362 | 427 | /** |
| 428 | + * Render trip category block (same card UI as destinations). | |
| 429 | + * | |
| 430 | + * @param array<string, mixed> $attributes | |
| 431 | + */ | |
| 432 | + public static function renderTripCategoryBlock(array $attributes): string | |
| 433 | + { | |
| 434 | + $shortcode = new TripCategoryShortcode(); | |
| 435 | + $merged = wp_parse_args(is_array($attributes) ? $attributes : [], self::defaultTripCategoryBlockAttributes()); | |
| 436 | + | |
| 437 | + return $shortcode->render(self::mapTripCategoryAttributes($merged)); | |
| 438 | + } | |
| 439 | + | |
| 440 | + /** | |
| 441 | + * @param array<string, mixed> $attributes | |
| 442 | + * @param string ...$legacyCsvKeys | |
| 443 | + */ | |
| 444 | + private static function classificationIdsCsvForShortcode( | |
| 445 | + array $attributes, | |
| 446 | + string $arrayKey, | |
| 447 | + string ...$legacyCsvKeys | |
| 448 | + ): string { | |
| 449 | + $ids = TripListingFilterBuilder::positiveIntIdsFromAtts($attributes, $arrayKey, ...$legacyCsvKeys); | |
| 450 | + | |
| 451 | + return $ids === [] ? '' : implode(',', $ids); | |
| 452 | + } | |
| 453 | + | |
| 454 | + /** | |
| 363 | 455 | * Map activity block attributes to shortcode format (full set for shortcode_atts merge). |
| 364 | 456 | * |
| 365 | 457 | * @param array<string, mixed> $attributes Merged with defaults |
| 366 | 458 | * @return array<string, string> |
| @@ -378,8 +470,17 @@ | ||
| 378 | 470 | |
| 379 | 471 | $cols = max(1, min(self::LISTING_COLUMNS_MAX, (int) ($attributes['columns'] ?? 3))); |
| 380 | 472 | |
| 381 | 473 | $showPag = self::coerceToBool($attributes['show_pagination'] ?? true, true); |
| 474 | + // Forward the same visibility / hide-empty toggles the | |
| 475 | + // trip-category block has exposed since v3.0 so all three | |
| 476 | + // taxonomy blocks share one user-facing surface. hide_empty | |
| 477 | + // is what actually skips activities with zero published | |
| 478 | + // trips (see ActivityShortcode::getActivities). | |
| 479 | + $showTripCount = self::coerceToBool($attributes['show_trip_count'] ?? true, true); | |
| 480 | + $showDescription = self::coerceToBool($attributes['show_description'] ?? true, true); | |
| 481 | + $showImage = self::coerceToBool($attributes['show_image'] ?? true, true); | |
| 482 | + $hideEmpty = self::coerceToBool($attributes['hide_empty'] ?? true, true); | |
| 382 | 483 | |
| 383 | 484 | return [ |
| 384 | 485 | 'order' => $order, |
| 385 | 486 | 'per_page' => (string) $perPage, |
| @@ -385,8 +486,18 @@ | ||
| 385 | 486 | 'per_page' => (string) $perPage, |
| 386 | 487 | 'columns' => (string) $cols, |
| 387 | 488 | 'title' => sanitize_text_field((string) ($attributes['title'] ?? 'Activity Listings')), |
| 388 | 489 | 'show_pagination' => $showPag ? 'yes' : 'no', |
| 490 | + 'activity' => self::classificationIdsCsvForShortcode( | |
| 491 | + $attributes, | |
| 492 | + 'activityIds', | |
| 493 | + 'activity_ids', | |
| 494 | + 'activity' | |
| 495 | + ), | |
| 496 | + 'show_trip_count' => $showTripCount ? 'yes' : 'no', | |
| 497 | + 'show_description' => $showDescription ? 'yes' : 'no', | |
| 498 | + 'show_image' => $showImage ? 'yes' : 'no', | |
| 499 | + 'hide_empty' => $hideEmpty ? 'yes' : 'no', | |
| 389 | 500 | ]; |
| 390 | 501 | } |
| 391 | 502 | |
| 392 | 503 | /** |
| @@ -406,8 +517,16 @@ | ||
| 406 | 517 | |
| 407 | 518 | $cols = max(1, min(self::LISTING_COLUMNS_MAX, (int) ($attributes['columns'] ?? 3))); |
| 408 | 519 | |
| 409 | 520 | $showPag = self::coerceToBool($attributes['show_pagination'] ?? true, true); |
| 521 | + // Forward the visibility + hide_empty + featured_only toggles | |
| 522 | + // so the destination block exposes the same controls the | |
| 523 | + // [yatra_destination] shortcode already accepts. | |
| 524 | + $showTripCount = self::coerceToBool($attributes['show_trip_count'] ?? true, true); | |
| 525 | + $showDescription = self::coerceToBool($attributes['show_description'] ?? true, true); | |
| 526 | + $showImage = self::coerceToBool($attributes['show_image'] ?? true, true); | |
| 527 | + $hideEmpty = self::coerceToBool($attributes['hide_empty'] ?? true, true); | |
| 528 | + $featuredOnly = self::coerceToBool($attributes['featured_only'] ?? false, false); | |
| 410 | 529 | |
| 411 | 530 | return [ |
| 412 | 531 | 'order' => $order, |
| 413 | 532 | 'per_page' => (string) $perPage, |
| @@ -413,7 +532,62 @@ | ||
| 413 | 532 | 'per_page' => (string) $perPage, |
| 414 | 533 | 'columns' => (string) $cols, |
| 415 | 534 | 'title' => sanitize_text_field((string) ($attributes['title'] ?? 'Destination Showcase')), |
| 416 | 535 | 'show_pagination' => $showPag ? 'yes' : 'no', |
| 536 | + 'destination' => self::classificationIdsCsvForShortcode( | |
| 537 | + $attributes, | |
| 538 | + 'destinationIds', | |
| 539 | + 'destination_ids', | |
| 540 | + 'destination' | |
| 541 | + ), | |
| 542 | + 'show_trip_count' => $showTripCount ? 'yes' : 'no', | |
| 543 | + 'show_description' => $showDescription ? 'yes' : 'no', | |
| 544 | + 'show_image' => $showImage ? 'yes' : 'no', | |
| 545 | + 'hide_empty' => $hideEmpty ? 'yes' : 'no', | |
| 546 | + 'featured_only' => $featuredOnly ? 'yes' : 'no', | |
| 547 | + ]; | |
| 548 | + } | |
| 549 | + | |
| 550 | + /** | |
| 551 | + * @param array<string, mixed> $attributes | |
| 552 | + * @return array<string, string> | |
| 553 | + */ | |
| 554 | + private static function mapTripCategoryAttributes(array $attributes): array | |
| 555 | + { | |
| 556 | + $order = strtolower((string) ($attributes['order'] ?? 'desc')); | |
| 557 | + $order = in_array($order, ['asc', 'desc'], true) ? $order : 'desc'; | |
| 558 | + | |
| 559 | + $perPage = (int) ($attributes['per_page'] ?? 10); | |
| 560 | + if ($perPage === -1) { | |
| 561 | + $perPage = 10; | |
| 562 | + } | |
| 563 | + $perPage = max(1, min(100, $perPage)); | |
| 564 | + | |
| 565 | + $cols = max(1, min(self::LISTING_COLUMNS_MAX, (int) ($attributes['columns'] ?? 3))); | |
| 566 | + | |
| 567 | + $showPag = self::coerceToBool($attributes['show_pagination'] ?? true, true); | |
| 568 | + $showTripCount = self::coerceToBool($attributes['show_trip_count'] ?? true, true); | |
| 569 | + $showDescription = self::coerceToBool($attributes['show_description'] ?? true, true); | |
| 570 | + $showImage = self::coerceToBool($attributes['show_image'] ?? true, true); | |
| 571 | + $hideEmpty = self::coerceToBool($attributes['hide_empty'] ?? true, true); | |
| 572 | + $featuredOnly = self::coerceToBool($attributes['featured_only'] ?? false, false); | |
| 573 | + | |
| 574 | + return [ | |
| 575 | + 'order' => $order, | |
| 576 | + 'per_page' => (string) $perPage, | |
| 577 | + 'columns' => (string) $cols, | |
| 578 | + 'title' => sanitize_text_field((string) ($attributes['title'] ?? 'Trip Categories')), | |
| 579 | + 'show_pagination' => $showPag ? 'yes' : 'no', | |
| 580 | + 'category' => self::classificationIdsCsvForShortcode( | |
| 581 | + $attributes, | |
| 582 | + 'categoryIds', | |
| 583 | + 'category_ids', | |
| 584 | + 'category' | |
| 585 | + ), | |
| 586 | + 'show_trip_count' => $showTripCount ? 'yes' : 'no', | |
| 587 | + 'show_description' => $showDescription ? 'yes' : 'no', | |
| 588 | + 'show_image' => $showImage ? 'yes' : 'no', | |
| 589 | + 'hide_empty' => $hideEmpty ? 'yes' : 'no', | |
| 590 | + 'featured_only' => $featuredOnly ? 'yes' : 'no', | |
| 417 | 591 | ]; |
| 418 | 592 | } |
| 419 | 593 | } |