fix: Astra style conflicts, full-width, responsive hero images, header search

Plugin (viator-collector 1.8.1):
- is_vc_page() now matches any Viator shortcode, so shortcode Pages (home)
  get the full-width no-sidebar canvas
- load vc-design.css after Astra + inline overrides: strip Astra page-builder
  article padding (removes extra gap above hero), full-bleed containers,
  enforce design font inside .vc-app
- vc_hero_img_html(): render hero from the WP media library with responsive
  srcset when the image is an attachment; used in listing + [viator_hero]
  ([viator_hero image_id=".."])

Theme (astra child):
- remove the user/profile header item
- working header search (expands, submits to the tours archive ?vc_q=)
- load chrome.css after Astra + enforce design font inside .hoho
- rebuild installable ZIP

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4hNL1PSHxXbu94SCenpKj
This commit is contained in:
2026-09-15 17:32:07 +03:30
parent eab161aa5c
commit 67c88c795b
10 changed files with 158 additions and 29 deletions

View File

@@ -62,9 +62,18 @@ class VC_Display {
|| is_tax( array( 'viator_destination', 'viator_tag', 'viator_category' ) ) ) {
return true;
}
// A Page hosting the full-listing shortcode also wants full width.
// Any Page hosting a Viator shortcode (hero, sections, listing, …) also
// wants the full-width, no-sidebar canvas.
$post = ( is_singular() ) ? get_post() : null;
return $post && has_shortcode( $post->post_content, 'viator_listing' );
if ( ! $post ) {
return false;
}
foreach ( self::SHORTCODES as $shortcode ) {
if ( has_shortcode( $post->post_content, $shortcode ) ) {
return true;
}
}
return false;
}
/**
@@ -134,9 +143,15 @@ class VC_Display {
// 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.
wp_enqueue_style( 'vc-design', VC_PLUGIN_URL . 'assets/css/vc-design.css', array( 'vc-fonts' ), VC_VERSION );
// One scoped stylesheet (.vc-app) covers listing, single, and homepage
// sections — ported from the "Hop On Hop Off" design. Depend on the Astra
// theme stylesheet (when present) so our rules load AFTER it and win ties.
$deps = array( 'vc-fonts' );
if ( wp_style_is( 'astra-theme-css', 'registered' ) ) {
$deps[] = 'astra-theme-css';
}
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.
@@ -146,6 +161,32 @@ class VC_Display {
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 (fixes the extra
// top gap above the hero and the non-full-width sections).
'.vc-fullwidth .site-main>article,.vc-fullwidth .ast-page-builder-template .site-main>article{padding:0;margin:0;border:0;}',
'.vc-fullwidth #primary{margin:0;padding:0;}',
'.vc-fullwidth .site-content .ast-container{max-width:none;padding-inline:0;}',
'.vc-fullwidth .ast-container{max-width:none;}',
'.vc-fullwidth .entry-content{margin-block:0;}',
'.vc-fullwidth .site-content{padding:0;}',
// Typography: force the design font over Astra inside our scopes.
'.vc-app,.vc-app h1,.vc-app h2,.vc-app h3,.vc-app h4,.vc-app h5,.vc-app h6,'
. '.vc-app p,.vc-app a,.vc-app span,.vc-app li,.vc-app button,.vc-app input,'
. '.vc-app select,.vc-app textarea,.vc-app blockquote'
. '{font-family:"Plus Jakarta Sans",system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;}',
)
);
}
/**
* Read + sanitize the current filter state from the query string. Shared by
* the query builder and the archive template so both stay in sync.

View File

@@ -41,16 +41,25 @@ class VC_Sections {
public static function hero( $atts ) {
$atts = shortcode_atts(
array(
'title' => __( 'Set out on the journey.', 'viator-collector' ),
'eyebrow' => __( 'Tour & Travel', 'viator-collector' ),
'image' => '',
'title' => __( 'Set out on the journey.', 'viator-collector' ),
'eyebrow' => __( 'Tour & Travel', 'viator-collector' ),
'image' => '',
'image_id' => '', // WordPress media attachment ID (responsive).
),
$atts,
self::HERO
);
$img = $atts['image'] ? $atts['image'] : vc_hero_image_url();
if ( ! $img ) {
// Prefer a media-library image (responsive srcset); fall back to a URL,
// the plugin's Hero image setting, then the bundled image.
$img = '';
if ( '' !== $atts['image_id'] ) {
$img = absint( $atts['image_id'] );
} elseif ( '' !== $atts['image'] ) {
$img = $atts['image'];
} elseif ( vc_hero_image_url() ) {
$img = vc_hero_image_url();
} else {
$img = vc_asset_url( 'img/hero.png' );
}
$archive = get_post_type_archive_link( 'viator_tour' );
@@ -64,7 +73,7 @@ class VC_Sections {
<div class="vc-app vc-sections">
<section class="hero">
<div class="hero__media">
<img class="hero__img" src="<?php echo esc_url( $img ); ?>" alt="" fetchpriority="high">
<?php echo vc_hero_img_html( $img, 'hero__img', true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<div class="hero__scrim" aria-hidden="true"></div>
</div>
<div class="container hero__content">

View File

@@ -506,6 +506,45 @@ function vc_asset_url( $rel ) {
return VC_PLUGIN_URL . 'assets/' . ltrim( (string) $rel, '/' );
}
/**
* Hero <img> markup. When the source is a WordPress media item (an attachment
* ID, or a URL that resolves to one), it is rendered with wp_get_attachment_image
* so the browser gets responsive `srcset`/`sizes` and device-appropriate files.
* Anything else (external URLs, bundled fallbacks) falls back to a plain <img>.
*
* @param int|string $src Attachment ID or image URL.
* @param string $class CSS class.
* @param bool $eager Prioritise loading (above-the-fold hero).
*/
function vc_hero_img_html( $src, $class = 'hero__img', $eager = true ) {
$loading = $eager ? 'eager' : 'lazy';
$id = is_numeric( $src ) ? (int) $src : (int) attachment_url_to_postid( (string) $src );
if ( $id ) {
$img = wp_get_attachment_image(
$id,
'full',
false,
array(
'class' => $class,
'loading' => $loading,
'alt' => '',
'sizes' => '100vw',
'fetchpriority' => $eager ? 'high' : 'auto',
)
);
if ( $img ) {
return $img;
}
}
if ( ! $src ) {
return '';
}
$fetch = $eager ? ' fetchpriority="high"' : '';
return '<img class="' . esc_attr( $class ) . '" src="' . esc_url( $src ) . '" alt="" loading="' . esc_attr( $loading ) . '"' . $fetch . '>';
}
/**
* Print the "Hop On Hop Off" SVG icon sprite once per request. The sprite
* holds every <symbol id="i-…"> plus the #ringPathScroll circular text path

Binary file not shown.

View File

@@ -82,7 +82,7 @@ if ( ! $vc_hero_img ) {
?>
<section class="hero hero--archive">
<div class="hero__media">
<img class="hero__img" src="<?php echo esc_url( $vc_hero_img ); ?>" alt="" fetchpriority="high">
<?php echo vc_hero_img_html( $vc_hero_img, 'hero__img', true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<div class="hero__scrim" aria-hidden="true"></div>
</div>

View File

@@ -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.8.0
* Version: 1.8.1
* Author: Amir Bagheri
* License: GPL-2.0-or-later
* Text Domain: viator-collector
*/
define('VC_VERSION', '1.8.0');
define('VC_VERSION', '1.8.1');
define('VC_PLUGIN_FILE', __FILE__);
define('VC_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('VC_PLUGIN_URL', plugin_dir_url(__FILE__));