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:
489
assets/js/blocks-editor.js
Normal file
489
assets/js/blocks-editor.js
Normal file
@@ -0,0 +1,489 @@
|
||||
/**
|
||||
* WP BnB Gutenberg Blocks
|
||||
*
|
||||
* @package Magdev\WpBnb
|
||||
*/
|
||||
|
||||
(function(wp) {
|
||||
'use strict';
|
||||
|
||||
const { registerBlockType } = wp.blocks;
|
||||
const { createElement, Fragment } = wp.element;
|
||||
const { InspectorControls, useBlockProps } = wp.blockEditor;
|
||||
const { PanelBody, SelectControl, ToggleControl, RangeControl, Placeholder, Spinner } = wp.components;
|
||||
const { ServerSideRender } = wp.editor || wp.serverSideRender;
|
||||
const { __ } = wp.i18n;
|
||||
const el = createElement;
|
||||
|
||||
// Get localized data
|
||||
const { buildings, rooms, roomTypes, i18n } = wpBnbBlocks;
|
||||
|
||||
// Building options for select
|
||||
const buildingOptions = [
|
||||
{ value: 0, label: i18n.selectBuilding },
|
||||
...buildings
|
||||
];
|
||||
|
||||
// Room options for select
|
||||
const roomOptions = [
|
||||
{ value: 0, label: i18n.selectRoom },
|
||||
...rooms.map(r => ({
|
||||
value: r.value,
|
||||
label: r.building ? `${r.label} (${r.building})` : r.label
|
||||
}))
|
||||
];
|
||||
|
||||
// Room type options
|
||||
const roomTypeOptions = [
|
||||
{ value: '', label: i18n.allTypes },
|
||||
...roomTypes.map(t => ({
|
||||
value: t.slug,
|
||||
label: t.name
|
||||
}))
|
||||
];
|
||||
|
||||
// Building filter options for rooms block
|
||||
const buildingFilterOptions = [
|
||||
{ value: 0, label: i18n.allBuildings },
|
||||
...buildings
|
||||
];
|
||||
|
||||
/**
|
||||
* Building Block
|
||||
*/
|
||||
registerBlockType('wp-bnb/building', {
|
||||
title: i18n.buildingBlock,
|
||||
icon: 'building',
|
||||
category: 'widgets',
|
||||
attributes: {
|
||||
buildingId: { type: 'number', default: 0 },
|
||||
showImage: { type: 'boolean', default: true },
|
||||
showAddress: { type: 'boolean', default: true },
|
||||
showRooms: { type: 'boolean', default: true },
|
||||
showContact: { type: 'boolean', default: true }
|
||||
},
|
||||
|
||||
edit: function(props) {
|
||||
const { attributes, setAttributes } = props;
|
||||
const blockProps = useBlockProps();
|
||||
|
||||
return el(Fragment, {},
|
||||
el(InspectorControls, {},
|
||||
el(PanelBody, { title: i18n.displaySettings },
|
||||
el(SelectControl, {
|
||||
label: i18n.buildingBlock,
|
||||
value: attributes.buildingId,
|
||||
options: buildingOptions,
|
||||
onChange: (value) => setAttributes({ buildingId: parseInt(value, 10) })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showImage,
|
||||
checked: attributes.showImage,
|
||||
onChange: (value) => setAttributes({ showImage: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showAddress,
|
||||
checked: attributes.showAddress,
|
||||
onChange: (value) => setAttributes({ showAddress: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showRooms,
|
||||
checked: attributes.showRooms,
|
||||
onChange: (value) => setAttributes({ showRooms: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showContact,
|
||||
checked: attributes.showContact,
|
||||
onChange: (value) => setAttributes({ showContact: value })
|
||||
})
|
||||
)
|
||||
),
|
||||
el('div', blockProps,
|
||||
attributes.buildingId ?
|
||||
el(ServerSideRender, {
|
||||
block: 'wp-bnb/building',
|
||||
attributes: attributes,
|
||||
LoadingResponsePlaceholder: () => el(Placeholder, { icon: 'building', label: i18n.buildingBlock }, el(Spinner))
|
||||
}) :
|
||||
el(Placeholder, { icon: 'building', label: i18n.buildingBlock },
|
||||
buildings.length === 0 ?
|
||||
el('p', {}, i18n.noBuildings) :
|
||||
el(SelectControl, {
|
||||
value: attributes.buildingId,
|
||||
options: buildingOptions,
|
||||
onChange: (value) => setAttributes({ buildingId: parseInt(value, 10) })
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
save: function() {
|
||||
return null; // Server-side rendered
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Room Block
|
||||
*/
|
||||
registerBlockType('wp-bnb/room', {
|
||||
title: i18n.roomBlock,
|
||||
icon: 'admin-home',
|
||||
category: 'widgets',
|
||||
attributes: {
|
||||
roomId: { type: 'number', default: 0 },
|
||||
showImage: { type: 'boolean', default: true },
|
||||
showGallery: { type: 'boolean', default: true },
|
||||
showPrice: { type: 'boolean', default: true },
|
||||
showAmenities: { type: 'boolean', default: true },
|
||||
showAvailability: { type: 'boolean', default: true }
|
||||
},
|
||||
|
||||
edit: function(props) {
|
||||
const { attributes, setAttributes } = props;
|
||||
const blockProps = useBlockProps();
|
||||
|
||||
return el(Fragment, {},
|
||||
el(InspectorControls, {},
|
||||
el(PanelBody, { title: i18n.displaySettings },
|
||||
el(SelectControl, {
|
||||
label: i18n.roomBlock,
|
||||
value: attributes.roomId,
|
||||
options: roomOptions,
|
||||
onChange: (value) => setAttributes({ roomId: parseInt(value, 10) })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showImage,
|
||||
checked: attributes.showImage,
|
||||
onChange: (value) => setAttributes({ showImage: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showGallery,
|
||||
checked: attributes.showGallery,
|
||||
onChange: (value) => setAttributes({ showGallery: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showPrice,
|
||||
checked: attributes.showPrice,
|
||||
onChange: (value) => setAttributes({ showPrice: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showAmenities,
|
||||
checked: attributes.showAmenities,
|
||||
onChange: (value) => setAttributes({ showAmenities: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showAvailability,
|
||||
checked: attributes.showAvailability,
|
||||
onChange: (value) => setAttributes({ showAvailability: value })
|
||||
})
|
||||
)
|
||||
),
|
||||
el('div', blockProps,
|
||||
attributes.roomId ?
|
||||
el(ServerSideRender, {
|
||||
block: 'wp-bnb/room',
|
||||
attributes: attributes,
|
||||
LoadingResponsePlaceholder: () => el(Placeholder, { icon: 'admin-home', label: i18n.roomBlock }, el(Spinner))
|
||||
}) :
|
||||
el(Placeholder, { icon: 'admin-home', label: i18n.roomBlock },
|
||||
rooms.length === 0 ?
|
||||
el('p', {}, i18n.noRooms) :
|
||||
el(SelectControl, {
|
||||
value: attributes.roomId,
|
||||
options: roomOptions,
|
||||
onChange: (value) => setAttributes({ roomId: parseInt(value, 10) })
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
save: function() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Room Search Block
|
||||
*/
|
||||
registerBlockType('wp-bnb/room-search', {
|
||||
title: i18n.roomSearchBlock,
|
||||
icon: 'search',
|
||||
category: 'widgets',
|
||||
attributes: {
|
||||
layout: { type: 'string', default: 'grid' },
|
||||
columns: { type: 'number', default: 3 },
|
||||
showDates: { type: 'boolean', default: true },
|
||||
showGuests: { type: 'boolean', default: true },
|
||||
showRoomType: { type: 'boolean', default: true },
|
||||
showAmenities: { type: 'boolean', default: true },
|
||||
showPriceRange: { type: 'boolean', default: true },
|
||||
showBuilding: { type: 'boolean', default: true },
|
||||
resultsPerPage: { type: 'number', default: 12 }
|
||||
},
|
||||
|
||||
edit: function(props) {
|
||||
const { attributes, setAttributes } = props;
|
||||
const blockProps = useBlockProps();
|
||||
|
||||
return el(Fragment, {},
|
||||
el(InspectorControls, {},
|
||||
el(PanelBody, { title: i18n.displaySettings },
|
||||
el(SelectControl, {
|
||||
label: i18n.layout,
|
||||
value: attributes.layout,
|
||||
options: [
|
||||
{ value: 'grid', label: i18n.grid },
|
||||
{ value: 'list', label: i18n.list }
|
||||
],
|
||||
onChange: (value) => setAttributes({ layout: value })
|
||||
}),
|
||||
el(RangeControl, {
|
||||
label: i18n.columns,
|
||||
value: attributes.columns,
|
||||
onChange: (value) => setAttributes({ columns: value }),
|
||||
min: 1,
|
||||
max: 4
|
||||
}),
|
||||
el(RangeControl, {
|
||||
label: i18n.resultsPerPage,
|
||||
value: attributes.resultsPerPage,
|
||||
onChange: (value) => setAttributes({ resultsPerPage: value }),
|
||||
min: 4,
|
||||
max: 48
|
||||
})
|
||||
),
|
||||
el(PanelBody, { title: i18n.filterSettings, initialOpen: false },
|
||||
el(ToggleControl, {
|
||||
label: i18n.showDates,
|
||||
checked: attributes.showDates,
|
||||
onChange: (value) => setAttributes({ showDates: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showGuests,
|
||||
checked: attributes.showGuests,
|
||||
onChange: (value) => setAttributes({ showGuests: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showRoomType,
|
||||
checked: attributes.showRoomType,
|
||||
onChange: (value) => setAttributes({ showRoomType: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showAmenities,
|
||||
checked: attributes.showAmenities,
|
||||
onChange: (value) => setAttributes({ showAmenities: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showPriceRange,
|
||||
checked: attributes.showPriceRange,
|
||||
onChange: (value) => setAttributes({ showPriceRange: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showBuilding,
|
||||
checked: attributes.showBuilding,
|
||||
onChange: (value) => setAttributes({ showBuilding: value })
|
||||
})
|
||||
)
|
||||
),
|
||||
el('div', blockProps,
|
||||
el(ServerSideRender, {
|
||||
block: 'wp-bnb/room-search',
|
||||
attributes: attributes,
|
||||
LoadingResponsePlaceholder: () => el(Placeholder, { icon: 'search', label: i18n.roomSearchBlock }, el(Spinner))
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
save: function() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Buildings List Block
|
||||
*/
|
||||
registerBlockType('wp-bnb/buildings', {
|
||||
title: i18n.buildingsBlock,
|
||||
icon: 'building',
|
||||
category: 'widgets',
|
||||
attributes: {
|
||||
layout: { type: 'string', default: 'grid' },
|
||||
columns: { type: 'number', default: 3 },
|
||||
limit: { type: 'number', default: -1 },
|
||||
showImage: { type: 'boolean', default: true },
|
||||
showAddress: { type: 'boolean', default: true },
|
||||
showRoomsCount: { type: 'boolean', default: true }
|
||||
},
|
||||
|
||||
edit: function(props) {
|
||||
const { attributes, setAttributes } = props;
|
||||
const blockProps = useBlockProps();
|
||||
|
||||
return el(Fragment, {},
|
||||
el(InspectorControls, {},
|
||||
el(PanelBody, { title: i18n.displaySettings },
|
||||
el(SelectControl, {
|
||||
label: i18n.layout,
|
||||
value: attributes.layout,
|
||||
options: [
|
||||
{ value: 'grid', label: i18n.grid },
|
||||
{ value: 'list', label: i18n.list }
|
||||
],
|
||||
onChange: (value) => setAttributes({ layout: value })
|
||||
}),
|
||||
el(RangeControl, {
|
||||
label: i18n.columns,
|
||||
value: attributes.columns,
|
||||
onChange: (value) => setAttributes({ columns: value }),
|
||||
min: 1,
|
||||
max: 4
|
||||
}),
|
||||
el(RangeControl, {
|
||||
label: i18n.limit,
|
||||
value: attributes.limit,
|
||||
onChange: (value) => setAttributes({ limit: value }),
|
||||
min: -1,
|
||||
max: 20
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showImage,
|
||||
checked: attributes.showImage,
|
||||
onChange: (value) => setAttributes({ showImage: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showAddress,
|
||||
checked: attributes.showAddress,
|
||||
onChange: (value) => setAttributes({ showAddress: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showRoomsCount,
|
||||
checked: attributes.showRoomsCount,
|
||||
onChange: (value) => setAttributes({ showRoomsCount: value })
|
||||
})
|
||||
)
|
||||
),
|
||||
el('div', blockProps,
|
||||
el(ServerSideRender, {
|
||||
block: 'wp-bnb/buildings',
|
||||
attributes: attributes,
|
||||
LoadingResponsePlaceholder: () => el(Placeholder, { icon: 'building', label: i18n.buildingsBlock }, el(Spinner))
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
save: function() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Rooms List Block
|
||||
*/
|
||||
registerBlockType('wp-bnb/rooms', {
|
||||
title: i18n.roomsBlock,
|
||||
icon: 'admin-home',
|
||||
category: 'widgets',
|
||||
attributes: {
|
||||
layout: { type: 'string', default: 'grid' },
|
||||
columns: { type: 'number', default: 3 },
|
||||
limit: { type: 'number', default: 12 },
|
||||
buildingId: { type: 'number', default: 0 },
|
||||
roomType: { type: 'string', default: '' },
|
||||
showImage: { type: 'boolean', default: true },
|
||||
showPrice: { type: 'boolean', default: true },
|
||||
showCapacity: { type: 'boolean', default: true },
|
||||
showAmenities: { type: 'boolean', default: true },
|
||||
showBuilding: { type: 'boolean', default: true }
|
||||
},
|
||||
|
||||
edit: function(props) {
|
||||
const { attributes, setAttributes } = props;
|
||||
const blockProps = useBlockProps();
|
||||
|
||||
return el(Fragment, {},
|
||||
el(InspectorControls, {},
|
||||
el(PanelBody, { title: i18n.displaySettings },
|
||||
el(SelectControl, {
|
||||
label: i18n.layout,
|
||||
value: attributes.layout,
|
||||
options: [
|
||||
{ value: 'grid', label: i18n.grid },
|
||||
{ value: 'list', label: i18n.list }
|
||||
],
|
||||
onChange: (value) => setAttributes({ layout: value })
|
||||
}),
|
||||
el(RangeControl, {
|
||||
label: i18n.columns,
|
||||
value: attributes.columns,
|
||||
onChange: (value) => setAttributes({ columns: value }),
|
||||
min: 1,
|
||||
max: 4
|
||||
}),
|
||||
el(RangeControl, {
|
||||
label: i18n.limit,
|
||||
value: attributes.limit,
|
||||
onChange: (value) => setAttributes({ limit: value }),
|
||||
min: 1,
|
||||
max: 48
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showImage,
|
||||
checked: attributes.showImage,
|
||||
onChange: (value) => setAttributes({ showImage: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showPrice,
|
||||
checked: attributes.showPrice,
|
||||
onChange: (value) => setAttributes({ showPrice: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showCapacity,
|
||||
checked: attributes.showCapacity,
|
||||
onChange: (value) => setAttributes({ showCapacity: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showAmenities,
|
||||
checked: attributes.showAmenities,
|
||||
onChange: (value) => setAttributes({ showAmenities: value })
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: i18n.showBuilding,
|
||||
checked: attributes.showBuilding,
|
||||
onChange: (value) => setAttributes({ showBuilding: value })
|
||||
})
|
||||
),
|
||||
el(PanelBody, { title: i18n.filterSettings, initialOpen: false },
|
||||
el(SelectControl, {
|
||||
label: i18n.buildingBlock,
|
||||
value: attributes.buildingId,
|
||||
options: buildingFilterOptions,
|
||||
onChange: (value) => setAttributes({ buildingId: parseInt(value, 10) })
|
||||
}),
|
||||
el(SelectControl, {
|
||||
label: i18n.roomType,
|
||||
value: attributes.roomType,
|
||||
options: roomTypeOptions,
|
||||
onChange: (value) => setAttributes({ roomType: value })
|
||||
})
|
||||
)
|
||||
),
|
||||
el('div', blockProps,
|
||||
el(ServerSideRender, {
|
||||
block: 'wp-bnb/rooms',
|
||||
attributes: attributes,
|
||||
LoadingResponsePlaceholder: () => el(Placeholder, { icon: 'admin-home', label: i18n.roomsBlock }, el(Spinner))
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
save: function() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
})(window.wp);
|
||||
Reference in New Issue
Block a user