Add frontend features with search, shortcodes, widgets, and blocks (v0.6.0)
All checks were successful
Create Release Package / build-release (push) Successful in 1m20s
All checks were successful
Create Release Package / build-release (push) Successful in 1m20s
- Room search with availability, capacity, room type, amenity, price range, and building filters - AJAX-powered search with pagination and load more - Shortcodes: [bnb_buildings], [bnb_rooms], [bnb_room_search], [bnb_building], [bnb_room] - Widgets: Similar Rooms, Building Rooms, Availability Calendar - Gutenberg blocks: Building, Room, Room Search, Buildings List, Rooms List - Frontend CSS with responsive design and CSS custom properties - Frontend JavaScript with SearchForm, CalendarWidget, AvailabilityForm, PriceCalculator Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
867
src/Frontend/Shortcodes.php
Normal file
867
src/Frontend/Shortcodes.php
Normal file
@@ -0,0 +1,867 @@
|
||||
<?php
|
||||
/**
|
||||
* Frontend shortcodes.
|
||||
*
|
||||
* Handles all shortcode registration and rendering.
|
||||
*
|
||||
* @package Magdev\WpBnb\Frontend
|
||||
*/
|
||||
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace Magdev\WpBnb\Frontend;
|
||||
|
||||
use Magdev\WpBnb\Booking\Availability;
|
||||
use Magdev\WpBnb\PostTypes\Building;
|
||||
use Magdev\WpBnb\PostTypes\Room;
|
||||
use Magdev\WpBnb\Pricing\Calculator;
|
||||
use Magdev\WpBnb\Pricing\PricingTier;
|
||||
use Magdev\WpBnb\Taxonomies\Amenity;
|
||||
use Magdev\WpBnb\Taxonomies\RoomType;
|
||||
|
||||
/**
|
||||
* Shortcodes class.
|
||||
*/
|
||||
final class Shortcodes {
|
||||
|
||||
/**
|
||||
* Initialize shortcodes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function init(): void {
|
||||
add_shortcode( 'bnb_buildings', array( self::class, 'render_buildings' ) );
|
||||
add_shortcode( 'bnb_rooms', array( self::class, 'render_rooms' ) );
|
||||
add_shortcode( 'bnb_room_search', array( self::class, 'render_room_search' ) );
|
||||
add_shortcode( 'bnb_building', array( self::class, 'render_single_building' ) );
|
||||
add_shortcode( 'bnb_room', array( self::class, 'render_single_room' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render buildings list/grid shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string HTML output.
|
||||
*/
|
||||
public static function render_buildings( $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'layout' => 'grid',
|
||||
'columns' => 3,
|
||||
'limit' => -1,
|
||||
'orderby' => 'title',
|
||||
'order' => 'ASC',
|
||||
'show_image' => 'yes',
|
||||
'show_address' => 'yes',
|
||||
'show_rooms_count' => 'yes',
|
||||
),
|
||||
$atts,
|
||||
'bnb_buildings'
|
||||
);
|
||||
|
||||
// Query buildings.
|
||||
$query_args = array(
|
||||
'post_type' => Building::POST_TYPE,
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => (int) $atts['limit'],
|
||||
'orderby' => sanitize_text_field( $atts['orderby'] ),
|
||||
'order' => strtoupper( $atts['order'] ) === 'DESC' ? 'DESC' : 'ASC',
|
||||
);
|
||||
|
||||
$buildings = get_posts( $query_args );
|
||||
|
||||
if ( empty( $buildings ) ) {
|
||||
return '<p class="wp-bnb-no-results">' . esc_html__( 'No buildings found.', 'wp-bnb' ) . '</p>';
|
||||
}
|
||||
|
||||
$layout = sanitize_text_field( $atts['layout'] );
|
||||
$columns = max( 1, min( 4, (int) $atts['columns'] ) );
|
||||
|
||||
$classes = array(
|
||||
'wp-bnb-buildings',
|
||||
'wp-bnb-buildings-' . $layout,
|
||||
);
|
||||
|
||||
if ( 'grid' === $layout ) {
|
||||
$classes[] = 'wp-bnb-columns-' . $columns;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="<?php echo esc_attr( implode( ' ', $classes ) ); ?>">
|
||||
<?php foreach ( $buildings as $building ) : ?>
|
||||
<?php echo self::render_building_card( $building, $atts ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a single building card.
|
||||
*
|
||||
* @param \WP_Post $building Building post.
|
||||
* @param array $atts Display attributes.
|
||||
* @return string HTML output.
|
||||
*/
|
||||
private static function render_building_card( \WP_Post $building, array $atts ): string {
|
||||
$show_image = 'yes' === $atts['show_image'];
|
||||
$show_address = 'yes' === $atts['show_address'];
|
||||
$show_rooms_count = 'yes' === $atts['show_rooms_count'];
|
||||
|
||||
// Get room count.
|
||||
$rooms = Room::get_rooms_for_building( $building->ID );
|
||||
$room_count = count( $rooms );
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="wp-bnb-building-card">
|
||||
<?php if ( $show_image && has_post_thumbnail( $building->ID ) ) : ?>
|
||||
<div class="wp-bnb-building-image">
|
||||
<a href="<?php echo esc_url( get_permalink( $building->ID ) ); ?>">
|
||||
<?php echo get_the_post_thumbnail( $building->ID, 'medium_large' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="wp-bnb-building-content">
|
||||
<h3 class="wp-bnb-building-title">
|
||||
<a href="<?php echo esc_url( get_permalink( $building->ID ) ); ?>">
|
||||
<?php echo esc_html( $building->post_title ); ?>
|
||||
</a>
|
||||
</h3>
|
||||
|
||||
<?php if ( $show_address ) : ?>
|
||||
<?php
|
||||
$city = get_post_meta( $building->ID, '_bnb_building_city', true );
|
||||
$country = get_post_meta( $building->ID, '_bnb_building_country', true );
|
||||
if ( $city || $country ) :
|
||||
$countries = Building::get_countries();
|
||||
$country_name = $countries[ $country ] ?? $country;
|
||||
?>
|
||||
<p class="wp-bnb-building-address">
|
||||
<span class="dashicons dashicons-location"></span>
|
||||
<?php echo esc_html( implode( ', ', array_filter( array( $city, $country_name ) ) ) ); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $show_rooms_count && $room_count > 0 ) : ?>
|
||||
<p class="wp-bnb-building-rooms">
|
||||
<span class="dashicons dashicons-admin-home"></span>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %d: Number of rooms */
|
||||
esc_html( _n( '%d room', '%d rooms', $room_count, 'wp-bnb' ) ),
|
||||
(int) $room_count
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( has_excerpt( $building->ID ) ) : ?>
|
||||
<div class="wp-bnb-building-excerpt">
|
||||
<?php echo wp_kses_post( get_the_excerpt( $building->ID ) ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<a href="<?php echo esc_url( get_permalink( $building->ID ) ); ?>" class="wp-bnb-button">
|
||||
<?php esc_html_e( 'View Details', 'wp-bnb' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render rooms list/grid shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string HTML output.
|
||||
*/
|
||||
public static function render_rooms( $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'layout' => 'grid',
|
||||
'columns' => 3,
|
||||
'limit' => 12,
|
||||
'building_id' => 0,
|
||||
'room_type' => '',
|
||||
'amenities' => '',
|
||||
'orderby' => 'title',
|
||||
'order' => 'ASC',
|
||||
'show_image' => 'yes',
|
||||
'show_price' => 'yes',
|
||||
'show_capacity' => 'yes',
|
||||
'show_amenities' => 'yes',
|
||||
'show_building' => 'yes',
|
||||
),
|
||||
$atts,
|
||||
'bnb_rooms'
|
||||
);
|
||||
|
||||
// Use search function for filtering.
|
||||
$search_args = array(
|
||||
'building_id' => (int) $atts['building_id'],
|
||||
'room_type' => sanitize_text_field( $atts['room_type'] ),
|
||||
'amenities' => $atts['amenities'] ? explode( ',', $atts['amenities'] ) : array(),
|
||||
'orderby' => sanitize_text_field( $atts['orderby'] ),
|
||||
'order' => $atts['order'],
|
||||
'limit' => (int) $atts['limit'],
|
||||
);
|
||||
|
||||
$rooms = Search::search( $search_args );
|
||||
|
||||
if ( empty( $rooms ) ) {
|
||||
return '<p class="wp-bnb-no-results">' . esc_html__( 'No rooms found.', 'wp-bnb' ) . '</p>';
|
||||
}
|
||||
|
||||
$layout = sanitize_text_field( $atts['layout'] );
|
||||
$columns = max( 1, min( 4, (int) $atts['columns'] ) );
|
||||
|
||||
$classes = array(
|
||||
'wp-bnb-rooms',
|
||||
'wp-bnb-rooms-' . $layout,
|
||||
);
|
||||
|
||||
if ( 'grid' === $layout ) {
|
||||
$classes[] = 'wp-bnb-columns-' . $columns;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="<?php echo esc_attr( implode( ' ', $classes ) ); ?>">
|
||||
<?php foreach ( $rooms as $room_data ) : ?>
|
||||
<?php echo self::render_room_card( $room_data, $atts ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a single room card.
|
||||
*
|
||||
* @param array $room Room data array.
|
||||
* @param array $atts Display attributes.
|
||||
* @return string HTML output.
|
||||
*/
|
||||
private static function render_room_card( array $room, array $atts ): string {
|
||||
$show_image = 'yes' === $atts['show_image'];
|
||||
$show_price = 'yes' === $atts['show_price'];
|
||||
$show_capacity = 'yes' === $atts['show_capacity'];
|
||||
$show_amenities = 'yes' === $atts['show_amenities'];
|
||||
$show_building = 'yes' === $atts['show_building'];
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="wp-bnb-room-card" data-room-id="<?php echo esc_attr( $room['id'] ); ?>">
|
||||
<?php if ( $show_image && ! empty( $room['featured_image'] ) ) : ?>
|
||||
<div class="wp-bnb-room-image">
|
||||
<a href="<?php echo esc_url( $room['permalink'] ); ?>">
|
||||
<img src="<?php echo esc_url( $room['featured_image'] ); ?>" alt="<?php echo esc_attr( $room['title'] ); ?>">
|
||||
</a>
|
||||
<?php if ( ! empty( $room['room_types'] ) ) : ?>
|
||||
<span class="wp-bnb-room-type-badge"><?php echo esc_html( $room['room_types'][0] ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="wp-bnb-room-content">
|
||||
<h3 class="wp-bnb-room-title">
|
||||
<a href="<?php echo esc_url( $room['permalink'] ); ?>">
|
||||
<?php echo esc_html( $room['title'] ); ?>
|
||||
</a>
|
||||
</h3>
|
||||
|
||||
<?php if ( $show_building && ! empty( $room['building'] ) ) : ?>
|
||||
<p class="wp-bnb-room-building">
|
||||
<span class="dashicons dashicons-building"></span>
|
||||
<a href="<?php echo esc_url( $room['building']['permalink'] ); ?>">
|
||||
<?php echo esc_html( $room['building']['title'] ); ?>
|
||||
</a>
|
||||
<?php if ( ! empty( $room['building']['city'] ) ) : ?>
|
||||
<span class="wp-bnb-room-city">, <?php echo esc_html( $room['building']['city'] ); ?></span>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="wp-bnb-room-meta">
|
||||
<?php if ( $show_capacity && ! empty( $room['capacity'] ) ) : ?>
|
||||
<span class="wp-bnb-room-capacity">
|
||||
<span class="dashicons dashicons-groups"></span>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %d: Number of guests */
|
||||
esc_html( _n( '%d guest', '%d guests', $room['capacity'], 'wp-bnb' ) ),
|
||||
(int) $room['capacity']
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $room['size'] ) ) : ?>
|
||||
<span class="wp-bnb-room-size">
|
||||
<span class="dashicons dashicons-editor-expand"></span>
|
||||
<?php echo esc_html( $room['size'] ); ?> m²
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $room['beds'] ) ) : ?>
|
||||
<span class="wp-bnb-room-beds">
|
||||
<span class="dashicons dashicons-admin-home"></span>
|
||||
<?php echo esc_html( $room['beds'] ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( $show_amenities && ! empty( $room['amenities'] ) ) : ?>
|
||||
<div class="wp-bnb-room-amenities">
|
||||
<?php foreach ( array_slice( $room['amenities'], 0, 4 ) as $amenity ) : ?>
|
||||
<span class="wp-bnb-amenity" title="<?php echo esc_attr( $amenity['name'] ); ?>">
|
||||
<?php if ( ! empty( $amenity['icon'] ) ) : ?>
|
||||
<span class="dashicons dashicons-<?php echo esc_attr( $amenity['icon'] ); ?>"></span>
|
||||
<?php endif; ?>
|
||||
<span class="wp-bnb-amenity-name"><?php echo esc_html( $amenity['name'] ); ?></span>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
<?php if ( count( $room['amenities'] ) > 4 ) : ?>
|
||||
<span class="wp-bnb-amenity-more">
|
||||
+<?php echo (int) ( count( $room['amenities'] ) - 4 ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="wp-bnb-room-footer">
|
||||
<?php if ( $show_price && ! empty( $room['price_formatted'] ) ) : ?>
|
||||
<span class="wp-bnb-room-price">
|
||||
<span class="wp-bnb-price-amount"><?php echo esc_html( $room['price_formatted'] ); ?></span>
|
||||
<span class="wp-bnb-price-unit"><?php esc_html_e( '/night', 'wp-bnb' ); ?></span>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<a href="<?php echo esc_url( $room['permalink'] ); ?>" class="wp-bnb-button">
|
||||
<?php esc_html_e( 'View Details', 'wp-bnb' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render room search form with results.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string HTML output.
|
||||
*/
|
||||
public static function render_room_search( $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'layout' => 'grid',
|
||||
'columns' => 3,
|
||||
'show_dates' => 'yes',
|
||||
'show_guests' => 'yes',
|
||||
'show_room_type' => 'yes',
|
||||
'show_amenities' => 'yes',
|
||||
'show_price_range' => 'yes',
|
||||
'show_building' => 'yes',
|
||||
'results_per_page' => 12,
|
||||
),
|
||||
$atts,
|
||||
'bnb_room_search'
|
||||
);
|
||||
|
||||
// Get search form data.
|
||||
$form_data = Search::get_search_form_data();
|
||||
|
||||
$layout = sanitize_text_field( $atts['layout'] );
|
||||
$columns = max( 1, min( 4, (int) $atts['columns'] ) );
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="wp-bnb-room-search" data-layout="<?php echo esc_attr( $layout ); ?>" data-columns="<?php echo esc_attr( $columns ); ?>" data-per-page="<?php echo esc_attr( $atts['results_per_page'] ); ?>">
|
||||
<form class="wp-bnb-search-form" id="wp-bnb-search-form">
|
||||
<div class="wp-bnb-search-fields">
|
||||
<?php if ( 'yes' === $atts['show_dates'] ) : ?>
|
||||
<div class="wp-bnb-field wp-bnb-field-dates">
|
||||
<div class="wp-bnb-field-group">
|
||||
<label for="wp-bnb-check-in"><?php esc_html_e( 'Check-in', 'wp-bnb' ); ?></label>
|
||||
<input type="date" id="wp-bnb-check-in" name="check_in" min="<?php echo esc_attr( gmdate( 'Y-m-d' ) ); ?>">
|
||||
</div>
|
||||
<div class="wp-bnb-field-group">
|
||||
<label for="wp-bnb-check-out"><?php esc_html_e( 'Check-out', 'wp-bnb' ); ?></label>
|
||||
<input type="date" id="wp-bnb-check-out" name="check_out" min="<?php echo esc_attr( gmdate( 'Y-m-d', strtotime( '+1 day' ) ) ); ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( 'yes' === $atts['show_guests'] ) : ?>
|
||||
<div class="wp-bnb-field wp-bnb-field-guests">
|
||||
<label for="wp-bnb-guests"><?php esc_html_e( 'Guests', 'wp-bnb' ); ?></label>
|
||||
<select id="wp-bnb-guests" name="guests">
|
||||
<option value=""><?php esc_html_e( 'Any', 'wp-bnb' ); ?></option>
|
||||
<?php for ( $i = 1; $i <= $form_data['capacity_range']['max']; $i++ ) : ?>
|
||||
<option value="<?php echo esc_attr( $i ); ?>">
|
||||
<?php echo esc_html( $i ); ?>
|
||||
</option>
|
||||
<?php endfor; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( 'yes' === $atts['show_room_type'] && ! empty( $form_data['room_types'] ) ) : ?>
|
||||
<div class="wp-bnb-field wp-bnb-field-room-type">
|
||||
<label for="wp-bnb-room-type"><?php esc_html_e( 'Room Type', 'wp-bnb' ); ?></label>
|
||||
<select id="wp-bnb-room-type" name="room_type">
|
||||
<option value=""><?php esc_html_e( 'All Types', 'wp-bnb' ); ?></option>
|
||||
<?php foreach ( $form_data['room_types'] as $type ) : ?>
|
||||
<option value="<?php echo esc_attr( $type['slug'] ); ?>">
|
||||
<?php echo esc_html( $type['name'] ); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( 'yes' === $atts['show_building'] && ! empty( $form_data['buildings'] ) ) : ?>
|
||||
<div class="wp-bnb-field wp-bnb-field-building">
|
||||
<label for="wp-bnb-building"><?php esc_html_e( 'Building', 'wp-bnb' ); ?></label>
|
||||
<select id="wp-bnb-building" name="building_id">
|
||||
<option value=""><?php esc_html_e( 'All Buildings', 'wp-bnb' ); ?></option>
|
||||
<?php foreach ( $form_data['buildings'] as $building ) : ?>
|
||||
<option value="<?php echo esc_attr( $building['id'] ); ?>">
|
||||
<?php echo esc_html( $building['title'] ); ?>
|
||||
<?php if ( ! empty( $building['city'] ) ) : ?>
|
||||
(<?php echo esc_html( $building['city'] ); ?>)
|
||||
<?php endif; ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( 'yes' === $atts['show_price_range'] && $form_data['price_range']['max'] > 0 ) : ?>
|
||||
<div class="wp-bnb-field wp-bnb-field-price-range">
|
||||
<label><?php esc_html_e( 'Price Range', 'wp-bnb' ); ?></label>
|
||||
<div class="wp-bnb-price-range-inputs">
|
||||
<input type="number" id="wp-bnb-price-min" name="price_min" placeholder="<?php esc_attr_e( 'Min', 'wp-bnb' ); ?>" min="0" step="10">
|
||||
<span class="wp-bnb-price-separator">-</span>
|
||||
<input type="number" id="wp-bnb-price-max" name="price_max" placeholder="<?php esc_attr_e( 'Max', 'wp-bnb' ); ?>" min="0" step="10">
|
||||
<span class="wp-bnb-currency"><?php echo esc_html( $form_data['currency'] ); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( 'yes' === $atts['show_amenities'] && ! empty( $form_data['amenities'] ) ) : ?>
|
||||
<div class="wp-bnb-search-amenities">
|
||||
<label><?php esc_html_e( 'Amenities', 'wp-bnb' ); ?></label>
|
||||
<div class="wp-bnb-amenities-list">
|
||||
<?php foreach ( $form_data['amenities'] as $amenity ) : ?>
|
||||
<label class="wp-bnb-amenity-checkbox">
|
||||
<input type="checkbox" name="amenities[]" value="<?php echo esc_attr( $amenity['slug'] ); ?>">
|
||||
<?php if ( ! empty( $amenity['icon'] ) ) : ?>
|
||||
<span class="dashicons dashicons-<?php echo esc_attr( $amenity['icon'] ); ?>"></span>
|
||||
<?php endif; ?>
|
||||
<span><?php echo esc_html( $amenity['name'] ); ?></span>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="wp-bnb-search-actions">
|
||||
<button type="submit" class="wp-bnb-button wp-bnb-button-primary">
|
||||
<span class="dashicons dashicons-search"></span>
|
||||
<?php esc_html_e( 'Search Rooms', 'wp-bnb' ); ?>
|
||||
</button>
|
||||
<button type="reset" class="wp-bnb-button wp-bnb-button-secondary">
|
||||
<?php esc_html_e( 'Clear', 'wp-bnb' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="wp-bnb-search-results-container">
|
||||
<div class="wp-bnb-search-status">
|
||||
<span class="wp-bnb-results-count"></span>
|
||||
<div class="wp-bnb-sort-options">
|
||||
<label for="wp-bnb-sort"><?php esc_html_e( 'Sort by:', 'wp-bnb' ); ?></label>
|
||||
<select id="wp-bnb-sort" name="orderby">
|
||||
<option value="title"><?php esc_html_e( 'Name', 'wp-bnb' ); ?></option>
|
||||
<option value="price"><?php esc_html_e( 'Price', 'wp-bnb' ); ?></option>
|
||||
<option value="capacity"><?php esc_html_e( 'Capacity', 'wp-bnb' ); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wp-bnb-search-results wp-bnb-rooms wp-bnb-rooms-<?php echo esc_attr( $layout ); ?> wp-bnb-columns-<?php echo esc_attr( $columns ); ?>">
|
||||
<div class="wp-bnb-loading">
|
||||
<span class="wp-bnb-spinner"></span>
|
||||
<span><?php esc_html_e( 'Loading rooms...', 'wp-bnb' ); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wp-bnb-search-pagination">
|
||||
<button type="button" class="wp-bnb-button wp-bnb-load-more" style="display:none;">
|
||||
<?php esc_html_e( 'Load More', 'wp-bnb' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render single building shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string HTML output.
|
||||
*/
|
||||
public static function render_single_building( $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => 0,
|
||||
'show_rooms' => 'yes',
|
||||
'show_address' => 'yes',
|
||||
'show_contact' => 'yes',
|
||||
),
|
||||
$atts,
|
||||
'bnb_building'
|
||||
);
|
||||
|
||||
$building_id = (int) $atts['id'];
|
||||
|
||||
if ( ! $building_id ) {
|
||||
return '<p class="wp-bnb-error">' . esc_html__( 'Building ID is required.', 'wp-bnb' ) . '</p>';
|
||||
}
|
||||
|
||||
$building = get_post( $building_id );
|
||||
|
||||
if ( ! $building || Building::POST_TYPE !== $building->post_type ) {
|
||||
return '<p class="wp-bnb-error">' . esc_html__( 'Building not found.', 'wp-bnb' ) . '</p>';
|
||||
}
|
||||
|
||||
$show_rooms = 'yes' === $atts['show_rooms'];
|
||||
$show_address = 'yes' === $atts['show_address'];
|
||||
$show_contact = 'yes' === $atts['show_contact'];
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="wp-bnb-building-single">
|
||||
<?php if ( has_post_thumbnail( $building->ID ) ) : ?>
|
||||
<div class="wp-bnb-building-featured-image">
|
||||
<?php echo get_the_post_thumbnail( $building->ID, 'large' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="wp-bnb-building-header">
|
||||
<h2 class="wp-bnb-building-title"><?php echo esc_html( $building->post_title ); ?></h2>
|
||||
</div>
|
||||
|
||||
<div class="wp-bnb-building-details">
|
||||
<?php if ( $show_address ) : ?>
|
||||
<?php $address = Building::get_formatted_address( $building->ID ); ?>
|
||||
<?php if ( ! empty( $address ) ) : ?>
|
||||
<div class="wp-bnb-building-address">
|
||||
<h4><?php esc_html_e( 'Address', 'wp-bnb' ); ?></h4>
|
||||
<address><?php echo nl2br( esc_html( $address ) ); ?></address>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $show_contact ) : ?>
|
||||
<?php
|
||||
$phone = get_post_meta( $building->ID, '_bnb_building_phone', true );
|
||||
$email = get_post_meta( $building->ID, '_bnb_building_email', true );
|
||||
$website = get_post_meta( $building->ID, '_bnb_building_website', true );
|
||||
?>
|
||||
<?php if ( $phone || $email || $website ) : ?>
|
||||
<div class="wp-bnb-building-contact">
|
||||
<h4><?php esc_html_e( 'Contact', 'wp-bnb' ); ?></h4>
|
||||
<?php if ( $phone ) : ?>
|
||||
<p class="wp-bnb-contact-phone">
|
||||
<span class="dashicons dashicons-phone"></span>
|
||||
<a href="tel:<?php echo esc_attr( $phone ); ?>"><?php echo esc_html( $phone ); ?></a>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<?php if ( $email ) : ?>
|
||||
<p class="wp-bnb-contact-email">
|
||||
<span class="dashicons dashicons-email"></span>
|
||||
<a href="mailto:<?php echo esc_attr( $email ); ?>"><?php echo esc_html( $email ); ?></a>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<?php if ( $website ) : ?>
|
||||
<p class="wp-bnb-contact-website">
|
||||
<span class="dashicons dashicons-admin-site"></span>
|
||||
<a href="<?php echo esc_url( $website ); ?>" target="_blank" rel="noopener"><?php echo esc_html( $website ); ?></a>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
$check_in_time = get_post_meta( $building->ID, '_bnb_building_check_in_time', true );
|
||||
$check_out_time = get_post_meta( $building->ID, '_bnb_building_check_out_time', true );
|
||||
if ( $check_in_time || $check_out_time ) :
|
||||
?>
|
||||
<div class="wp-bnb-building-times">
|
||||
<h4><?php esc_html_e( 'Check-in / Check-out', 'wp-bnb' ); ?></h4>
|
||||
<?php if ( $check_in_time ) : ?>
|
||||
<p><strong><?php esc_html_e( 'Check-in:', 'wp-bnb' ); ?></strong> <?php echo esc_html( $check_in_time ); ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if ( $check_out_time ) : ?>
|
||||
<p><strong><?php esc_html_e( 'Check-out:', 'wp-bnb' ); ?></strong> <?php echo esc_html( $check_out_time ); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( ! empty( $building->post_content ) ) : ?>
|
||||
<div class="wp-bnb-building-description">
|
||||
<?php echo wp_kses_post( apply_filters( 'the_content', $building->post_content ) ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $show_rooms ) : ?>
|
||||
<?php $rooms = Room::get_rooms_for_building( $building->ID ); ?>
|
||||
<?php if ( ! empty( $rooms ) ) : ?>
|
||||
<div class="wp-bnb-building-rooms">
|
||||
<h3><?php esc_html_e( 'Available Rooms', 'wp-bnb' ); ?></h3>
|
||||
<?php
|
||||
echo self::render_rooms(
|
||||
array(
|
||||
'building_id' => $building->ID,
|
||||
'show_building' => 'no',
|
||||
'limit' => -1,
|
||||
)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render single room shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string HTML output.
|
||||
*/
|
||||
public static function render_single_room( $atts ): string {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => 0,
|
||||
'show_gallery' => 'yes',
|
||||
'show_pricing' => 'yes',
|
||||
'show_amenities' => 'yes',
|
||||
'show_availability' => 'yes',
|
||||
),
|
||||
$atts,
|
||||
'bnb_room'
|
||||
);
|
||||
|
||||
$room_id = (int) $atts['id'];
|
||||
|
||||
if ( ! $room_id ) {
|
||||
return '<p class="wp-bnb-error">' . esc_html__( 'Room ID is required.', 'wp-bnb' ) . '</p>';
|
||||
}
|
||||
|
||||
$room = get_post( $room_id );
|
||||
|
||||
if ( ! $room || Room::POST_TYPE !== $room->post_type ) {
|
||||
return '<p class="wp-bnb-error">' . esc_html__( 'Room not found.', 'wp-bnb' ) . '</p>';
|
||||
}
|
||||
|
||||
$show_gallery = 'yes' === $atts['show_gallery'];
|
||||
$show_pricing = 'yes' === $atts['show_pricing'];
|
||||
$show_amenities = 'yes' === $atts['show_amenities'];
|
||||
$show_availability = 'yes' === $atts['show_availability'];
|
||||
|
||||
// Get room data.
|
||||
$room_data = Search::get_room_data( $room );
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="wp-bnb-room-single" data-room-id="<?php echo esc_attr( $room->ID ); ?>">
|
||||
<?php if ( $show_gallery && ( has_post_thumbnail( $room->ID ) || ! empty( $room_data['gallery'] ) ) ) : ?>
|
||||
<div class="wp-bnb-room-gallery">
|
||||
<?php if ( has_post_thumbnail( $room->ID ) ) : ?>
|
||||
<div class="wp-bnb-room-featured-image">
|
||||
<?php echo get_the_post_thumbnail( $room->ID, 'large' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $room_data['gallery'] ) ) : ?>
|
||||
<div class="wp-bnb-room-gallery-thumbnails">
|
||||
<?php foreach ( $room_data['gallery'] as $image ) : ?>
|
||||
<a href="<?php echo esc_url( $image['url'] ); ?>" class="wp-bnb-gallery-thumb" data-gallery>
|
||||
<img src="<?php echo esc_url( $image['thumb'] ); ?>" alt="">
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="wp-bnb-room-header">
|
||||
<div class="wp-bnb-room-header-content">
|
||||
<h2 class="wp-bnb-room-title"><?php echo esc_html( $room->post_title ); ?></h2>
|
||||
|
||||
<?php if ( ! empty( $room_data['building'] ) ) : ?>
|
||||
<p class="wp-bnb-room-building">
|
||||
<span class="dashicons dashicons-building"></span>
|
||||
<a href="<?php echo esc_url( $room_data['building']['permalink'] ); ?>">
|
||||
<?php echo esc_html( $room_data['building']['title'] ); ?>
|
||||
</a>
|
||||
<?php if ( ! empty( $room_data['building']['city'] ) ) : ?>
|
||||
<span>, <?php echo esc_html( $room_data['building']['city'] ); ?></span>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $room_data['room_types'] ) ) : ?>
|
||||
<span class="wp-bnb-room-type"><?php echo esc_html( implode( ', ', $room_data['room_types'] ) ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( $show_pricing && ! empty( $room_data['price_formatted'] ) ) : ?>
|
||||
<div class="wp-bnb-room-header-price">
|
||||
<span class="wp-bnb-price-label"><?php esc_html_e( 'From', 'wp-bnb' ); ?></span>
|
||||
<span class="wp-bnb-price-amount"><?php echo esc_html( $room_data['price_formatted'] ); ?></span>
|
||||
<span class="wp-bnb-price-unit"><?php esc_html_e( '/night', 'wp-bnb' ); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="wp-bnb-room-info">
|
||||
<div class="wp-bnb-room-specs">
|
||||
<?php if ( ! empty( $room_data['capacity'] ) ) : ?>
|
||||
<div class="wp-bnb-spec">
|
||||
<span class="dashicons dashicons-groups"></span>
|
||||
<span class="wp-bnb-spec-label"><?php esc_html_e( 'Capacity', 'wp-bnb' ); ?></span>
|
||||
<span class="wp-bnb-spec-value">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %d: Number of guests */
|
||||
esc_html( _n( '%d guest', '%d guests', $room_data['capacity'], 'wp-bnb' ) ),
|
||||
(int) $room_data['capacity']
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $room_data['size'] ) ) : ?>
|
||||
<div class="wp-bnb-spec">
|
||||
<span class="dashicons dashicons-editor-expand"></span>
|
||||
<span class="wp-bnb-spec-label"><?php esc_html_e( 'Size', 'wp-bnb' ); ?></span>
|
||||
<span class="wp-bnb-spec-value"><?php echo esc_html( $room_data['size'] ); ?> m²</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $room_data['beds'] ) ) : ?>
|
||||
<div class="wp-bnb-spec">
|
||||
<span class="dashicons dashicons-admin-home"></span>
|
||||
<span class="wp-bnb-spec-label"><?php esc_html_e( 'Beds', 'wp-bnb' ); ?></span>
|
||||
<span class="wp-bnb-spec-value"><?php echo esc_html( $room_data['beds'] ); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $room_data['bathrooms'] ) ) : ?>
|
||||
<div class="wp-bnb-spec">
|
||||
<span class="dashicons dashicons-admin-page"></span>
|
||||
<span class="wp-bnb-spec-label"><?php esc_html_e( 'Bathrooms', 'wp-bnb' ); ?></span>
|
||||
<span class="wp-bnb-spec-value"><?php echo esc_html( $room_data['bathrooms'] ); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $room_data['floor'] ) ) : ?>
|
||||
<div class="wp-bnb-spec">
|
||||
<span class="dashicons dashicons-building"></span>
|
||||
<span class="wp-bnb-spec-label"><?php esc_html_e( 'Floor', 'wp-bnb' ); ?></span>
|
||||
<span class="wp-bnb-spec-value"><?php echo esc_html( $room_data['floor'] ); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( $show_amenities && ! empty( $room_data['amenities'] ) ) : ?>
|
||||
<div class="wp-bnb-room-amenities-full">
|
||||
<h4><?php esc_html_e( 'Amenities', 'wp-bnb' ); ?></h4>
|
||||
<ul class="wp-bnb-amenities-list">
|
||||
<?php foreach ( $room_data['amenities'] as $amenity ) : ?>
|
||||
<li class="wp-bnb-amenity">
|
||||
<?php if ( ! empty( $amenity['icon'] ) ) : ?>
|
||||
<span class="dashicons dashicons-<?php echo esc_attr( $amenity['icon'] ); ?>"></span>
|
||||
<?php endif; ?>
|
||||
<span><?php echo esc_html( $amenity['name'] ); ?></span>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( ! empty( $room->post_content ) ) : ?>
|
||||
<div class="wp-bnb-room-description">
|
||||
<?php echo wp_kses_post( apply_filters( 'the_content', $room->post_content ) ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $show_pricing ) : ?>
|
||||
<?php $pricing = Calculator::getRoomPricing( $room->ID ); ?>
|
||||
<div class="wp-bnb-room-pricing-details">
|
||||
<h4><?php esc_html_e( 'Pricing', 'wp-bnb' ); ?></h4>
|
||||
<table class="wp-bnb-pricing-table">
|
||||
<tbody>
|
||||
<?php foreach ( PricingTier::cases() as $tier ) : ?>
|
||||
<?php $price = $pricing[ $tier->value ]['price'] ?? null; ?>
|
||||
<?php if ( $price ) : ?>
|
||||
<tr>
|
||||
<td class="wp-bnb-tier-label"><?php echo esc_html( $tier->label() ); ?></td>
|
||||
<td class="wp-bnb-tier-price">
|
||||
<?php echo esc_html( Calculator::formatPrice( $price ) ); ?>
|
||||
<span class="wp-bnb-tier-unit"><?php echo esc_html( $tier->unit() ); ?></span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $show_availability ) : ?>
|
||||
<div class="wp-bnb-room-availability">
|
||||
<h4><?php esc_html_e( 'Check Availability', 'wp-bnb' ); ?></h4>
|
||||
<form class="wp-bnb-availability-form" data-room-id="<?php echo esc_attr( $room->ID ); ?>">
|
||||
<div class="wp-bnb-availability-fields">
|
||||
<div class="wp-bnb-field-group">
|
||||
<label for="wp-bnb-avail-check-in"><?php esc_html_e( 'Check-in', 'wp-bnb' ); ?></label>
|
||||
<input type="date" id="wp-bnb-avail-check-in" name="check_in" min="<?php echo esc_attr( gmdate( 'Y-m-d' ) ); ?>" required>
|
||||
</div>
|
||||
<div class="wp-bnb-field-group">
|
||||
<label for="wp-bnb-avail-check-out"><?php esc_html_e( 'Check-out', 'wp-bnb' ); ?></label>
|
||||
<input type="date" id="wp-bnb-avail-check-out" name="check_out" min="<?php echo esc_attr( gmdate( 'Y-m-d', strtotime( '+1 day' ) ) ); ?>" required>
|
||||
</div>
|
||||
<button type="submit" class="wp-bnb-button wp-bnb-button-primary">
|
||||
<?php esc_html_e( 'Check', 'wp-bnb' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
<div class="wp-bnb-availability-result" style="display:none;"></div>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user