<?php
|
namespace JVBase\meta;
|
|
if (!defined('ABSPATH')) {
|
exit; // Exit if accessed directly
|
}
|
class MetaRenderer
|
{
|
|
/**
|
* Rendering can be overridden in individual plugin/theme setups by creating a function
|
* A) for the named field via camelCased, no underscore function: BASE.Render{$name}Field($value, $config);
|
* B) for the entire field type via camelCased, no underscore function: BASE.Render{$type}Field($value, $config);
|
* @param string $name
|
* @param mixed $value
|
* @param array $config
|
*
|
* @return mixed
|
*/
|
public function render(string $name, mixed $value, array $config, bool $return = false):mixed
|
{
|
$type = array_map('ucfirst', explode('_', $config['type']));
|
$type = implode('', $type);
|
$method = 'render' . $type . 'Field';
|
$methodFunction = str_replace('_', '', BASE).ucfirst($method);
|
$nameFunction = str_replace('_', '', BASE).'Render'.ucfirst($name).'Field';
|
$output = '';
|
if (function_exists($nameFunction)) {
|
$output = call_user_func($nameFunction, $value, $config);
|
} elseif (function_exists($methodFunction)) {
|
$output = call_user_func($methodFunction, $value, $config);
|
} elseif (method_exists($this, $method)) {
|
$output = $this->$method($name, $value, $config);
|
}
|
|
if ($return) {
|
return $output;
|
}
|
|
echo $output;
|
return true;
|
}
|
|
protected function renderTextField(string $name, string $value, array $field):string
|
{
|
return apply_filters('the_content', $value);
|
}
|
|
protected function renderTextareaField(string $name, string $value, array $field):string
|
{
|
return $this->renderTextField($name, $value, $field);
|
}
|
protected function renderNumberField(string $name, string $value, array $field):string
|
{
|
return $this->renderTextField($name, $value, $field);
|
}
|
protected function renderEmailField(string $name, string $value, array $field):string
|
{
|
$link = 'mailto:'.$value.'?subject='.rawurlencode('Contact from edmonton.ink').'&body='.rawurlencode('Hey,
|
I found you on edmonton.ink, and I wanted to reach out!');
|
|
return '<a href="'.$link.'" title="Send an Email">'.jvbIcon('envelope').'<span>Email</span></a>';
|
|
}
|
protected function renderUrlField(string $name, string $value, array $field):string
|
{
|
// jvbDump($value, 'URL Field:');
|
// jvbDump($field);
|
return '';
|
}
|
protected function renderImageField(string $name, string $value, array $field):string
|
{
|
if (!is_numeric($value)) {
|
return '';
|
}
|
return jvbFormatImage($value, 'tiny', 'medium');
|
}
|
protected function renderGalleryField(string $name, array|null|false $value, array $field):string
|
{
|
// jvbDump($value, 'Gallery Field:');
|
// jvbDump($field);
|
return '';
|
}
|
protected function renderTaxonomyField($name, $value, $field):string
|
{
|
if ($value === '') {
|
return '';
|
}
|
$value = explode(',', $value);
|
$terms = get_terms([
|
'taxonomy' => jvbCheckBase($field['taxonomy']),
|
'terms_in' => $value
|
]);
|
return jvbRenderTermList($terms, $field['label']);
|
}
|
|
protected function renderTagListField(string $name, array|bool $value, array $field): string
|
{
|
if (empty($value) || !is_array($value)) {
|
return '';
|
}
|
|
if (!isset($field['fields']) || !is_array($field['fields'])) {
|
return '';
|
}
|
|
$tag_format = $field['tag_format'] ?? 'first_field';
|
$output = '<div class="tag-list-display">';
|
|
if (!empty($field['label']) && ($field['show_label'] ?? false)) {
|
$output .= '<h4 class="tag-list-label">' . esc_html($field['label']) . '</h4>';
|
}
|
|
$output .= '<div class="tag-list-items">';
|
|
foreach ($value as $item) {
|
if (!is_array($item) || empty($item)) {
|
continue;
|
}
|
|
$tag_text = $this->getTagDisplayText($item, $tag_format);
|
$output .= '<span class="tag-list-item">' . esc_html($tag_text) . '</span>';
|
}
|
|
$output .= '</div></div>';
|
|
return $output;
|
}
|
|
/**
|
* Get display text for a tag based on format
|
*/
|
protected function getTagDisplayText(array $data, string $format): string
|
{
|
$values = array_filter(array_values($data));
|
|
if (empty($values)) {
|
return '';
|
}
|
|
switch ($format) {
|
case 'first_field':
|
return $values[0];
|
|
case 'all_fields':
|
return implode(', ', $values);
|
|
default:
|
// Template format like "{name} ({email})"
|
if (strpos($format, '{') !== false) {
|
$text = $format;
|
foreach ($data as $key => $value) {
|
$text = str_replace('{' . $key . '}', $value, $text);
|
}
|
return $text;
|
}
|
|
// Use specific field
|
return $data[$format] ?? $values[0];
|
}
|
}
|
|
protected function renderRepeaterField($name, $value, $field):string
|
{
|
// jvbDump($value, 'Repeater Field:');
|
// jvbDump($field);
|
return '';
|
}
|
|
protected function renderGroupField(string $name, array|bool $value, array $field):string
|
{
|
if (empty($value) || !$value || !isset($field['fields'])) {
|
return '';
|
}
|
|
$output = '<div class="group-field ' . esc_attr($name) . '">';
|
|
// Add field label if configured to show
|
if (isset($field['show_label']) && $field['show_label'] && !empty($field['label'])) {
|
$output .= '<h3 class="group-label">' . esc_html($field['label']) . '</h3>';
|
}
|
|
$output .= '<div class="group-content col">';
|
|
foreach ($field['fields'] as $subfield_name => $subfield_config) {
|
if (!isset($value[$subfield_name]) || empty($value[$subfield_name])) {
|
continue;
|
}
|
|
$subfield_value = $value[$subfield_name];
|
|
// Check if subfield has conditions that prevent display
|
if (isset($subfield_config['condition'])) {
|
$condition = $subfield_config['condition'];
|
$condition_field = $condition['field'];
|
$condition_value = $value[$condition_field] ?? '';
|
$operator = $condition['operator'] ?? '==';
|
$expected_value = $condition['value'];
|
|
$condition_met = false;
|
switch ($operator) {
|
case '==':
|
$condition_met = $condition_value == $expected_value;
|
break;
|
case '!=':
|
$condition_met = $condition_value != $expected_value;
|
break;
|
case 'in':
|
$condition_met = is_array($expected_value) && in_array($condition_value, $expected_value);
|
break;
|
case 'not_in':
|
$condition_met = is_array($expected_value) && !in_array($condition_value, $expected_value);
|
break;
|
}
|
|
if (!$condition_met) {
|
continue;
|
}
|
}
|
|
// Render the subfield
|
$subfield_output = $this->render($subfield_name, $subfield_value, $subfield_config, true);
|
|
if (!empty($subfield_output)) {
|
$output .= '<div class="group-item ' . esc_attr($subfield_name) . '">';
|
|
// Add label if configured
|
if (isset($subfield_config['show_label']) && $subfield_config['show_label'] && !empty($subfield_config['label'])) {
|
$output .= '<span class="subfield-label">' . esc_html($subfield_config['label']) . ':</span> ';
|
}
|
|
$output .= $subfield_output;
|
$output .= '</div>';
|
}
|
}
|
|
$output .= '</div></div>';
|
|
return $output;
|
}
|
protected function renderLocationField(string $name, array|bool $value, array $field): string
|
{
|
if (!$value) {
|
return '';
|
}
|
// Early return if no location data
|
if (empty($value) || empty($value['lat']) || empty($value['lng'])) {
|
return '';
|
}
|
|
$googleMaps = JVB()->connect('maps');
|
if (!$googleMaps->isSetUp()) {
|
error_log('Google Maps is not set up');
|
// Fallback to text-only display
|
return $this->renderLocationFallback($value, $field);
|
}
|
|
error_log('Google Maps: '.print_r($googleMaps, true));
|
$lat = (float)$value['lat'];
|
$lng = (float)$value['lng'];
|
$address = $googleMaps->formatAddress($value, 'full');
|
|
// Map display options (can be configured via field config)
|
$map_options = array_merge([
|
'height' => '200px',
|
'zoom' => 14,
|
'show_marker' => true,
|
'show_info_window' => true,
|
'interactive' => true
|
], $field['map_options'] ?? []);
|
|
// Link options
|
$link_options = array_merge([
|
'show_icons' => true,
|
'style' => 'buttons',
|
'include' => ['google', 'apple']
|
], $field['link_options'] ?? []);
|
|
ob_start();
|
?>
|
<div class="jvb-location-display">
|
<?php
|
// Render the interactive map
|
echo $googleMaps->renderDisplayMap($value, $map_options);
|
?>
|
|
<div class="jvb-location-details">
|
<?php if (!empty($address)): ?>
|
<div class="jvb-location-address">
|
<?= jvbIcon('map-pin'); ?>
|
<span><?= esc_html($address); ?></span>
|
</div>
|
<?php endif; ?>
|
|
<?php
|
// Render map application links
|
echo $googleMaps->renderMapLinks($lat, $lng, $address, $link_options);
|
?>
|
</div>
|
</div>
|
|
<style>
|
.jvb-location-display {
|
margin: 1rem 0;
|
}
|
|
.jvb-location-map-display {
|
margin-bottom: 1rem;
|
border: 1px solid #e0e0e0;
|
}
|
|
.jvb-location-details {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 1rem;
|
align-items: center;
|
font-size: 0.95rem;
|
}
|
|
.jvb-location-address {
|
display: flex;
|
align-items: center;
|
color: #1B1B1B;
|
flex: 1;
|
min-width: 200px;
|
}
|
|
.jvb-location-address svg {
|
margin-right: 0.5rem;
|
color: #FF0080;
|
width: 18px;
|
height: 18px;
|
}
|
|
.jvb-map-links {
|
display: flex;
|
gap: 0.75rem;
|
}
|
|
.jvb-map-links.button-style .map-link {
|
display: inline-flex;
|
align-items: center;
|
padding: 0.4rem 0.75rem;
|
border-radius: 6px;
|
background-color: #1B1B1B;
|
color: #EFEFEF;
|
text-decoration: none;
|
transition: all 0.2s ease;
|
font-size: 0.9rem;
|
}
|
|
.jvb-map-links.button-style .map-link svg {
|
margin-right: 0.35rem;
|
width: 16px;
|
height: 16px;
|
}
|
|
.jvb-map-links.button-style .map-link:hover {
|
background-color: #FF0080;
|
transform: translateY(-1px);
|
}
|
|
.jvb-map-links.text-style .map-link {
|
color: #FF0080;
|
text-decoration: none;
|
font-weight: 500;
|
}
|
|
.jvb-map-links.text-style .map-link:hover {
|
text-decoration: underline;
|
}
|
|
.map-info-window {
|
padding: 8px 12px;
|
font-weight: 500;
|
color: #1B1B1B;
|
}
|
|
@media (max-width: 768px) {
|
.jvb-location-details {
|
flex-direction: column;
|
align-items: flex-start;
|
gap: 0.75rem;
|
}
|
|
.jvb-location-address {
|
min-width: auto;
|
}
|
}
|
</style>
|
<?php
|
|
return ob_get_clean();
|
}
|
|
protected function renderSetField(string $name, string $value, array $field):string
|
{
|
if ($value === '') {
|
return '';
|
}
|
$value = explode(',', $value);
|
|
$output = '<div class="set-field-display row">';
|
|
if (!empty($field['label']) && ($field['show_label'] ?? false)) {
|
$output .= '<span class="set-label">' . esc_html($field['label']) . ':</span> ';
|
}
|
|
$items = [];
|
foreach ($value as $key) {
|
if (isset($field['options'][$key])) {
|
$items[] = '<span class="set-item">' . esc_html($field['options'][$key]) . '</span>';
|
}
|
}
|
|
$separator = $field['separator'] ?? ', ';
|
$output .= implode($separator, $items);
|
$output .= '</div>';
|
|
return $output;
|
}
|
|
protected function renderCheckboxField(string $name, string $value, array $field):string
|
{
|
// Checkbox fields are essentially the same as set fields for display
|
return $this->renderSetField($name, $value, $field);
|
}
|
|
protected function renderRadioField(string $name, string $value, array $field):string
|
{
|
if (empty($value) || !isset($field['options'][$value])) {
|
return '';
|
}
|
|
$display_value = $field['options'][$value];
|
|
$output = '<div class="radio-field-display">';
|
|
if (!empty($field['label']) && ($field['show_label'] ?? false)) {
|
$output .= '<span class="radio-label">' . esc_html($field['label']) . ':</span> ';
|
}
|
|
$output .= '<span class="radio-value">' . esc_html($display_value) . '</span>';
|
$output .= '</div>';
|
|
return $output;
|
}
|
|
protected function renderSelectField(string $name, string $value, array $field):string
|
{
|
// Select fields display the same as radio fields
|
return $this->renderRadioField($name, $value, $field);
|
}
|
|
protected function renderTrueFalseField(string $name, bool $value, array $field):string
|
{
|
$display_text = $value ? ($field['true_text'] ?? 'Yes') : ($field['false_text'] ?? 'No');
|
$css_class = $value ? 'true-value' : 'false-value';
|
|
$output = '<div class="true-false-field-display">';
|
|
if (!empty($field['label']) && ($field['show_label'] ?? false)) {
|
$output .= '<span class="true-false-label">' . esc_html($field['label']) . ':</span> ';
|
}
|
|
$output .= '<span class="' . $css_class . '">' . esc_html($display_text) . '</span>';
|
$output .= '</div>';
|
|
return $output;
|
}
|
|
protected function renderTimeField(string $name, string $value, array $field):string
|
{
|
if (empty($value)) {
|
return '';
|
}
|
|
// Format time for display
|
$display_format = $field['display_format'] ?? 'g:i A'; // Default: 12-hour format with AM/PM
|
|
// Parse the time value
|
$timestamp = strtotime($value);
|
if ($timestamp === false) {
|
return '';
|
}
|
|
$formatted_time = date($display_format, $timestamp);
|
|
// Add icon if configured
|
$show_icon = $field['show_icon'] ?? true;
|
$icon_html = $show_icon ? jvbIcon('clock') : '';
|
|
return sprintf(
|
'<div class="time-field-display">%s<span class="time-value">%s</span></div>',
|
$icon_html,
|
esc_html($formatted_time)
|
);
|
}
|
|
protected function renderDatetimeField(string $name, string $value, array $field):string
|
{
|
if (empty($value)) {
|
return '';
|
}
|
|
// Parse datetime
|
$date = DateTime::createFromFormat('Y-m-d H:i:s', $value);
|
if (!$date) {
|
// Try alternative formats
|
$formats = ['Y-m-d\TH:i:s', 'Y-m-d\TH:i', 'Y-m-d H:i'];
|
foreach ($formats as $format) {
|
$date = DateTime::createFromFormat($format, $value);
|
if ($date) break;
|
}
|
}
|
|
if (!$date) {
|
return '';
|
}
|
|
// Format for display
|
$display_format = $field['display_format'] ?? 'F j, Y \a\t g:i A'; // Default: March 15, 2024 at 2:30 PM
|
$formatted_datetime = $date->format($display_format);
|
|
// Add icon if configured
|
$show_icon = $field['show_icon'] ?? true;
|
$icon_html = $show_icon ? jvbIcon('calendar') : '';
|
|
return sprintf(
|
'<div class="datetime-field-display">%s<span class="datetime-value">%s</span></div>',
|
$icon_html,
|
esc_html($formatted_datetime)
|
);
|
}
|
|
protected function renderDateField(string $name, string $value, array $field):string
|
{
|
if (empty($value)) {
|
return '';
|
}
|
|
$timestamp = strtotime($value);
|
if ($timestamp === false) {
|
return '';
|
}
|
|
// Format for display
|
$display_format = $field['display_format'] ?? 'F j, Y'; // Default: March 15, 2024
|
$formatted_date = date($display_format, $timestamp);
|
|
// Add icon if configured
|
$show_icon = $field['show_icon'] ?? true;
|
$icon_html = $show_icon ? jvbIcon('calendar') : '';
|
|
return sprintf(
|
'<div class="date-field-display">%s<span class="date-value">%s</span></div>',
|
$icon_html,
|
esc_html($formatted_date)
|
);
|
}
|
}
|