<?php
/**
* Internal module: Field Registry + Elementor helpers.
* Loaded by onOffice Elementor Bridge.
*/
defined('ABSPATH') || exit;
final class FRESH_OnOffice_Field_Registry {
const CPT = 'fresh_immobilie';
private static array $fields = [
'oo_objekttitel' => ['Objekttitel','string'],
'oo_objektbeschreibung' => ['Objektbeschreibung','string'],
'oo_lage' => ['Lage','string'],
'oo_ausstatt_beschr' => ['Ausstattung','string'],
'oo_sonstige_angaben' => ['Sonstige Angaben','string'],
'oo_objektart' => ['Objektart','string'],
'oo_objekttyp' => ['Objekttyp','string'],
'oo_nutzungsart' => ['Nutzungsart','string'],
'oo_vermarktungsart' => ['Vermarktungsart','string'],
'oo_ort' => ['Ort','string'],
'oo_plz' => ['PLZ','string'],
'oo_strasse' => ['Straße','string'],
'oo_hausnummer' => ['Hausnummer','string'],
'oo_land' => ['Land','string'],
'oo_wohnflaeche' => ['Wohnfläche','number'],
'oo_nutzflaeche' => ['Nutzfläche','number'],
'oo_grundstuecksflaeche' => ['Grundstücksfläche','number'],
'oo_anzahl_zimmer' => ['Zimmer','number'],
'oo_anzahl_schlafzimmer' => ['Schlafzimmer','number'],
'oo_anzahl_badezimmer' => ['Badezimmer','number'],
'oo_anzahl_balkone' => ['Balkone','number'],
'oo_anzahl_terrassen' => ['Terrassen','number'],
'oo_etagenzahl' => ['Etagen','number'],
'oo_baujahr' => ['Baujahr','number'],
'oo_zustand' => ['Zustand','string'],
'oo_waehrung' => ['Währung','string'],
'oo_kaufpreis' => ['Kaufpreis','number'],
'oo_kaltmiete' => ['Kaltmiete','number'],
'oo_warmmiete' => ['Warmmiete','number'],
'oo_hausgeld' => ['Hausgeld','number'],
'oo_aussen_courtage' => ['Außen-Provision','string'],
'oo_provisionsfrei' => ['Provisionsfrei','boolean'],
'oo_energieausweistyp' => ['Energieausweistyp','string'],
'oo_endenergiebedarf' => ['Endenergiebedarf','number'],
'oo_endenergieverbrauch' => ['Endenergieverbrauch','number'],
'oo_energyclass' => ['Energieeffizienzklasse','string'],
'oo_baujahr_laut_energieausweis' => ['Baujahr lt. Energieausweis','number'],
'oo_heizungsart' => ['Heizungsart','string'],
'oo_befeuerung' => ['Befeuerung','string'],
'oo_fahrstuhl' => ['Fahrstuhl','boolean'],
'oo_balkon' => ['Balkon','boolean'],
'oo_terrasse' => ['Terrasse','boolean'],
'oo_keller' => ['Keller','boolean'],
'oo_gartennutzung' => ['Gartennutzung','boolean'],
'oo_stellplatzart' => ['Stellplatzart','string'],
'oo_veroeffentlichen' => ['Veröffentlichen','boolean'],
'oo_referenz' => ['Referenzobjekt','boolean'],
'oo_objektnr_extern' => ['Objektnummer','string'],
'oo_etagen_zahl' => ['Etagen','number'],
'oo_energieverbrauchskennwert' => ['Energieverbrauchskennwert','number'],
'oo_energieausweisbaujahr' => ['Baujahr lt. Energieausweis','number'],
'oo_energieausweis_gueltig_bis' => ['Energieausweis gültig bis','string'],
'oo_verfuegbar_ab' => ['Verfügbar ab','string'],
'oo_gallery_ids' => ['Galerie-IDs','array'],
'oo_gallery_csv' => ['Galerie-IDs CSV','string'],
];
public function __construct() {
add_action('init', [$this, 'register_meta'], 20);
add_action('add_meta_boxes', [$this, 'add_meta_box']);
add_action('elementor/dynamic_tags/register', [$this, 'register_elementor_tag']);
}
public static function field_definitions(): array {
$fields = self::$fields;
$schema = get_option('fresh_oo_bridge_field_schema', []);
if (is_array($schema)) {
foreach ($schema as $key => $props) {
$meta_key = 'oo_' . sanitize_key((string)$key);
if (isset($fields[$meta_key])) continue;
$props = is_array($props) ? $props : [];
$label = '';
foreach (['label', 'name', 'content'] as $candidate) {
if (!empty($props[$candidate]) && is_scalar($props[$candidate])) {
$label = wp_strip_all_tags((string)$props[$candidate]);
break;
}
}
if ($label === '') $label = (string)$key;
$remote_type = strtolower((string)($props['type'] ?? $props['realDataType'] ?? ''));
if (in_array($remote_type, ['float','double','integer','int','decimal','number'], true)) $type = 'number';
elseif (in_array($remote_type, ['boolean','bool'], true)) $type = 'boolean';
elseif (in_array($remote_type, ['multiselect','array'], true)) $type = 'array';
else $type = 'string';
$fields[$meta_key] = [$label, $type];
}
}
return $fields;
}
public function register_meta(): void {
foreach (self::field_definitions() as $key => [$label, $type]) {
$args = [
'single' => true,
'show_in_rest' => true,
'auth_callback' => static fn() => current_user_can('edit_posts'),
];
if ($type === 'number') {
$args['type'] = 'number';
} elseif ($type === 'boolean') {
$args['type'] = 'boolean';
} elseif ($type === 'array') {
$args['type'] = 'array';
$args['show_in_rest'] = ['schema' => ['type' => 'array', 'items' => ['type' => 'integer']]];
} else {
$args['type'] = 'string';
}
register_post_meta(self::CPT, $key, $args);
}
}
public function add_meta_box(): void {
add_meta_box('fresh_oo_fields', 'Immobiliendaten (onOffice)', [$this, 'render_meta_box'], self::CPT, 'normal', 'high');
}
public function render_meta_box(WP_Post $post): void {
$fields = self::field_definitions();
echo '<style>.fresh-oo-meta{background:#f7faf8;border:1px solid #dce5df;border-radius:12px;padding:14px}.fresh-oo-meta-head{display:flex;justify-content:space-between;gap:12px;align-items:center;margin-bottom:12px}.fresh-oo-meta-head strong{font-size:14px}.fresh-oo-meta-head span{font-size:12px;color:#66736d}.fresh-oo-fields{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}.fresh-oo-fields>div{background:#fff;padding:10px 12px;border:1px solid #e1e8e4;border-radius:9px;min-width:0}.fresh-oo-fields strong{display:block;font-size:11px;color:#66736d;margin-bottom:4px}.fresh-oo-fields span{display:block;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fresh-oo-fields code{display:block;margin-top:5px;font-size:10px;color:#7a8680;word-break:break-all}.fresh-oo-meta-note{font-size:12px;color:#66736d;margin:12px 2px 0}@media(max-width:1100px){.fresh-oo-fields{grid-template-columns:1fr 1fr}}@media(max-width:700px){.fresh-oo-fields{grid-template-columns:1fr}}</style>';
echo '<div class="fresh-oo-meta"><div class="fresh-oo-meta-head"><strong>Lokale onOffice-Daten</strong><span>'.count($fields).' bekannte Felder</span></div><div class="fresh-oo-fields">';
foreach ($fields as $key => [$label, $type]) {
if (in_array($key, ['oo_gallery_ids','oo_gallery_csv'], true)) continue;
$value = get_post_meta($post->ID, $key, true);
if ($value === '' || $value === null || $value === []) continue;
if (is_array($value)) $display = implode(', ', array_map('strval', $value));
elseif ($type === 'boolean') $display = filter_var($value, FILTER_VALIDATE_BOOLEAN) || (string)$value === '1' ? 'Ja' : 'Nein';
elseif ($type === 'number' && is_numeric($value)) {
$number = (float)$value;
$display = ((float)(int)$number === $number) ? (string)(int)$number : rtrim(rtrim(number_format($number, 2, ',', '.'), '0'), ',');
} else $display = (string)$value;
echo '<div title="'.esc_attr($display).'"><strong>'.esc_html($label).'</strong><span>'.esc_html($display).'</span><code>'.esc_html($key).'</code></div>';
}
echo '</div><p class="fresh-oo-meta-note">Diese Werte werden beim nächsten onOffice-Sync aktualisiert. In Elementor nutzt Du am bequemsten den Dynamic Tag <strong>onOffice Feld</strong>.</p></div>';
}
public function register_elementor_tag($dynamic_tags): void {
// This callback runs after Elementor has loaded its Dynamic Tag API.
// Load the concrete tag class only now so the plugin can never fatal merely
// because Elementor loads later or is temporarily deactivated.
if (!class_exists('Elementor\\Core\\DynamicTags\\Data_Tag') ||
!class_exists('Elementor\\Modules\\DynamicTags\\Module') ||
!class_exists('Elementor\\Controls_Manager')) {
return;
}
if (!class_exists('FRESH_OO_Elementor_Field_Tag', false)) {
require_once __DIR__ . '/elementor-field-tag.php';
}
if (class_exists('FRESH_OO_Elementor_Field_Tag', false)) {
$dynamic_tags->register(new FRESH_OO_Elementor_Field_Tag());
}
}
public function fields(): array {
return self::$fields;
}
}
new FRESH_OnOffice_Field_Registry();