post_content, $shortcode ) ) { return true; } } return false; } /** * Marker class so the full-width CSS can be gated to our pages only. */ public static function body_class( $classes ) { if ( self::is_vc_page() ) { $classes[] = 'vc-fullwidth'; } return $classes; } /** * Astra: drop the sidebar on Viator pages. */ public static function astra_page_layout( $layout ) { return self::is_vc_page() ? 'no-sidebar' : $layout; } /** * Astra: use the "page-builder" content layout, which removes the * .ast-container max-width/padding for a true full-width canvas. */ public static function astra_content_layout( $layout ) { return self::is_vc_page() ? 'page-builder' : $layout; } /** * Lazily fetch and cache full product detail the first time a tour page is * viewed, so itinerary/inclusions/etc. are available without crawling * detail for the whole catalogue up front. */ public static function maybe_enrich_single() { if ( is_admin() || ! is_singular( 'viator_tour' ) ) { return; } $post_id = get_queried_object_id(); if ( ! $post_id || get_post_meta( $post_id, '_vc_detail_fetched', true ) ) { return; } $code = get_post_meta( $post_id, '_vc_viator_product_code', true ); if ( ! $code ) { return; } // Avoid repeated calls (and hammering on errors) for the same product. $lock = 'vc_enrich_' . $post_id; if ( get_transient( $lock ) ) { return; } set_transient( $lock, 1, 10 * MINUTE_IN_SECONDS ); ( new VC_Importer() )->enrich_from_detail( $post_id, $code ); } public static function enqueue_assets() { $is_single = is_singular( 'viator_tour' ); $is_archive = is_post_type_archive( 'viator_tour' ) || is_tax( array( 'viator_destination', 'viator_tag', 'viator_category' ) ); $has_short = self::post_has_shortcode(); if ( ! $is_single && ! $is_archive && ! $has_short ) { return; } // Design typeface. wp_enqueue_style( 'vc-fonts', 'https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;700;800&display=swap', array(), null ); // One scoped stylesheet (.vc-app) covers listing, single, and homepage // sections — ported from the "Hop On Hop Off" design. Declare every theme // stylesheet that could fight ours as a dependency (when present) so our // rules always print AFTER them and win equal-specificity ties. We enqueue // at priority 100, so by now the theme (priority 20) has registered them. $deps = array( 'vc-fonts' ); foreach ( array( 'astra-theme-css', 'astra-parent', 'hoho-chrome' ) as $handle ) { if ( wp_style_is( $handle, 'registered' ) ) { $deps[] = $handle; } } 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() ); // Front-end interactions: card rails, FAQ accordion, testimonials // marquee, date field, and auto-submit on quick filter toggles. wp_enqueue_script( 'vc-design', VC_PLUGIN_URL . 'assets/js/vc-design.js', array(), VC_VERSION, true ); // The SVG icon sprite (+ ring-badge path) is printed once in the footer. add_action( 'wp_footer', 'vc_print_icon_sprite' ); } /** * CSS that neutralises Astra's content spacing/width on Viator pages and * makes the design typography win over the theme. Injected after vc-design.css. */ private static function astra_overrides() { return implode( '', array( // Full-bleed: strip Astra's page-builder article padding/width so // the hero and sections reach the viewport edges. !important beats // Astra's own high-specificity rules (e.g. the 2em article padding // that leaves a gap above the hero). '.vc-fullwidth .site-main>article,' . '.vc-fullwidth .ast-page-builder-template .site-main>article,' . '.vc-fullwidth.ast-page-builder-template .site-main>article' . '{padding:0!important;margin:0!important;border:0!important;max-width:none!important;}', '.vc-fullwidth #primary,.vc-fullwidth #content{margin:0!important;padding:0!important;}', // display:block undoes Astra's `.site-content .ast-container{display:flex}` // (≥922px), which otherwise sizes our content to its contents instead // of filling the full-width container. '.vc-fullwidth .site-content .ast-container,.vc-fullwidth .ast-container' . '{max-width:none!important;padding-left:0!important;padding-right:0!important;display:block!important;}', '.vc-fullwidth .entry-content{margin-block:0!important;}', '.vc-fullwidth .site-content{padding:0!important;}', // Guard against a stray horizontal scrollbar from any full-bleed child. 'body.vc-fullwidth{overflow-x:hidden;}', // A gradient stands in when no hero image is set, so the banner is // never blank. '.vc-app.vc-app .hero__media,.vc-app.vc-app .hero-tour{background:linear-gradient(120deg,#101317,#2cafc2);}', // Normalize: stop Astra from decorating our components. Its // .entry-content rules (underlined links, list bullets/indent) // out-specify our scoped base, so reset them here (!important beats // e.g. `.ast-single-post .entry-content a`). Every selector matches // the doubled `.vc-app.vc-app` scope of the main stylesheet so these // patches keep winning against it, not just against the theme. '.vc-app.vc-app a{text-decoration:none;box-shadow:none;}', // No !important on margin/padding: the doubled .vc-app.vc-app scope // already out-specifies Astra's list rules, and !important here was // steamrolling design lists that need their own spacing — e.g. the // rail (