diff --git a/astra-child-hoponhopoff.zip b/astra-child-hoponhopoff.zip
index 64a1e9c..fb0bdd2 100644
Binary files a/astra-child-hoponhopoff.zip and b/astra-child-hoponhopoff.zip differ
diff --git a/astra-child-hoponhopoff/functions.php b/astra-child-hoponhopoff/functions.php
index cc07b68..cf6ee6c 100644
--- a/astra-child-hoponhopoff/functions.php
+++ b/astra-child-hoponhopoff/functions.php
@@ -23,10 +23,10 @@ add_action( 'wp_enqueue_scripts', function () {
if ( wp_style_is( 'astra-theme-css', 'registered' ) ) {
$deps[] = 'astra-theme-css';
}
- wp_enqueue_style( 'hoho-chrome', get_stylesheet_directory_uri() . '/assets/chrome.css', $deps, '1.0.12' );
+ wp_enqueue_style( 'hoho-chrome', get_stylesheet_directory_uri() . '/assets/chrome.css', $deps, '1.0.13' );
// Header interactions: burger, submenu, sticky, back-to-top, search toggle.
- wp_enqueue_script( 'hoho-chrome', get_stylesheet_directory_uri() . '/assets/chrome.js', array(), '1.0.12', true );
+ wp_enqueue_script( 'hoho-chrome', get_stylesheet_directory_uri() . '/assets/chrome.js', array(), '1.0.13', true );
wp_add_inline_style(
'hoho-chrome',
diff --git a/astra-child-hoponhopoff/inc/footer.php b/astra-child-hoponhopoff/inc/footer.php
index a5179dd..c621063 100644
--- a/astra-child-hoponhopoff/inc/footer.php
+++ b/astra-child-hoponhopoff/inc/footer.php
@@ -12,8 +12,51 @@ $hoho_about = apply_filters(
$hoho_socials = hoho_socials();
-$hoho_footer_col = function ( $location ) {
+/**
+ * Default links for a footer column that has no menu assigned, so the footer
+ * is never three empty headings. Pages are linked only if they exist.
+ */
+$hoho_footer_defaults = function ( $location ) {
+ $page = function ( $slugs, $label ) {
+ foreach ( (array) $slugs as $slug ) {
+ $p = get_page_by_path( $slug );
+ if ( $p && 'publish' === $p->post_status ) {
+ return array( $label, get_permalink( $p ) );
+ }
+ }
+ return null;
+ };
+ $links = array();
+ if ( 'hoho_quick' === $location ) {
+ $links[] = array( __( 'Home', 'hoponhopoff' ), home_url( '/' ) );
+ if ( get_post_type_archive_link( 'viator_tour' ) ) {
+ $links[] = array( __( 'All Tours', 'hoponhopoff' ), get_post_type_archive_link( 'viator_tour' ) );
+ }
+ $links[] = get_option( 'page_for_posts' ) ? array( __( 'Blog', 'hoponhopoff' ), get_permalink( get_option( 'page_for_posts' ) ) ) : $page( array( 'blogs', 'blog' ), __( 'Blog', 'hoponhopoff' ) );
+ } elseif ( 'hoho_tours' === $location && class_exists( 'VC_Structure' ) ) {
+ // The first cities from Settings → Viator Structure.
+ foreach ( array_slice( VC_Structure::cities( VC_Structure::get() ), 0, 6 ) as $city ) {
+ $links[] = array( $city['name'], home_url( '/' . $city['slug'] . '/' ) );
+ }
+ } elseif ( 'hoho_account' === $location ) {
+ $links[] = $page( array( 'contact-us', 'contact' ), __( 'Contact Us', 'hoponhopoff' ) );
+ $links[] = $page( array( 'about-us', 'about' ), __( 'About Us', 'hoponhopoff' ) );
+ $links[] = $page( array( 'faq', 'faqs' ), __( 'FAQ', 'hoponhopoff' ) );
+ }
+ $links = array_filter( $links );
+ if ( ! $links ) {
+ return;
+ }
+ echo '
';
+};
+
+$hoho_footer_col = function ( $location ) use ( $hoho_footer_defaults ) {
if ( ! has_nav_menu( $location ) ) {
+ $hoho_footer_defaults( $location );
return;
}
wp_nav_menu(
diff --git a/astra-child-hoponhopoff/style.css b/astra-child-hoponhopoff/style.css
index 339bf8b..758727c 100644
--- a/astra-child-hoponhopoff/style.css
+++ b/astra-child-hoponhopoff/style.css
@@ -4,7 +4,7 @@ Theme URI: https://git.kaamyab.dev/vargha/TourWebsite
Description: Astra child theme that replaces the Astra header and footer with the "Hop On Hop Off" design. Pairs with the Viator Collector plugin.
Author: Amir Bagheri
Template: astra
-Version: 1.0.12
+Version: 1.0.13
Text Domain: hoponhopoff
*/
diff --git a/viator-collector.zip b/viator-collector.zip
index ec4d876..2568b6e 100644
Binary files a/viator-collector.zip and b/viator-collector.zip differ
diff --git a/viator-collector/assets/css/vc-tour.css b/viator-collector/assets/css/vc-tour.css
new file mode 100644
index 0000000..d6bf7ea
--- /dev/null
+++ b/viator-collector/assets/css/vc-tour.css
@@ -0,0 +1,175 @@
+/* Single tour — top section (photos + booking card first) and the mobile
+ booking bar. Hand-written, loaded after vc-design.css on tour pages only. */
+
+/* No hero any more: the header turns solid (chrome.js) and the page starts
+ with the breadcrumb. */
+.vc-app.vc-app .tour--top {
+ padding-block-start: var(--sp-5);
+}
+
+.vc-app.vc-app .tour__crumbs {
+ margin-block-end: var(--sp-3);
+ color: var(--c-ink);
+}
+
+.vc-app.vc-app .tour__crumbs li[aria-current] {
+ overflow: hidden;
+ max-width: 28ch;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+/* ---------- gallery: one large photo + two, the rest in the lightbox ---------- */
+.vc-app.vc-app .tgal {
+ position: relative;
+ display: grid;
+ grid-template-columns: 2fr 1fr;
+ grid-template-rows: repeat(2, clamp(9rem, 6rem + 6vw, 12.5rem));
+ gap: var(--sp-1);
+}
+
+.vc-app.vc-app .tgal img {
+ width: 100%;
+ height: 100%;
+ aspect-ratio: auto;
+ border-radius: var(--r-card);
+ object-fit: cover;
+}
+
+.vc-app.vc-app .tgal .tgal__main {
+ grid-row: span 2;
+}
+
+.vc-app.vc-app .tgal .tgal__extra {
+ display: none;
+}
+
+.vc-app.vc-app .tgal--few {
+ grid-template-columns: 1fr;
+}
+
+.vc-app.vc-app .tgal--few .tgal__thumb {
+ display: none;
+}
+
+.vc-app.vc-app .tgal__all {
+ position: absolute;
+ right: var(--sp-2);
+ bottom: var(--sp-2);
+ display: inline-flex;
+ align-items: center;
+ gap: 0.375rem;
+ padding: 0.5rem 0.875rem;
+ border: 0;
+ border-radius: var(--r-pill);
+ background: rgba(255, 255, 255, 0.95);
+ color: var(--c-ink);
+ font-size: 0.8125rem;
+ font-weight: 700;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18);
+ cursor: pointer;
+}
+
+/* ---------- title row under the photos ---------- */
+.vc-app.vc-app .tour--top .tour-head__title {
+ font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2.25rem);
+ line-height: 1.2;
+}
+
+.vc-app.vc-app .tmeta__reviews {
+ margin-inline-start: 0.25rem;
+ font-weight: 500;
+ opacity: 0.6;
+}
+
+/* ---------- mobile booking bar ---------- */
+.vc-app.vc-app .tbar {
+ display: none;
+}
+
+@media (max-width: 68.75rem) {
+ /* The bar does the booking now: the full card moves below the content. */
+ .vc-app.vc-app .tour--top .tour__aside {
+ order: 1;
+ }
+
+ .vc-app.vc-app .tbar {
+ position: fixed;
+ inset: auto 0 0 0;
+ z-index: 50;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--sp-3);
+ padding: 0.75rem var(--gutter) calc(0.75rem + env(safe-area-inset-bottom));
+ background: var(--c-white);
+ box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.12);
+ }
+
+ .vc-app.vc-app .tbar__price {
+ display: flex;
+ flex-direction: column;
+ margin: 0;
+ line-height: 1.15;
+ }
+
+ .vc-app.vc-app .tbar__price span {
+ font-size: 0.75rem;
+ opacity: 0.6;
+ }
+
+ .vc-app.vc-app .tbar__price b {
+ font-size: 1.375rem;
+ }
+
+ .vc-app.vc-app .tbar__cta {
+ background: var(--c-accent);
+ color: var(--c-black);
+ }
+
+ /* room for the bar so it never covers the footer */
+ .vc-app.vc-single {
+ padding-block-end: 5rem;
+ }
+}
+
+@media (max-width: 48rem) {
+ /* Swipe through every photo; tap one (or the button) for the lightbox. */
+ .vc-app.vc-app .tgal {
+ display: flex;
+ overflow-x: auto;
+ scroll-snap-type: x mandatory;
+ scrollbar-width: none;
+ margin-inline: calc(var(--gutter) * -1);
+ padding-inline: var(--gutter);
+ }
+
+ .vc-app.vc-app .tgal::-webkit-scrollbar {
+ display: none;
+ }
+
+ .vc-app.vc-app .tgal img,
+ .vc-app.vc-app .tgal .tgal__extra,
+ .vc-app.vc-app .tgal--few .tgal__thumb {
+ display: block;
+ flex: 0 0 88%;
+ aspect-ratio: 4 / 3;
+ scroll-snap-align: center;
+ }
+
+ /* every photo is already in the swipe row */
+ .vc-app.vc-app .tgal__all {
+ display: none;
+ }
+
+ /* the tour name is the page title right below — keep the trail short */
+ .vc-app.vc-app .tour__crumbs li[aria-current] {
+ display: none;
+ }
+
+
+ /* Compact 2 × 2 facts instead of four stacked full-width cards. */
+ .vc-app.vc-app .tour--top .facts {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+}
diff --git a/viator-collector/assets/js/vc-design.js b/viator-collector/assets/js/vc-design.js
index de5591d..ccb3ed2 100644
--- a/viator-collector/assets/js/vc-design.js
+++ b/viator-collector/assets/js/vc-design.js
@@ -138,6 +138,9 @@
box.querySelector(".vc-lightbox__next").addEventListener("click", function () { show(idx + 1); });
box.querySelector(".vc-lightbox__close").addEventListener("click", close);
box.addEventListener("click", function (e) { if (e.target === box) close(); });
+ /* tour page top gallery: "All N photos" opens at the first photo not on show */
+ var allBtn = app.querySelector(".tgal__all");
+ if (allBtn) allBtn.addEventListener("click", function () { open(Math.min(3, imgs.length - 1)); });
document.addEventListener("keydown", function (e) {
if (!box.classList.contains("is-open")) return;
if (e.key === "Escape") close();
diff --git a/viator-collector/includes/class-vc-display.php b/viator-collector/includes/class-vc-display.php
index cd07386..0823e68 100644
--- a/viator-collector/includes/class-vc-display.php
+++ b/viator-collector/includes/class-vc-display.php
@@ -34,7 +34,7 @@ class VC_Display {
// equal-specificity ties. Loading last makes our design win those ties.
add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_assets' ), 100 );
add_action( 'template_redirect', array( __CLASS__, 'maybe_enrich_single' ) );
- add_action( 'pre_get_posts', array( __CLASS__, 'filter_archive_query' ) );
+ add_action( 'pre_get_posts', array( __CLASS__, 'filter_archive_query' ), 999 );
add_filter( 'single_template', array( __CLASS__, 'single_template' ) );
add_filter( 'archive_template', array( __CLASS__, 'archive_template' ) );
add_filter( 'taxonomy_template', array( __CLASS__, 'taxonomy_template' ) );
@@ -164,6 +164,10 @@ class VC_Display {
}
wp_enqueue_style( 'vc-design', VC_PLUGIN_URL . 'assets/css/vc-design.css', $deps, VC_VERSION );
wp_add_inline_style( 'vc-design', self::astra_overrides() );
+ if ( $is_single ) {
+ // Tour page top section + mobile booking bar (after the overrides above).
+ wp_enqueue_style( 'vc-tour', VC_PLUGIN_URL . 'assets/css/vc-tour.css', array( 'vc-design' ), VC_VERSION );
+ }
// Front-end interactions: card rails, FAQ accordion, testimonials
// marquee, date field, and auto-submit on quick filter toggles.
@@ -318,6 +322,8 @@ class VC_Display {
* Apply the filter state to the main tours query (archive + taxonomy pages).
*/
public static function filter_archive_query( $query ) {
+ // Runs late (priority 999, see init) so another plugin/theme setting the
+ // page size can't leave the listing at 10 while it says "1–12".
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
@@ -346,7 +352,9 @@ class VC_Display {
*/
public static function build_query_vars( array $base_tax = array() ) {
$f = self::get_filter_state();
- $vars = array( 'posts_per_page' => 12, 'ignore_sticky_posts' => true );
+ // posts_per_archive_page too: when set (Settings or another plugin), WP_Query
+ // uses it instead of posts_per_page on archives.
+ $vars = array( 'posts_per_page' => 12, 'posts_per_archive_page' => 12, 'ignore_sticky_posts' => true );
if ( '' !== $f['q'] ) {
$vars['s'] = $f['q'];
@@ -741,7 +749,7 @@ class VC_Display {
'viator_browse_activities'
);
- $terms = self::get_section_terms( 'viator_tag', $atts['count'], $atts['ids'] );
+ $terms = VC_Tags::public_terms( self::get_section_terms( 'viator_tag', $atts['count'], $atts['ids'] ) );
if ( empty( $terms ) ) {
return '';
}
diff --git a/viator-collector/includes/class-vc-plugin.php b/viator-collector/includes/class-vc-plugin.php
index 388d6cd..c630ee1 100644
--- a/viator-collector/includes/class-vc-plugin.php
+++ b/viator-collector/includes/class-vc-plugin.php
@@ -34,6 +34,7 @@ final class VC_Plugin {
'includes/class-vc-cpt.php',
'includes/class-vc-taxonomies.php',
'includes/class-vc-structure.php',
+ 'includes/class-vc-tags.php',
'includes/class-vc-api.php',
'includes/class-vc-importer.php',
'includes/class-vc-cron.php',
diff --git a/viator-collector/includes/class-vc-tags.php b/viator-collector/includes/class-vc-tags.php
new file mode 100644
index 0000000..c3fdb97
--- /dev/null
+++ b/viator-collector/includes/class-vc-tags.php
@@ -0,0 +1,41 @@
+name );
+ }
+ )
+ );
+ }
+}
diff --git a/viator-collector/templates/listing.php b/viator-collector/templates/listing.php
index 90e4c94..d34bdbc 100644
--- a/viator-collector/templates/listing.php
+++ b/viator-collector/templates/listing.php
@@ -36,7 +36,7 @@ if ( is_wp_error( $vc_action ) || ! $vc_action ) {
$vc_destinations = get_terms( array( 'taxonomy' => 'viator_destination', 'hide_empty' => true, 'number' => 20, 'orderby' => 'count', 'order' => 'DESC' ) );
$vc_categories = get_terms( array( 'taxonomy' => 'viator_tag', 'hide_empty' => true, 'number' => 20, 'orderby' => 'count', 'order' => 'DESC' ) );
$vc_destinations = is_wp_error( $vc_destinations ) ? array() : $vc_destinations;
-$vc_categories = is_wp_error( $vc_categories ) ? array() : $vc_categories;
+$vc_categories = is_wp_error( $vc_categories ) ? array() : VC_Tags::public_terms( $vc_categories );
$vc_total = (int) $vc_query->found_posts;
$vc_per = 12;
diff --git a/viator-collector/templates/single-viator_tour.php b/viator-collector/templates/single-viator_tour.php
index 7aa9f6e..93f8c25 100644
--- a/viator-collector/templates/single-viator_tour.php
+++ b/viator-collector/templates/single-viator_tour.php
@@ -25,7 +25,7 @@ while ( have_posts() ) :
$dest_terms = get_the_terms( $post_id, 'viator_destination' );
$dest_names = ( $dest_terms && ! is_wp_error( $dest_terms ) ) ? wp_list_pluck( $dest_terms, 'name' ) : array();
$cat_terms = get_the_terms( $post_id, 'viator_tag' );
- $cat_names = ( $cat_terms && ! is_wp_error( $cat_terms ) ) ? array_slice( wp_list_pluck( $cat_terms, 'name' ), 0, 2 ) : array();
+ $cat_names = ( $cat_terms && ! is_wp_error( $cat_terms ) ) ? array_slice( wp_list_pluck( VC_Tags::public_terms( $cat_terms ), 'name' ), 0, 2 ) : array();
$gallery = vc_json_decode_meta( get_post_meta( $post_id, '_vc_gallery_image_urls', true ), array() );
$gallery = array_values( array_filter( (array) $gallery ) );
@@ -33,48 +33,62 @@ while ( have_posts() ) :
if ( ! $primary && ! empty( $gallery ) ) {
$primary = $gallery[0];
}
- $more = array_slice( array_values( array_diff( $gallery, array( $primary ) ) ), 0, 5 );
- $big_word = ! empty( $dest_names ) ? $dest_names[0] : get_the_title();
+ // The featured image (sharp, full size) leads the gallery when set;
+ // Viator's own photos follow.
+ $lead = has_post_thumbnail( $post_id ) ? (string) get_the_post_thumbnail_url( $post_id, 'large' ) : $primary;
+ $all = array_values( array_unique( array_filter( array_merge( array( $lead, $primary ), $gallery ) ) ) );
+
+ // Breadcrumb: Home › Region › City › Tour (the tour's canonical city).
+ $crumbs = array( array( __( 'Home', 'viator-collector' ), home_url( '/' ) ) );
+ $city_slug = class_exists( 'VC_Routing' ) ? VC_Routing::product_city( $post_id ) : '';
+ $city = $city_slug ? get_term_by( 'slug', $city_slug, 'viator_destination' ) : null;
+ if ( ! $city && $dest_terms && ! is_wp_error( $dest_terms ) ) {
+ $city = $dest_terms[0];
+ }
+ if ( $city && $city->parent ) {
+ $region = get_term( $city->parent, 'viator_destination' );
+ if ( $region instanceof WP_Term && ! is_wp_error( get_term_link( $region ) ) ) {
+ $crumbs[] = array( $region->name, get_term_link( $region ) );
+ }
+ }
+ if ( $city && ! is_wp_error( get_term_link( $city ) ) ) {
+ $crumbs[] = array( $city->name, get_term_link( $city ) );
+ }
+
+ $book_href = $booking_url ? $booking_url : '#';
+ $book_attrs = $booking_url ? ' target="_blank" rel="nofollow noopener"' : '';
?>
-
- 'hero-tour__photo', 'fetchpriority' => 'high', 'alt' => '', 'sizes' => '100vw' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- elseif ( $primary ) :
- ?>
-
-
-
+
-
-
-
-
- 'hero-tour__figure', 'loading' => 'eager', 'alt' => '' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
- ?>
-
-
+
-
-
-
+
+
+
+ $url ) : ?>
+
; ?>)
>
+
+ 3 ) : ?>
+
+
+
+
+
-
+
@@ -262,6 +264,14 @@ while ( have_posts() ) :
+
+
+
'Agent Low Quality Product' ),
+ (object) array( 'name' => 'Audio Guides' ),
+ (object) array( 'name' => 'Bus Tours' ),
+ );
+ vc_assert_same( array( 'Audio Guides', 'Bus Tours' ), array_column( VC_Tags::public_terms( $terms ), 'name' ) );
+}
diff --git a/viator-collector/viator-collector.php b/viator-collector/viator-collector.php
index 7702d66..b3154ec 100644
--- a/viator-collector/viator-collector.php
+++ b/viator-collector/viator-collector.php
@@ -4,13 +4,13 @@ defined('ABSPATH') || exit;
/**
* Plugin Name: Viator Collector
* Description: Import Viator tours using the Viator Partner API and display them with native WordPress post types, templates, and shortcodes.
- * Version: 1.9.4
+ * Version: 1.9.5
* Author: Amir Bagheri
* License: GPL-2.0-or-later
* Text Domain: viator-collector
*/
-define('VC_VERSION', '1.9.4');
+define('VC_VERSION', '1.9.5');
define('VC_PLUGIN_FILE', __FILE__);
define('VC_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('VC_PLUGIN_URL', plugin_dir_url(__FILE__));