<?php
/**
* Elementor widget: WooCommerce-style onOffice property gallery.
*/
defined('ABSPATH') || exit;
final class FRESH_OO_Property_Gallery_Widget extends \Elementor\Widget_Base {
public function get_name(): string { return 'fresh-oo-property-gallery'; }
public function get_title(): string { return 'onOffice Immobiliengalerie'; }
public function get_icon(): string { return 'eicon-gallery-grid'; }
public function get_categories(): array { return ['general']; }
public function get_keywords(): array { return ['onoffice','immobilie','galerie','gallery','slider','thumbnails']; }
public function get_style_depends(): array { return ['fresh-oo-property-gallery']; }
public function get_script_depends(): array { return ['fresh-oo-property-gallery']; }
protected function register_controls(): void {
$this->start_controls_section('section_content', [
'label' => 'Galerie',
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]);
$this->add_control('image_size', [
'label' => 'Hauptbild-Größe',
'type' => \Elementor\Controls_Manager::SELECT,
'default' => 'large',
'options' => [
'medium_large' => 'Medium Large',
'large' => 'Large',
'full' => 'Original / Full',
],
]);
$this->add_control('thumb_size', [
'label' => 'Thumbnail-Größe',
'type' => \Elementor\Controls_Manager::SELECT,
'default' => 'thumbnail',
'options' => [
'thumbnail' => 'Thumbnail',
'medium' => 'Medium',
'medium_large' => 'Medium Large',
],
]);
$this->add_control('lightbox', [
'label' => 'Lightbox',
'type' => \Elementor\Controls_Manager::SWITCHER,
'label_on' => 'An', 'label_off' => 'Aus',
'return_value' => 'yes', 'default' => 'yes',
]);
$this->add_control('show_arrows', [
'label' => 'Pfeile',
'type' => \Elementor\Controls_Manager::SWITCHER,
'return_value' => 'yes', 'default' => 'yes',
]);
$this->add_control('show_counter', [
'label' => 'Bildzähler',
'type' => \Elementor\Controls_Manager::SWITCHER,
'return_value' => 'yes', 'default' => 'yes',
]);
$this->add_control('show_caption', [
'label' => 'Bildunterschrift',
'type' => \Elementor\Controls_Manager::SWITCHER,
'return_value' => 'yes', 'default' => '',
]);
$this->add_control('seo_markup', [
'label' => 'SEO-/GEO-Markup',
'type' => \Elementor\Controls_Manager::SWITCHER,
'description' => 'Semantisches ImageGallery-Markup, Alt-Texte, Captions und strukturierte Bildbeziehungen für Suchmaschinen und KI-Systeme.',
'return_value' => 'yes', 'default' => 'yes',
]);
$this->end_controls_section();
$this->start_controls_section('section_layout', [
'label' => 'Layout',
'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]);
$this->add_responsive_control('main_ratio', [
'label' => 'Hauptbild-Seitenverhältnis',
'type' => \Elementor\Controls_Manager::SELECT,
'default' => '4 / 3',
'tablet_default' => '4 / 3',
'mobile_default' => '1 / 1',
'options' => [
'16 / 9' => '16:9', '3 / 2' => '3:2', '4 / 3' => '4:3',
'1 / 1' => '1:1', '3 / 4' => '3:4', 'auto' => 'Automatisch',
],
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery__main-media' => 'aspect-ratio: {{VALUE}};'],
]);
$this->add_responsive_control('gallery_gap', [
'label' => 'Abstand zu Thumbnails',
'type' => \Elementor\Controls_Manager::SLIDER,
'size_units' => ['px','rem'],
'range' => ['px'=>['min'=>0,'max'=>60], 'rem'=>['min'=>0,'max'=>4,'step'=>0.1]],
'default' => ['unit'=>'px','size'=>12],
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery' => '--fresh-oo-gallery-gap: {{SIZE}}{{UNIT}};'],
]);
$this->add_responsive_control('thumb_width', [
'label' => 'Thumbnail-Breite',
'type' => \Elementor\Controls_Manager::SLIDER,
'size_units' => ['px','vw'],
'range' => ['px'=>['min'=>50,'max'=>240], 'vw'=>['min'=>10,'max'=>50]],
'default' => ['unit'=>'px','size'=>110],
'tablet_default' => ['unit'=>'px','size'=>95],
'mobile_default' => ['unit'=>'px','size'=>80],
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery' => '--fresh-oo-thumb-width: {{SIZE}}{{UNIT}};'],
]);
$this->add_responsive_control('thumb_ratio', [
'label' => 'Thumbnail-Seitenverhältnis',
'type' => \Elementor\Controls_Manager::SELECT,
'default' => '4 / 3',
'options' => ['16 / 9'=>'16:9','3 / 2'=>'3:2','4 / 3'=>'4:3','1 / 1'=>'1:1'],
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery__thumb' => 'aspect-ratio: {{VALUE}};'],
]);
$this->add_responsive_control('thumb_gap', [
'label' => 'Thumbnail-Abstand',
'type' => \Elementor\Controls_Manager::SLIDER,
'size_units' => ['px'],
'range' => ['px'=>['min'=>0,'max'=>30]],
'default' => ['unit'=>'px','size'=>8],
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery' => '--fresh-oo-thumb-gap: {{SIZE}}{{UNIT}};'],
]);
$this->end_controls_section();
$this->start_controls_section('section_main_style', [
'label' => 'Hauptbild', 'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]);
$this->add_responsive_control('main_radius', [
'label' => 'Eckenradius', 'type' => \Elementor\Controls_Manager::DIMENSIONS,
'size_units' => ['px','%'],
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery__main-media' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'],
]);
$this->add_group_control(\Elementor\Group_Control_Border::get_type(), [
'name' => 'main_border', 'selector' => '{{WRAPPER}} .fresh-oo-gallery__main-media',
]);
$this->add_group_control(\Elementor\Group_Control_Box_Shadow::get_type(), [
'name' => 'main_shadow', 'selector' => '{{WRAPPER}} .fresh-oo-gallery__main-media',
]);
$this->add_control('image_fit', [
'label' => 'Bildanpassung', 'type' => \Elementor\Controls_Manager::SELECT,
'default' => 'cover', 'options' => ['cover'=>'Ausfüllen (Cover)','contain'=>'Einpassen (Contain)'],
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery__main-image' => 'object-fit: {{VALUE}};'],
]);
$this->add_control('main_bg', [
'label' => 'Hintergrund', 'type' => \Elementor\Controls_Manager::COLOR,
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery__main-media' => 'background-color: {{VALUE}};'],
]);
$this->end_controls_section();
$this->start_controls_section('section_thumb_style', [
'label' => 'Thumbnails', 'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]);
$this->add_responsive_control('thumb_radius', [
'label' => 'Eckenradius', 'type' => \Elementor\Controls_Manager::DIMENSIONS,
'size_units' => ['px','%'],
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery__thumb' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'],
]);
$this->add_control('thumb_opacity', [
'label' => 'Inaktive Deckkraft', 'type' => \Elementor\Controls_Manager::SLIDER,
'range' => ['px'=>['min'=>0.2,'max'=>1,'step'=>0.05]],
'default' => ['size'=>0.65],
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery' => '--fresh-oo-thumb-opacity: {{SIZE}};'],
]);
$this->add_control('thumb_active_color', [
'label' => 'Aktive Rahmenfarbe', 'type' => \Elementor\Controls_Manager::COLOR,
'default' => '#9a7b4f',
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery' => '--fresh-oo-active-color: {{VALUE}};'],
]);
$this->add_responsive_control('thumb_active_width', [
'label' => 'Aktive Rahmenstärke', 'type' => \Elementor\Controls_Manager::SLIDER,
'range' => ['px'=>['min'=>1,'max'=>8]], 'default'=>['unit'=>'px','size'=>2],
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery' => '--fresh-oo-active-width: {{SIZE}}{{UNIT}};'],
]);
$this->end_controls_section();
$this->start_controls_section('section_ui_style', [
'label' => 'Navigation & UI', 'tab' => \Elementor\Controls_Manager::TAB_STYLE,
]);
$this->add_control('ui_color', [
'label' => 'Icon-Farbe', 'type' => \Elementor\Controls_Manager::COLOR,
'default' => '#1f1f1f', 'selectors' => ['{{WRAPPER}} .fresh-oo-gallery' => '--fresh-oo-ui-color: {{VALUE}};'],
]);
$this->add_control('ui_bg', [
'label' => 'Button-Hintergrund', 'type' => \Elementor\Controls_Manager::COLOR,
'default' => 'rgba(255,255,255,.90)', 'selectors' => ['{{WRAPPER}} .fresh-oo-gallery' => '--fresh-oo-ui-bg: {{VALUE}};'],
]);
$this->add_responsive_control('arrow_size', [
'label' => 'Pfeil-Button Größe', 'type' => \Elementor\Controls_Manager::SLIDER,
'range' => ['px'=>['min'=>28,'max'=>72]], 'default'=>['unit'=>'px','size'=>42],
'selectors' => ['{{WRAPPER}} .fresh-oo-gallery' => '--fresh-oo-arrow-size: {{SIZE}}{{UNIT}};'],
]);
$this->add_control('counter_bg', [
'label' => 'Zähler-Hintergrund', 'type' => \Elementor\Controls_Manager::COLOR,
'default' => 'rgba(0,0,0,.60)', 'selectors' => ['{{WRAPPER}} .fresh-oo-gallery__counter' => 'background-color: {{VALUE}};'],
]);
$this->add_control('counter_color', [
'label' => 'Zähler-Farbe', 'type' => \Elementor\Controls_Manager::COLOR,
'default' => '#ffffff', 'selectors' => ['{{WRAPPER}} .fresh-oo-gallery__counter' => 'color: {{VALUE}};'],
]);
$this->end_controls_section();
}
protected function render(): void {
$settings = $this->get_settings_for_display();
$post_id = get_the_ID();
if (!$post_id) return;
$ids = get_post_meta($post_id, 'oo_gallery_ids', true);
if (!is_array($ids)) $ids = [];
$ids = array_values(array_unique(array_filter(array_map('intval', $ids))));
if (!$ids) {
if (\Elementor\Plugin::$instance->editor->is_edit_mode()) {
echo '<div class="elementor-alert elementor-alert-info">Für diese Immobilie wurden noch keine onOffice-Galeriebilder importiert.</div>';
}
return;
}
$images = [];
foreach ($ids as $id) {
if (get_post_type($id) !== 'attachment') continue;
$full = wp_get_attachment_image_src($id, 'full');
$main = wp_get_attachment_image_src($id, $settings['image_size'] ?: 'large');
$thumb = wp_get_attachment_image_src($id, $settings['thumb_size'] ?: 'thumbnail');
if (!$full || !$main || !$thumb) continue;
$alt = trim((string)get_post_meta($id, '_wp_attachment_image_alt', true));
$attachment = get_post($id);
$caption = $attachment ? trim((string)$attachment->post_excerpt) : '';
$title = $attachment ? trim((string)$attachment->post_title) : '';
if ($alt === '') $alt = $caption ?: $title ?: get_the_title($post_id);
$images[] = [
'id'=>$id, 'full'=>$full[0], 'main'=>$main[0], 'thumb'=>$thumb[0],
'srcset'=>wp_get_attachment_image_srcset($id, $settings['image_size'] ?: 'large') ?: '',
'sizes'=>wp_get_attachment_image_sizes($id, $settings['image_size'] ?: 'large') ?: '(max-width: 1200px) 100vw, 1200px',
'width'=>(int)$main[1], 'height'=>(int)$main[2], 'alt'=>$alt,
'caption'=>$caption, 'title'=>$title,
];
}
if (!$images) return;
$uid = 'fresh-oo-gallery-' . esc_attr($this->get_id());
$first = $images[0];
$schema = ($settings['seo_markup'] ?? 'yes') === 'yes';
$lightbox = ($settings['lightbox'] ?? 'yes') === 'yes';
$show_arrows = ($settings['show_arrows'] ?? 'yes') === 'yes' && count($images) > 1;
$show_counter = ($settings['show_counter'] ?? 'yes') === 'yes' && count($images) > 1;
$show_caption = ($settings['show_caption'] ?? '') === 'yes';
?>
<div id="<?php echo esc_attr($uid); ?>" class="fresh-oo-gallery" data-fresh-oo-gallery data-lightbox="<?php echo $lightbox ? '1' : '0'; ?>" <?php if ($schema): ?>itemscope itemtype="https://schema.org/ImageGallery"<?php endif; ?>>
<figure class="fresh-oo-gallery__main" <?php if ($schema): ?>itemprop="associatedMedia" itemscope itemtype="https://schema.org/ImageObject"<?php endif; ?>>
<button type="button" class="fresh-oo-gallery__main-media<?php echo $lightbox ? ' is-lightbox-enabled' : ''; ?>" data-gallery-main aria-label="<?php echo esc_attr($lightbox ? 'Bild vergrößern' : 'Galeriebild'); ?>">
<img class="fresh-oo-gallery__main-image" data-gallery-main-image src="<?php echo esc_url($first['main']); ?>" srcset="<?php echo esc_attr($first['srcset']); ?>" sizes="<?php echo esc_attr($first['sizes']); ?>" width="<?php echo (int)$first['width']; ?>" height="<?php echo (int)$first['height']; ?>" alt="<?php echo esc_attr($first['alt']); ?>" loading="eager" decoding="async" fetchpriority="high" <?php if ($schema): ?>itemprop="contentUrl"<?php endif; ?>>
<?php if ($show_counter): ?><span class="fresh-oo-gallery__counter" aria-live="polite"><span data-gallery-current>1</span> / <?php echo count($images); ?></span><?php endif; ?>
<?php if ($show_arrows): ?>
<span class="fresh-oo-gallery__main-nav fresh-oo-gallery__main-nav--prev" data-gallery-prev aria-hidden="true">‹</span>
<span class="fresh-oo-gallery__main-nav fresh-oo-gallery__main-nav--next" data-gallery-next aria-hidden="true">›</span>
<?php endif; ?>
</button>
<?php if ($show_caption): ?><figcaption class="fresh-oo-gallery__caption" data-gallery-caption <?php if ($schema): ?>itemprop="caption"<?php endif; ?>><?php echo esc_html($first['caption'] ?: $first['title']); ?></figcaption><?php endif; ?>
<?php if ($schema): ?><meta itemprop="name" content="<?php echo esc_attr($first['title'] ?: $first['alt']); ?>"><meta itemprop="description" content="<?php echo esc_attr($first['caption'] ?: $first['alt']); ?>"><?php endif; ?>
</figure>
<?php if (count($images) > 1): ?>
<div class="fresh-oo-gallery__thumb-shell">
<?php if ($show_arrows): ?><button type="button" class="fresh-oo-gallery__thumb-arrow fresh-oo-gallery__thumb-arrow--prev" data-gallery-thumbs-prev aria-label="Vorherige Vorschaubilder">‹</button><?php endif; ?>
<div class="fresh-oo-gallery__thumbs" data-gallery-thumbs role="list" aria-label="Immobilienbilder">
<?php foreach ($images as $i => $img): ?>
<button type="button" class="fresh-oo-gallery__thumb<?php echo $i === 0 ? ' is-active' : ''; ?>" role="listitem" aria-label="Bild <?php echo $i+1; ?> von <?php echo count($images); ?> anzeigen" aria-current="<?php echo $i === 0 ? 'true' : 'false'; ?>"
data-gallery-thumb data-index="<?php echo $i; ?>"
data-main="<?php echo esc_url($img['main']); ?>"
data-full="<?php echo esc_url($img['full']); ?>"
data-srcset="<?php echo esc_attr($img['srcset']); ?>"
data-sizes="<?php echo esc_attr($img['sizes']); ?>"
data-alt="<?php echo esc_attr($img['alt']); ?>"
data-caption="<?php echo esc_attr($img['caption'] ?: $img['title']); ?>"
data-title="<?php echo esc_attr($img['title']); ?>">
<?php echo wp_get_attachment_image($img['id'], $settings['thumb_size'] ?: 'thumbnail', false, ['loading'=>'lazy','decoding'=>'async','alt'=>$img['alt']]); ?>
</button>
<?php endforeach; ?>
</div>
<?php if ($show_arrows): ?><button type="button" class="fresh-oo-gallery__thumb-arrow fresh-oo-gallery__thumb-arrow--next" data-gallery-thumbs-next aria-label="Weitere Vorschaubilder">›</button><?php endif; ?>
</div>
<?php endif; ?>
<?php if ($lightbox): ?>
<dialog class="fresh-oo-gallery__lightbox" data-gallery-lightbox aria-label="Bildansicht">
<button type="button" class="fresh-oo-gallery__lightbox-close" data-gallery-lightbox-close aria-label="Lightbox schließen">×</button>
<?php if ($show_arrows && count($images) > 1): ?><button type="button" class="fresh-oo-gallery__lightbox-nav fresh-oo-gallery__lightbox-nav--prev" data-gallery-lightbox-prev aria-label="Vorheriges Bild">‹</button><?php endif; ?>
<figure>
<img data-gallery-lightbox-image src="" alt="" decoding="async">
<?php if ($show_caption): ?><figcaption data-gallery-lightbox-caption></figcaption><?php endif; ?>
</figure>
<?php if ($show_arrows && count($images) > 1): ?><button type="button" class="fresh-oo-gallery__lightbox-nav fresh-oo-gallery__lightbox-nav--next" data-gallery-lightbox-next aria-label="Nächstes Bild">›</button><?php endif; ?>
</dialog>
<?php endif; ?>
</div>
<?php
}
}