/**
- ============= ZMAJ NEKRETNINE – GLOBAL FUNKCIJE =============
- Shortcode napredne pretrage + binder za query + ikonice + i18n + RU-fix
*/
/* ——————————————————————
i18n helper + registracija stringova za Polylang
——————————————————————- */
// i18n helper: SR = original, EN/RU = prevod ili fallback
if (!function_exists(‘zr_t’)) {
function zr_t($text, $fallback = ”) {
// ✅ Ako je aktivni jezik srpski → vrati original
if (function_exists('pll_current_language') && pll_current_language('slug') === 'hr') {
return $text;
}
// ✅ Ako postoji Polylang prevod → koristi ga
if (function_exists('pll__')) {
$translated = pll__($text);
if ($translated !== $text && $translated !== '') {
return $translated;
}
}
// ✅ Ako nema prevoda → koristi fallback
if ($fallback !== '') {
return $fallback;
}
// poslednja rezerva
return $text;
}
}
// 2) Registruj tekstove za prevođenje u Polylang (Languages → String translations)
add_action(‘init’, function () {
if (!function_exists(‘pll_register_string’)) { return; }
$group = ‘ZR Advanced Search’;
$strings = [
‘Prodaja / Iznajmljivanje’,
‘Vrsta nekretnine’,
‘Lokacija’,
‘Cena’,
‘Min’,
‘Max’,
‘Pretraži’,
‘Reset’,
‘Izaberi…’, // napomena: ovo je UNICODE elipsa (…)
‘— %s (ceo grad)’,
‘Detalji’,
‘Nema rezultata.’, // <= NOVO
];
foreach ($strings as $s) {
pll_register_string($s, $s, $group);
}
});
/* ——————————————————————
Polylang pomoćni argument za get_terms
——————————————————————- */
if (!function_exists(‘zr_get_lang_arg’)) {
function zr_get_lang_arg() {
if (function_exists(‘pll_current_language’)) {
return [‘lang’ => pll_current_language(‘slug’)];
}
return [];
}
}
/* ——————————————————————
UI: select bez hijerarhije (akcija, tip)
——————————————————————- */
if (!function_exists(‘zr_render_taxonomy_select_flat’)) {
function zr_render_taxonomy_select_flat($args) {
$defaults = [
‘taxonomy’ => ”,
‘label’ => ”,
‘name’ => ”,
‘id’ => ”,
‘placeholder’ => zr_t(‘Izaberi…’, ‘Select…’),
‘allow_empty’ => true,
‘class’ => ‘zr-select’,
];
$args = wp_parse_args($args, $defaults);
if (empty($args[‘taxonomy’]) || empty($args[‘name’]) || empty($args[‘id’])) return ”;
$term_args = array_merge([
'taxonomy' => $args['taxonomy'],
'hide_empty' => false,
'orderby' => 'name',
'order' => 'ASC',
], zr_get_lang_arg());
$terms = get_terms($term_args);
$current = isset($_GET[$args['name']]) ? sanitize_text_field(wp_unslash($_GET[$args['name']])) : '';
ob_start(); ?>
<div class="zr-field zr-field-<?php echo esc_attr($args['taxonomy']); ?>">
<?php if ($args['label']): ?>
<label for="<?php echo esc_attr($args['id']); ?>"><?php echo esc_html($args['label']); ?></label>
<?php endif; ?>
<select id="<?php echo esc_attr($args['id']); ?>" name="<?php echo esc_attr($args['name']); ?>" class="<?php echo esc_attr($args['class']); ?>">
<?php if ($args['allow_empty']): ?>
<option value=""><?php echo esc_html($args['placeholder']); ?></option>
<?php endif; ?>
<?php if (!is_wp_error($terms) && $terms): foreach ($terms as $t): ?>
<option value="<?php echo esc_attr($t->slug); ?>" <?php selected($current, $t->slug); ?>>
<?php echo esc_html($t->name); ?>
</option>
<?php endforeach; endif; ?>
</select>
</div>
<?php
return ob_get_clean();
}
}
/* ——————————————————————
UI: Lokacija (grad/opština) hijerarhijski sa optgroup
——————————————————————- */
if (!function_exists(‘zr_render_taxonomy_select_city_hier’)) {
function zr_render_taxonomy_select_city_hier($args) {
$defaults = [
‘taxonomy’ => ‘property_city’,
‘label’ => zr_t(‘Lokacija’, ‘Location’),
‘name’ => ‘property_city’,
‘id’ => ‘zr_prop_city’,
‘placeholder’ => zr_t(‘Izaberi…’, ‘Select…’),
‘allow_empty’ => true,
‘class’ => ‘zr-select’,
];
$args = wp_parse_args($args, $defaults);
$current = isset($_GET[$args['name']]) ? sanitize_text_field(wp_unslash($_GET[$args['name']])) : '';
$lang_part = zr_get_lang_arg();
$parents = get_terms(array_merge([
'taxonomy' => $args['taxonomy'],
'hide_empty' => false,
'parent' => 0,
'orderby' => 'name',
'order' => 'ASC',
], $lang_part));
ob_start(); ?>
<div class="zr-field zr-field-<?php echo esc_attr($args['taxonomy']); ?>">
<?php if ($args['label']): ?>
<label for="<?php echo esc_attr($args['id']); ?>"><?php echo esc_html($args['label']); ?></label>
<?php endif; ?>
<select id="<?php echo esc_attr($args['id']); ?>" name="<?php echo esc_attr($args['name']); ?>" class="<?php echo esc_attr($args['class']); ?>">
<?php if ($args['allow_empty']): ?>
<option value=""><?php echo esc_html($args['placeholder']); ?></option>
<?php endif; ?>
<?php if (!is_wp_error($parents) && $parents): foreach ($parents as $parent): ?>
<?php
$children = get_terms(array_merge([
'taxonomy' => $args['taxonomy'],
'hide_empty' => false,
'parent' => $parent->term_id,
'orderby' => 'name',
'order' => 'ASC',
], $lang_part));
?>
<?php if (empty($children)): ?>
<option value="<?php echo esc_attr($parent->slug); ?>" <?php selected($current, $parent->slug); ?>>
<?php echo esc_html($parent->name); ?>
</option>
<?php else: ?>
<optgroup label="<?php echo esc_attr($parent->name); ?>">
<option value="<?php echo esc_attr($parent->slug); ?>" <?php selected($current, $parent->slug); ?>>
<?php echo esc_html( sprintf( zr_t('— %s (ceo grad)', '— %s (entire city)'), $parent->name ) ); ?>
</option>
<?php foreach ($children as $child): ?>
<option value="<?php echo esc_attr($child->slug); ?>" <?php selected($current, $child->slug); ?>>
<?php echo esc_html('— ' . $child->name); ?>
</option>
<?php endforeach; ?>
</optgroup>
<?php endif; ?>
<?php endforeach; endif; ?>
</select>
</div>
<?php
return ob_get_clean();
}
}
/* ——————————————————————
SHORTCODE:
——————————————————————- */
if (!function_exists(‘zr_advanced_search_shortcode’)) {
function zr_advanced_search_shortcode() {
// šaljemo uvek na arhivu gde imamo naš template
$action_url = get_post_type_archive_link(‘estate_property’);
$v_pmin = isset($_GET['price_min']) ? sanitize_text_field(wp_unslash($_GET['price_min'])) : '';
$v_pmax = isset($_GET['price_max']) ? sanitize_text_field(wp_unslash($_GET['price_max'])) : '';
ob_start(); ?>
<form class="zr-advanced-search" method="get" action="<?php echo esc_url($action_url); ?>">
<input type="hidden" name="post_type" value="estate_property" />
<input type="hidden" name="zr_as" value="1" />
<?php
// 1) Prodaja / Iznajmljivanje
echo zr_render_taxonomy_select_flat([
'taxonomy' => 'property_action_category',
'label' => zr_t('Prodaja / Iznajmljivanje', 'Sale / Rent'),
'name' => 'property_action_category',
'id' => 'zr_prop_action',
'placeholder' => zr_t('Izaberi…', 'Select…'),
]);
// 2) Vrsta nekretnine
echo zr_render_taxonomy_select_flat([
'taxonomy' => 'property_category',
'label' => zr_t('Vrsta nekretnine', 'Property Type'),
'name' => 'property_category',
'id' => 'zr_prop_category',
'placeholder' => zr_t('Izaberi…', 'Select…'),
]);
// 3) Lokacija — hijerarhijski
echo zr_render_taxonomy_select_city_hier([
'taxonomy' => 'property_city',
'label' => zr_t('Lokacija', 'Location'),
'name' => 'property_city',
'id' => 'zr_prop_city',
'placeholder' => zr_t('Izaberi…', 'Select…'),
]);
?>
<!-- 4) Cena -->
<div class="zr-field zr-field-price">
<label><?php echo esc_html( zr_t('Cena', 'Price') ); ?></label>
<div class="zr-price-wrap">
<input type="text" inputmode="numeric" pattern="[0-9]*" name="price_min" id="zr_price_min"
value="<?php echo esc_attr($v_pmin); ?>"
placeholder="<?php echo esc_attr( zr_t('Min', 'Min') ); ?>" class="zr-input" />
<span class="zr-price-sep">–</span>
<input type="text" inputmode="numeric" pattern="[0-9]*" name="price_max" id="zr_price_max"
value="<?php echo esc_attr($v_pmax); ?>"
placeholder="<?php echo esc_attr( zr_t('Max', 'Max') ); ?>" class="zr-input" />
</div>
</div>
<div class="zr-actions">
<button type="submit" class="zr-btn zr-btn-primary"><?php echo esc_html( zr_t('Pretraži', 'Search') ); ?></button>
<button type="button" class="zr-btn zr-btn-reset" id="zr_reset_btn"><?php echo esc_html( zr_t('Reset', 'Reset') ); ?></button>
</div>
</form>
<style>
:root{ --zr-brand:#bf9b5f; --zr-brand-fore:#fff; --zr-border:#e2e2e8; }
.zr-advanced-search{
display:grid; gap:12px;
grid-template-columns: repeat(4, minmax(180px,1fr));
align-items:end;
}
@media (max-width: 900px){ .zr-advanced-search{ grid-template-columns: repeat(2, minmax(160px,1fr)); } }
@media (max-width: 640px){ .zr-advanced-search{ grid-template-columns: 1fr; } }
.zr-field label{ display:block; font-weight:600; font-size:13px; margin-bottom:6px; color:#222; }
.zr-select, .zr-input, .zr-btn{
width:100%; padding:10px 12px; border-radius:10px; border:1px solid var(--zr-border); background:#fff; min-height:42px;
}
.zr-field-price .zr-price-wrap{ display:flex; align-items:center; gap:8px; }
.zr-field-price .zr-price-sep{ padding:0 2px; opacity:.65; }
.zr-actions{ grid-column: 1 / -1; display:flex; gap:10px; }
.zr-btn{ cursor:pointer; font-weight:700; }
.zr-btn-primary{ background:var(--zr-brand); color:var(--zr-brand-fore); border-color:var(--zr-brand); }
.zr-btn-primary:hover{ filter:brightness(.95); }
.zr-btn-reset{ background:#fff; color:var(--zr-brand); border-color:var(--zr-brand); }
.zr-btn-reset:hover{ background:#fff8f0; }
.zr-select optgroup{ font-weight:700; color:#111; }
.zr-select optgroup option{ font-weight:400; }
</style>
<script>
(function(){
var btn = document.getElementById('zr_reset_btn');
if(!btn) return;
btn.addEventListener('click', function(){
window.location.href = "<?php echo esc_js($action_url); ?>";
});
})();
</script>
<?php
return ob_get_clean();
}
add_shortcode(‘zr_advanced_search’, ‘zr_advanced_search_shortcode’);
}
/* ——————————————————————
Clean price helper
——————————————————————- */
if (!function_exists(‘zr_clean_price’)) {
function zr_clean_price($val) {
$val = str_replace([‘.’, ‘,’], ”, (string)$val);
return (” === $val) ? ” : (string)absint($val);
}
}
/* ===========================================================
- ZR BINDER — primeni filtere na glavni upit (robustan za RU)
- – radi sa term_id, slug ili imenom (i duplo enkodiranim RU slugovima)
- – podržava price_min / price_max preko više meta ključeva
- – forsira aktivni jezik (Polylang)
- =========================================================== */
if (!function_exists(‘zr_bind_property_filters’)) {
function zr_bind_property_filters(\WP_Query $q) {
if (is_admin() || !$q->is_main_query()) return; // važi samo kad smo na našoj arhivi / listingu
$is_estate = (isset($_GET[‘post_type’]) && $_GET[‘post_type’] === ‘estate_property’) || isset($_GET[‘zr_as’]);
if (!$is_estate) return; $q->set(‘post_type’, ‘estate_property’); // — helper: bezbedno čišćenje cene (fallback ako nema globalne funkcije) —
$clean_price = function($val) {
$val = (string)$val;
$val = str_replace([‘.’, ‘,’,’ ‘], ”, $val);
return ($val === ”) ? ” : (string)absint($val);
}; // — helper: agresivno dekodiranje i mapiranje na term_id —
$resolve_term_clause = function(string $taxonomy, string $raw) {
// 1) agresivno dekodiranje (skidaj %25 → % → UTF-8 više puta)
$val = trim($raw);
for ($i = 0; $i < 5; $i++) {
$dec = rawurldecode($val);
if ($dec === $val) break;
$val = $dec;
}
$val = str_replace(‘+’, ‘ ‘, $val);
$val = trim($val); // 2) ako je broj → term_id
if ($val !== ” && ctype_digit($val)) {
return [
‘taxonomy’ => $taxonomy,
‘field’ => ‘term_id’,
‘terms’ => [ (int)$val ],
];
} // 3) probaj po slug-u
$t = get_term_by(‘slug’, $val, $taxonomy);
if ($t && !is_wp_error($t)) {
return [
‘taxonomy’ => $taxonomy,
‘field’ => ‘term_id’,
‘terms’ => [ (int)$t->term_id ],
];
} // 4) probaj po imenu (tačno poklapanje)
$t = get_term_by(‘name’, $val, $taxonomy);
if ($t && !is_wp_error($t)) {
return [
‘taxonomy’ => $taxonomy,
‘field’ => ‘term_id’,
‘terms’ => [ (int)$t->term_id ],
];
} // 5) tolerantno poređenje (case-insensitive) kroz sve termine aktivnog jezika
$terms = get_terms([
‘taxonomy’ => $taxonomy,
‘hide_empty’ => false,
‘lang’ => function_exists(‘pll_current_language’) ? pll_current_language(‘slug’) : ”,
]);
if (!is_wp_error($terms) && $terms) {
$needle = function_exists(‘mb_strtolower’) ? mb_strtolower($val, ‘UTF-8’) : strtolower($val);
foreach ($terms as $cand) {
$cand_slug = function_exists(‘mb_strtolower’) ? mb_strtolower($cand->slug, ‘UTF-8’) : strtolower($cand->slug);
$cand_name = function_exists(‘mb_strtolower’) ? mb_strtolower($cand->name, ‘UTF-8’) : strtolower($cand->name);
if ($cand_slug === $needle || $cand_name === $needle) {
return [
‘taxonomy’ => $taxonomy,
‘field’ => ‘term_id’,
‘terms’ => [ (int)$cand->term_id ],
];
}
}
} // 6) poslednja rezerva — ipak vrati slug (ako ga tema negde specijalno obrađuje)
return [
‘taxonomy’ => $taxonomy,
‘field’ => ‘slug’,
‘terms’ => [ $val ],
];
}; // — taksonomije koje pratimo iz forme —
$tax_query = [];
$taxes = [‘property_action_category’,’property_category’,’property_city’]; foreach ($taxes as $tax) {
if (!empty($_GET[$tax])) {
$raw = sanitize_text_field( wp_unslash($_GET[$tax]) );
$tax_query[] = $resolve_term_clause($tax, $raw);
}
} if ($tax_query) {
if (count($tax_query) > 1) {
$tax_query = array_merge([‘relation’ => ‘AND’], $tax_query);
}
$q->set(‘tax_query’, $tax_query);
} // — jezik (Polylang) —
if (function_exists(‘pll_current_language’)) {
$q->set(‘lang’, pll_current_language(‘slug’));
} // — cena (min / max) —
$price_min = isset($_GET[‘price_min’]) ? $clean_price($_GET[‘price_min’]) : ”;
$price_max = isset($_GET[‘price_max’]) ? $clean_price($_GET[‘price_max’]) : ”; if ($price_min !== ” || $price_max !== ”) {
$price_keys = apply_filters(‘zr_property_price_keys’, [‘property_price’,’price’,’estate_price’,’_price’]);
$meta_or = [‘relation’ => ‘OR’]; foreach ($price_keys as $k) {
$clause = [‘key’ => $k, ‘type’ => ‘NUMERIC’];
if ($price_min !== ” && $price_max !== ”) {
$clause[‘value’] = [ (int)$price_min, (int)$price_max ];
$clause[‘compare’] = ‘BETWEEN’;
} elseif ($price_min !== ”) {
$clause[‘value’] = (int)$price_min;
$clause[‘compare’] = ‘>=’;
} else {
$clause[‘value’] = (int)$price_max;
$clause[‘compare’] = ‘<=’;
}
$meta_or[] = $clause;
} $q->set(‘meta_query’, [ $meta_or ]);
}
}
add_action(‘pre_get_posts’, ‘zr_bind_property_filters’);
}
/**
- ZR — preusmeri taxonomy property_category + property_action_category + property_city
- na našu arhivu sa našim filterom
*/
add_action(‘template_redirect’, function () {
if ( is_admin() ) return; if ( is_tax([‘property_category’,’property_action_category’,’property_city’]) ) {$tax_obj = get_queried_object(); if (!$tax_obj || empty($tax_obj->taxonomy) || empty($tax_obj->slug)) return; // gradimo naš URL sa GET parametrima $url = add_query_arg([ 'post_type' => 'estate_property', 'zr_as' => '1', $tax_obj->taxonomy => $tax_obj->slug, ], get_post_type_archive_link('estate_property')); wp_safe_redirect($url, 302); exit;}
});
/* ===========================================================
- ZR QUERY NORMALIZER — skini dupli encoding (%25) i očisti GET
- – radi pre bidera; popravlja RU URL-e tipa %25d0%25…
- =========================================================== */
add_action(‘init’, function () {
if (is_admin()) return; $keys = [‘property_action_category’,’property_category’,’property_city’]; foreach ($keys as $k) {
if (!isset($_GET[$k])) continue; $raw = $_GET[$k]; // 1) skini slasheve koje WP ume da doda
if (is_string($raw)) {
$val = wp_unslash($raw);
} else {
// ako bi ikad stigao array (ne bi trebalo), preskoči
continue;
} // 2) agresivno dekodiranje: više puta rawurldecode (skida %25 → % → utf-8)
for ($i = 0; $i < 5; $i++) {
$dec = rawurldecode($val);
if ($dec === $val) break;
$val = $dec;
} // 3) plus → space
$val = str_replace(‘+’, ‘ ‘, $val); // 4) trim i sanitizacija (ostavi UTF-8 slova)
$val = trim( wp_strip_all_tags( $val ) ); // 5) upiši nazad u superglobal da binder dobije čisto
$_GET[$k] = $val;
}
}, 5);
/* ——————————————————————
GLOBALNE IKONICE (bed/bath/garage/area) + layout detalja
(rooms rešavamo posebnim inline SVG blokom ispod, da ne zavisi od media library)
——————————————————————- */
add_action(‘wp_head’, function () {
$icons = [
// rooms namerno ne koristimo ovde (biće inline SVG ispod)
‘bed’ => ‘https://zmaj-nekretnine.com/wp-content/uploads/2023/05/bed-1-5c727d-1-4-2-3-1.svg’,
‘bath’ => ‘https://zmaj-nekretnine.com/wp-content/uploads/2023/05/bath2-1-5C727D-4-2-3-1.svg’,
‘garage’ => ‘https://zmaj-nekretnine.com/wp-content/uploads/2023/05/garage.svg’,
‘area’ => ‘https://zmaj-nekretnine.com/wp-content/uploads/2023/05/area-1.svg’,
];
?>
‘); ?> ‘Sobe’, ‘Комната’ => ‘Sobe’, ‘Спальни’ => ‘Spavaće sobe’, ‘Спальня’ => ‘Spavaće sobe’, ‘Ванные комнаты’ => ‘Kupatila’, ‘Ванная комната’ => ‘Kupatila’, ‘Санузлы’ => ‘Kupatila’, ‘Гаражи’ => ‘Garaže’, ‘Гараж’ => ‘Garaže’, ‘Площадь’ => ‘Površina’, ‘м²’ => ‘m²’, ]; $ru_to_en = [ ‘Комнаты’ => ‘Rooms’, ‘Комната’ => ‘Rooms’, ‘Спальни’ => ‘Bedrooms’, ‘Спальня’ => ‘Bedrooms’, ‘Ванные комнаты’ => ‘Bathrooms’, ‘Ванная комната’ => ‘Bathrooms’, ‘Санузлы’ => ‘Bathrooms’, ‘Гаражи’ => ‘Garages’, ‘Гараж’ => ‘Garages’, ‘Площадь’ => ‘Area’, ‘м²’ => ‘m²’, ]; if ($lang === ‘hr’) { $html = strtr($html, $ru_to_hr); } elseif ($lang === ‘en’) { $html = strtr($html, $ru_to_en); } return $html; } add_action(‘template_redirect’, function () { if ( is_admin() ) return; // Ako postoji prevod aktivnog oglasa na aktivnom jeziku – preusmeri na njega if ( function_exists(‘pll_current_language’) && function_exists(‘pll_get_post’) && is_singular(‘estate_property’) ) { $current_lang = pll_current_language(‘slug’); $post_id = get_queried_object_id(); if ($post_id) { $target_id = pll_get_post($post_id, $current_lang); if ( $target_id && (int)$target_id !== (int)$post_id ) { wp_safe_redirect( get_permalink($target_id), 302 ); exit; } } } // RU→HR/EN zamena u letu za single if ( is_singular(‘estate_property’) ) { ob_start(‘zr_replace_labels_in_html’); } }, 9); /* —————————————————————— (Opcionalno) Ako znaš tačan meta ključ cene: ——————————————————————- */ /* add_filter(‘zr_property_price_keys’, function($keys){ return [‘property_price’]; // prilagodi nazivu meta ključa tvoje teme }); */ // === FORCE TRANSLATE “Detalji” NA LISTING KARTICAMA (archive/tax query) === function zr_archive_replace_labels_in_html($html){ if (!function_exists(‘pll_current_language’)) return $html; $lang = pll_current_language(‘slug’); // hvata više varijanti koje tema zna da ubaci $sr_variants = [ ‘Detalji’,’DETALJI’,’Detaljnije’,’DETALJNIJE’,’Vidi detalje’,’VIDI DETALJE’ ]; if ($lang === ‘en’) { $map = array_fill_keys($sr_variants, ‘Details’); return strtr($html, $map); } if ($lang === ‘ru’) { $map = array_fill_keys($sr_variants, ‘Подробнее’); return strtr($html, $map); } return $html; } add_action(‘template_redirect’, function () { if ( is_admin() ) return; // primeni na sve listing stranice za estate_property: $is_estate_listing = is_post_type_archive(‘estate_property’) || is_tax([‘property_action_category’,’property_category’,’property_city’]) || ( isset($_GET[‘zr_as’]) && !is_singular(‘estate_property’) ); if ( $is_estate_listing ) { ob_start(‘zr_archive_replace_labels_in_html’); } }, 11); //
';
echo "DEBUG zr_property_list\n\nARGS:\n"; print_r($a);
echo "\nTerm map:\n"; print_r($debug_info);
echo "\nWP_Query args:\n"; print_r($qargs);
echo "\nFound posts: ".$q->found_posts."\n";
echo "
“; } if ($q->have_posts()): ?>
have_posts()): $q->the_post(); $pid = get_the_ID(); $perma = get_permalink($pid); $price = get_post_meta($pid, ‘property_price’, true); if ($price===”) { $price = get_post_meta($pid, ‘price’, true); } $price = $price!==” ? number_format_i18n((float)$price, 0).’ €’ : ”; $get_meta = function($keys){ foreach ((array)$keys as $k) { $v = get_post_meta(get_the_ID(), $k, true); if ($v!==” && $v!==null) return $v; } return ”; }; $rooms = $get_meta([‘property_rooms’,’rooms’,’estate_rooms’,’prop_rooms’,’room_no’,’wpestate_rooms’,’property_no_of_rooms’,’_rooms’,’no_of_rooms’,’no_rooms’,’plan_rooms’]); $bedrooms = $get_meta([‘property_bedrooms’,’bedrooms’,’estate_bedrooms’,’prop_bedrooms’,’_bedrooms’]); $baths = $get_meta([‘property_bathrooms’,’bathrooms’,’estate_bathrooms’,’prop_bathrooms’,’_bathrooms’,’sanitary’]); $garages = $get_meta([‘property_garage’,’garages’,’garage’,’estate_garage’,’_garage’]); $area = $get_meta([‘property_size’,’property_area’,’estate_size’,’_area’,’_size’,’size’]); if ($area && is_numeric($area)) { $area = intval($area).’ m²’; } ?> itemscope itemtype=”https://schema.org/Place”>
‘async’,’loading’=>’lazy’]); } ?>
‘names’]); echo esc_html( implode(‘, ‘, $city_terms ?: []) ); ?>
$q->max_num_pages,’current’=>$paged]); ?>
<style>
.zr-grid{ display:grid; gap:16px; grid-template-columns:repeat(4,minmax(0,1fr)); }
@media (max-width:1100px){ .zr-grid{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
@media (max-width:800px){ .zr-grid{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
@media (max-width:560px){ .zr-grid{ grid-template-columns:1fr; } }
.zr-btn.zr-btn-primary{ background:#bf9b5f; color:#fff; border:1px solid #bf9b5f; padding:10px 14px; border-radius:10px; font-weight:700; display:inline-block; }
.zr-btn.zr-btn-primary:hover{ filter:brightness(.95); }
</style>
<?php
else:
echo ‘
‘.esc_html( zr_t(‘Nema rezultata.’,’No results.’) ).”;
endif;
wp_reset_postdata();
return ob_get_clean();
});
// Stil za ZR kartice (veća slika, elegantniji card, manje dugme)
add_action(‘wp_head’, function(){ ?>
<?php });
// ZR: “Nema rezultata.” hard patch — zameni po jeziku, bez obzira odakle tekst dolazi
add_action(‘template_redirect’, function () {
if (is_admin()) return;
// startuj output buffer i zameni u letu
ob_start(function ($html) {
if (!function_exists(‘pll_current_language’)) return $html;
$lang = pll_current_language('slug');
// šta tražimo
$needles = [
'Nema rezultata.',
'Nema rezultata', // bez tačke (neke teme ovako)
];
if ($lang === 'en') {
$repls = [
'No results.',
'No results',
];
return str_replace($needles, $repls, $html);
}
if ($lang === 'ru') {
$repls = [
'Нет результатов.',
'Нет результатов',
];
return str_replace($needles, $repls, $html);
}
// ostali jezici (sr/hr) ostaju isti
return $html;
});
}, 8);
/* ===========================================================
- ZR HARD SAFE MODE — stop redirect loops for our listing
- – no canonical redirects whenever our filter GETs are present
- – NO taxonomy -> archive redirects (we disable them for now)
- =========================================================== */
/* 1) Helper: da li je ovo naš listing zahtev? */
function zr_is_zr_listing_request() {
return (
(isset($_GET[‘zr_as’]) && $_GET[‘zr_as’] == ‘1’) ||
isset($_GET[‘property_action_category’]) ||
isset($_GET[‘property_category’]) ||
isset($_GET[‘property_city’])
);
}
/* 2) Isključi canonical redirekcije čim vidimo naše GET parametre */
add_filter(‘redirect_canonical’, function ($redirect, $requested) {
if ( zr_is_zr_listing_request() ) {
return false;
}
return $redirect;
}, 1000, 2);
/* 3) Dodatno: ukloni core canonical u template_redirect za svaki slučaj + SEO canonical */
add_action(‘template_redirect’, function () {
if ( zr_is_zr_listing_request() ) {
// core canonical
remove_action(‘template_redirect’, ‘redirect_canonical’);
// Yoast
if (has_filter(‘wpseo_canonical’)) {
add_filter(‘wpseo_canonical’, ‘__return_false’, 99);
}
// RankMath
if (has_filter(‘rank_math/frontend/canonical’)) {
add_filter(‘rank_math/frontend/canonical’, ‘__return_empty_string’, 99);
}
}
}, 0);
/* 4) (Namerno) NE radimo više taxonomy -> archive preusmerenje ovde.
- Pusti taxonomy URL-ove da budu kakvi jesu – korisnike usmeravaj iz MENIJA / LINKOVA na našu /property/ arhivu sa GET parametrima.
*/