<?php
/** Shared helpers for FRESH onOffice Elementor widgets. */
defined('ABSPATH') || exit;
if (!class_exists('FRESH_OO_Widget_Base') && class_exists('\\Elementor\\Widget_Base')) {
abstract class FRESH_OO_Widget_Base extends \Elementor\Widget_Base {
public function get_categories(): array { return ['fresh-onoffice']; }
public function get_style_depends(): array { return ['fresh-oo-toolkit']; }
protected function current_post_id(): int {
$id = (int)get_the_ID();
if (!$id && !empty($_GET['post'])) $id = (int)$_GET['post'];
return $id;
}
protected function field_definitions(): array {
return class_exists('FRESH_OnOffice_Field_Registry') ? FRESH_OnOffice_Field_Registry::field_definitions() : [];
}
protected function field_options(bool $include_empty = false): array {
$options = $include_empty ? ['' => '— Feld wählen —'] : [];
foreach ($this->field_definitions() as $key => $def) $options[$key] = ($def[0] ?? $key) . ' · ' . $key;
return $options;
}
protected function meta(string $key, ?int $post_id = null) {
if ($key === '') return '';
$post_id = $post_id ?: $this->current_post_id();
return $post_id ? get_post_meta($post_id, $key, true) : '';
}
protected function has_value($value): bool {
if (is_array($value)) return count(array_filter($value, static fn($v) => $v !== '' && $v !== null)) > 0;
return !($value === '' || $value === null || $value === false);
}
protected function is_truthy($value): bool {
if (is_array($value)) return !empty($value);
$v = strtolower(trim((string)$value));
return in_array($v, ['1','true','yes','ja','on','y'], true);
}
protected function normalize_array($value): array {
if (is_string($value) && is_serialized($value)) $value = maybe_unserialize($value);
if ($value === '' || $value === null || $value === false) return [];
if (!is_array($value)) return [trim((string)$value)];
$flat = [];
$walk = static function ($item) use (&$walk, &$flat): void {
if (is_array($item)) {
foreach ($item as $child) $walk($child);
return;
}
if ($item === '' || $item === null || $item === false) return;
if (is_scalar($item)) {
$text = trim((string)$item);
if ($text !== '') $flat[] = $text;
}
};
$walk($value);
return array_values($flat);
}
protected function format_number($value, int $decimals = 2, bool $group = true): string {
if (!is_numeric($value)) return trim((string)$value);
$n = (float)$value;
$decimals = max(0, $decimals);
// Whole numbers must never lose significant trailing zeroes.
// Example: 160.00 => 160, 680.00 => 680, 299000.00 => 299.000.
if (abs($n - round($n)) < 0.0000001 || $decimals === 0) {
return $group ? number_format_i18n($n, 0) : number_format($n, 0, ',', '');
}
$formatted = $group
? number_format_i18n($n, $decimals)
: number_format($n, $decimals, ',', '');
// Trim zeroes only from the fractional part, never from the integer part.
$formatted = preg_replace('/([,.]\d*?[1-9])0+$/', '$1', $formatted);
$formatted = preg_replace('/[,.]0+$/', '', $formatted);
return $formatted;
}
protected function field_semantics(string $key): string {
$k = strtolower($key);
if (preg_match('/(^|_)baujahr($|_)/', $k) || preg_match('/energieausweisbaujahr|baujahr_laut/', $k)) return 'year';
if (preg_match('/(_gueltig_bis|gueltig_bis|datum|date|verfuegbar_ab)$/', $k)) return 'date';
if (preg_match('/preis|miete|hausgeld|pacht|kaution|courtage_betrag|nebenkosten/', $k)) return 'price';
if (preg_match('/flaeche/', $k)) return 'area';
if (preg_match('/energieverbrauch|energiebedarf|endenergie/', $k)) return 'energy';
if (preg_match('/anzahl_|etagen_zahl|etagenzahl|stellplaetze|zimmer/', $k)) return 'count';
$defs = $this->field_definitions();
$type = $defs[$key][1] ?? '';
if ($type === 'boolean') return 'boolean';
if ($type === 'array') return 'array';
if ($type === 'number') return 'number';
return 'text';
}
protected function zero_is_empty(string $key): bool {
$semantic = $this->field_semantics($key);
return in_array($semantic, ['price','area','energy','count'], true) && !preg_match('/provisionsfrei|referenz|veroeffentlichen/', strtolower($key));
}
protected function meaningful_value($value, string $key = '', bool $hide_zero = true): bool {
if (!$this->has_value($value) && $value !== 0 && $value !== '0') return false;
if ($hide_zero && $key !== '' && $this->zero_is_empty($key) && is_numeric($value) && (float)$value == 0.0) return false;
return true;
}
protected function format_date($value): string {
$raw = trim((string)$value);
if ($raw === '' || $raw === '0000-00-00') return '';
$ts = strtotime($raw);
return $ts ? wp_date('d.m.Y', $ts) : $raw;
}
protected function pretty_value($value, string $key = '', string $format = 'auto', string $custom_suffix = ''): string {
if (!$this->has_value($value) && $value !== '0' && $value !== 0) return '';
$semantic = $this->field_semantics($key);
if ($format === 'auto') $format = $this->inferred_format($key);
if ($format === 'boolean') return $this->is_truthy($value) ? 'Ja' : 'Nein';
if ($format === 'price') return $this->format_number($value) . ' €';
if ($format === 'area') return $this->format_number($value) . ' m²';
if ($format === 'energy') return $this->format_number($value, 1) . ' kWh/(m²·a)';
if ($format === 'year') return is_numeric($value) ? $this->format_number($value, 0, false) : trim((string)$value);
if ($format === 'date') return $this->format_date($value);
if ($format === 'integer') return $this->format_number($value, 0);
if ($format === 'number') return $this->format_number($value);
if ($format === 'array' || $semantic === 'array' || is_array($value) || (is_string($value) && is_serialized($value))) {
$parts = [];
foreach ($this->normalize_array($value) as $part) {
$parts[] = $this->pretty_value($part, '', 'text');
}
return implode(', ', array_values(array_unique(array_filter($parts, 'strlen'))));
}
$text = trim((string)$value);
$map = [
'kauf'=>'Kauf','miete'=>'Miete','pacht'=>'Pacht','erbpacht'=>'Erbpacht','wohnen'=>'Wohnen','gewerbe'=>'Gewerbe','anlage'=>'Anlage',
'haus'=>'Haus','wohnung'=>'Wohnung','grundstueck'=>'Grundstück','einfamilienhaus'=>'Einfamilienhaus','mehrfamilienhaus'=>'Mehrfamilienhaus',
'etage'=>'Etagenwohnung','maisonette'=>'Maisonette','penthouse'=>'Penthouse','dachgeschoss'=>'Dachgeschosswohnung','erdgeschoss'=>'Erdgeschosswohnung',
'aktive_vermarktung'=>'Aktive Vermarktung','reserviert'=>'Reserviert','verkauft'=>'Verkauft','vermietet'=>'Vermietet',
'gas'=>'Gas','oel'=>'Öl','öl'=>'Öl','fernwaerme'=>'Fernwärme','fussboden'=>'Fußbodenheizung','personen'=>'Personenaufzug',
'luftwp'=>'Luft-Wasser-Wärmepumpe','waermepumpe'=>'Wärmepumpe','erdwaerme'=>'Erdwärme','pellet'=>'Pelletheizung','holz'=>'Holz','strom'=>'Strom',
'fluessiggas'=>'Flüssiggas','solar'=>'Solarenergie','block'=>'Blockheizkraftwerk','alternative'=>'Alternative Energie',
'ja'=>'Ja','nein'=>'Nein','true'=>'Ja','false'=>'Nein',
'gepflegt'=>'Gepflegt','modernisiert'=>'Modernisiert','neuwertig'=>'Neuwertig','renoviert'=>'Renoviert','sanierungsbeduerftig'=>'Sanierungsbedürftig',
];
$lower = strtolower($text);
$text = $map[$lower] ?? str_replace('_', ' ', $text);
if ($custom_suffix !== '') $text .= $custom_suffix;
return $text;
}
protected function inferred_format(string $key): string {
return match ($this->field_semantics($key)) {
'price' => 'price', 'area' => 'area', 'energy' => 'energy', 'year' => 'year', 'date' => 'date',
'count' => 'number', 'boolean' => 'boolean', 'array' => 'array', 'number' => 'number', default => 'text',
};
}
protected function marketing_type(): string { return strtolower(trim((string)$this->meta('oo_vermarktungsart'))); }
protected function object_type(): string { return strtolower(trim((string)$this->meta('oo_objektart'))); }
protected function is_rental(): bool { $m=$this->marketing_type(); return str_contains($m,'miet') || str_contains($m,'pacht'); }
protected function editor_empty(string $message): void {
if (class_exists('\\Elementor\\Plugin') && \Elementor\Plugin::$instance->editor->is_edit_mode()) echo '<div class="elementor-alert elementor-alert-info">'.esc_html($message).'</div>';
}
protected function render_selected_icon(array $icon, string $class = ''): void {
if (empty($icon['value'])) return;
echo '<span class="'.esc_attr($class).'" aria-hidden="true">';
\Elementor\Icons_Manager::render_icon($icon, ['aria-hidden'=>'true']);
echo '</span>';
}
protected function add_common_card_style_controls(string $prefix, string $selector): void {
$this->add_control($prefix.'_bg', ['label'=>'Hintergrund','type'=>\Elementor\Controls_Manager::COLOR,'selectors'=>[$selector=>'background-color: {{VALUE}};']]);
$this->add_group_control(\Elementor\Group_Control_Border::get_type(), ['name'=>$prefix.'_border','selector'=>$selector]);
$this->add_responsive_control($prefix.'_radius', ['label'=>'Eckenradius','type'=>\Elementor\Controls_Manager::DIMENSIONS,'size_units'=>['px','%'],'selectors'=>[$selector=>'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};']]);
$this->add_responsive_control($prefix.'_padding', ['label'=>'Innenabstand','type'=>\Elementor\Controls_Manager::DIMENSIONS,'size_units'=>['px','em'],'selectors'=>[$selector=>'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};']]);
$this->add_group_control(\Elementor\Group_Control_Box_Shadow::get_type(), ['name'=>$prefix.'_shadow','selector'=>$selector]);
}
}
}