perf/fix: externalize images to WP media; normalize Astra leaks; full-width

Plugin (1.8.2):
- remove all bundled raster images (~9.3MB) from assets/img; hero + single
  hero figure now come from the WP Media Library (Settings), shortcode args
  ([viator_hero image_id]), or the vc_testimonials filter — rendered responsive
- vc_hero_image_source() prefers an attachment ID (srcset); listing/hero use it
- settings: store hero_image_id + single_hero_figure_id (media pickers)
- enqueue at priority 20 + depend on astra-theme-css so our CSS wins ties
- stronger Astra overrides (!important): kill page-builder article top padding
  (gap above hero), force full-bleed containers, guard horizontal scroll
- normalize theme leaks inside .vc-app: no link underline, no list bullets
  (with prose exceptions for the tour Overview); gradient hero fallback

Theme: normalize .hoho link/list leaks; rebuild installable ZIP.
Also: move optimized originals to /removed-images/; ship viator-collector.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 19:42:49 +03:30
parent 67c88c795b
commit 35368fb5f9
26 changed files with 135 additions and 29 deletions

View File

@@ -75,6 +75,8 @@ class VC_Settings {
'timeout' => 20,
'default_post_status' => 'publish',
'hero_image' => '',
'hero_image_id' => 0,
'single_hero_figure_id' => 0,
'hero_slides' => '',
'crawl_destinations' => '',
'rate_limit_per_minute' => 25,
@@ -122,6 +124,8 @@ class VC_Settings {
'timeout' => max( 5, absint( $input['timeout'] ?? 20 ) ),
'default_post_status' => sanitize_key( $input['default_post_status'] ?? 'publish' ),
'hero_image' => esc_url_raw( $input['hero_image'] ?? '' ),
'hero_image_id' => absint( $input['hero_image_id'] ?? 0 ),
'single_hero_figure_id' => absint( $input['single_hero_figure_id'] ?? 0 ),
'hero_slides' => self::sanitize_id_list( $input['hero_slides'] ?? '' ),
'crawl_destinations' => self::sanitize_id_list( $input['crawl_destinations'] ?? '' ),
'rate_limit_per_minute' => max( 1, min( 60, absint( $input['rate_limit_per_minute'] ?? 25 ) ) ),
@@ -198,9 +202,10 @@ class VC_Settings {
<th scope="row"><label for="vc_hero_image"><?php echo esc_html__( 'Hero image', 'viator-collector' ); ?></label></th>
<td>
<input id="vc_hero_image" type="url" class="regular-text" name="vc_settings[hero_image]" value="<?php echo esc_attr( $options['hero_image'] ); ?>" placeholder="https://…">
<input id="vc_hero_image_id" type="hidden" name="vc_settings[hero_image_id]" value="<?php echo esc_attr( $options['hero_image_id'] ); ?>">
<button type="button" class="button" id="vc-hero-pick"><?php echo esc_html__( 'Select image', 'viator-collector' ); ?></button>
<button type="button" class="button" id="vc-hero-clear"><?php echo esc_html__( 'Clear', 'viator-collector' ); ?></button>
<p class="description"><?php echo esc_html__( 'Banner shown at the top of the tours listing. Leave empty for a gradient. Destination pages use their own image when one is set.', 'viator-collector' ); ?></p>
<p class="description"><?php echo esc_html__( 'Banner at the top of the tours listing / home hero. Pick from the Media Library so the browser gets responsive, device-sized images. Leave empty for a gradient. Destination pages use their own image when one is set.', 'viator-collector' ); ?></p>
<div id="vc-hero-preview" style="margin-top:8px;">
<?php if ( $options['hero_image'] ) : ?>
<img src="<?php echo esc_url( $options['hero_image'] ); ?>" alt="" style="max-width:320px;height:auto;border-radius:8px;">
@@ -221,6 +226,7 @@ class VC_Settings {
frame.on('select', function () {
var img = frame.state().get('selection').first().toJSON();
$('#vc_hero_image').val(img.url);
$('#vc_hero_image_id').val(img.id);
$('#vc-hero-preview').html($('<img>', { src: img.url, alt: '' }).css({ maxWidth: '320px', height: 'auto', borderRadius: '8px' }));
});
frame.open();
@@ -228,12 +234,56 @@ class VC_Settings {
$('#vc-hero-clear').on('click', function (e) {
e.preventDefault();
$('#vc_hero_image').val('');
$('#vc_hero_image_id').val('');
$('#vc-hero-preview').empty();
});
});
</script>
</td>
</tr>
<tr>
<th scope="row"><label><?php echo esc_html__( 'Single tour hero figure', 'viator-collector' ); ?></label></th>
<td>
<input id="vc_single_figure_id" type="hidden" name="vc_settings[single_hero_figure_id]" value="<?php echo esc_attr( $options['single_hero_figure_id'] ); ?>">
<button type="button" class="button" id="vc-figure-pick"><?php echo esc_html__( 'Select image', 'viator-collector' ); ?></button>
<button type="button" class="button" id="vc-figure-clear"><?php echo esc_html__( 'Clear', 'viator-collector' ); ?></button>
<p class="description"><?php echo esc_html__( 'Optional decorative cut-out shown over the single-tour hero (e.g. a landmark PNG with a transparent background). Leave empty to hide it.', 'viator-collector' ); ?></p>
<div id="vc-figure-preview" style="margin-top:8px;">
<?php
if ( $options['single_hero_figure_id'] ) {
echo wp_get_attachment_image( (int) $options['single_hero_figure_id'], 'medium', false, array( 'style' => 'max-width:200px;height:auto;' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
?>
</div>
<script>
jQuery(function ($) {
var frame;
$('#vc-figure-pick').on('click', function (e) {
e.preventDefault();
if (frame) { frame.open(); return; }
frame = wp.media({
title: <?php echo wp_json_encode( __( 'Select hero figure', 'viator-collector' ) ); ?>,
button: { text: <?php echo wp_json_encode( __( 'Use this image', 'viator-collector' ) ); ?> },
library: { type: 'image' },
multiple: false
});
frame.on('select', function () {
var img = frame.state().get('selection').first().toJSON();
$('#vc_single_figure_id').val(img.id);
var src = (img.sizes && img.sizes.medium) ? img.sizes.medium.url : img.url;
$('#vc-figure-preview').html($('<img>', { src: src, alt: '' }).css({ maxWidth: '200px', height: 'auto' }));
});
frame.open();
});
$('#vc-figure-clear').on('click', function (e) {
e.preventDefault();
$('#vc_single_figure_id').val('');
$('#vc-figure-preview').empty();
});
});
</script>
</td>
</tr>
<tr>
<th scope="row"><label for="vc_hero_slides"><?php echo esc_html__( 'Hero slider images', 'viator-collector' ); ?></label></th>
<td>