- Fix template variable replacement in guide pages by removing {{}} brackets
- Escape code blocks in guide markdown to prevent template processing
- Completely rewrite guide documentation with comprehensive CMS features
- Add bilingual guide support (English/Dutch) with detailed examples
- Enhance CodePressCMS core with improved guide page handling
- Update template system with better layout and footer components
- Improve language files with additional translations
- Update configuration with enhanced theme and language settings
Resolves issue where guide pages were showing replaced template variables
instead of displaying them as documentation examples.
144 lines
6.6 KiB
PHP
144 lines
6.6 KiB
PHP
<?php
|
|
|
|
/**
|
|
* SimpleTemplate - Lightweight template rendering engine
|
|
*
|
|
* Features:
|
|
* - Variable replacement with {{variable}} syntax
|
|
* - Unescaped HTML content with {{{variable}}} syntax
|
|
* - Conditional blocks with {{#variable}}...{{/variable}}
|
|
* - Negative conditionals with {{^variable}}...{{/variable}}
|
|
* - Partial includes with {{>partial}}
|
|
* - Simple string-based rendering (no external dependencies)
|
|
*/
|
|
class SimpleTemplate {
|
|
private $data;
|
|
|
|
/**
|
|
* Render template with data
|
|
*
|
|
* @param string $template Template content with placeholders
|
|
* @param array $data Data to populate template
|
|
* @return string Rendered template
|
|
*/
|
|
public static function render($template, $data) {
|
|
$instance = new self();
|
|
$instance->data = $data;
|
|
return $instance->renderTemplate($template);
|
|
}
|
|
|
|
/**
|
|
* Process template and replace placeholders
|
|
*
|
|
* @param string $template Template content
|
|
* @return string Processed template
|
|
*/
|
|
private function renderTemplate($template) {
|
|
// Handle partial includes first ({{>partial}})
|
|
$template = preg_replace_callback('/{{>([^}]+)}}/', [$this, 'replacePartial'], $template);
|
|
|
|
// Handle equal conditionals first
|
|
$template = preg_replace_callback('/{{#equal\s+(\w+)\s+["\']([^"\']+)["\']}}(.*?){{\/equal}}/s', function($matches) {
|
|
$key = $matches[1];
|
|
$expectedValue = $matches[2];
|
|
$content = $matches[3];
|
|
|
|
$actualValue = $this->data[$key] ?? '';
|
|
return ($actualValue === $expectedValue) ? $content : '';
|
|
}, $template);
|
|
|
|
// Handle conditional blocks
|
|
foreach ($this->data as $key => $value) {
|
|
if (is_array($value)) {
|
|
// Handle {{#key}}...{{/key}} blocks for arrays (iteration)
|
|
$pattern = '/{{#' . preg_quote($key, '/') . '}}(.*?){{\/' . preg_quote($key, '/') . '}}/s';
|
|
if (preg_match($pattern, $template, $matches)) {
|
|
$blockTemplate = $matches[1];
|
|
$replacement = '';
|
|
|
|
foreach ($value as $item) {
|
|
if (is_array($item)) {
|
|
// Create a temporary template instance for nested data
|
|
$tempTemplate = new self();
|
|
$tempTemplate->data = $item;
|
|
$replacement .= $tempTemplate->renderTemplate($blockTemplate);
|
|
} else {
|
|
// Simple array, replace {{.}} with the item value
|
|
$itemBlock = str_replace('{{.}}', htmlspecialchars($item, ENT_QUOTES, 'UTF-8'), $blockTemplate);
|
|
$replacement .= $itemBlock;
|
|
}
|
|
}
|
|
|
|
$template = preg_replace($pattern, $replacement, $template);
|
|
}
|
|
|
|
// Handle {{^key}}...{{/key}} blocks (negative condition for empty arrays)
|
|
$pattern = '/{{\^' . preg_quote($key, '/') . '}}(.*?){{\/' . preg_quote($key, '/') . '}}/s';
|
|
if (empty($value)) {
|
|
// Show the content if array is empty
|
|
if (preg_match($pattern, $template, $matches)) {
|
|
$template = preg_replace($pattern, $matches[1], $template);
|
|
}
|
|
} else {
|
|
// Remove the content if array is not empty
|
|
$template = preg_replace($pattern, '', $template);
|
|
}
|
|
} elseif ((is_string($value) && !empty($value)) || (is_bool($value) && $value === true)) {
|
|
// Handle {{#key}}...{{/key}} blocks for truthy values
|
|
$pattern = '/{{#' . preg_quote($key, '/') . '}}(.*?){{\/' . preg_quote($key, '/') . '}}/s';
|
|
if (preg_match($pattern, $template, $matches)) {
|
|
$replacement = $matches[1];
|
|
$template = preg_replace($pattern, $replacement, $template);
|
|
}
|
|
|
|
// Handle {{^key}}...{{/key}} blocks (negative condition)
|
|
$pattern = '/{{\^' . preg_quote($key, '/') . '}}(.*?){{\/' . preg_quote($key, '/') . '}}/s';
|
|
$template = preg_replace($pattern, '', $template);
|
|
} else {
|
|
// Handle empty blocks
|
|
$pattern = '/{{#' . preg_quote($key, '/') . '}}.*?{{\/' . preg_quote($key, '/') . '}}/s';
|
|
$template = preg_replace($pattern, '', $template);
|
|
|
|
// Handle {{^key}}...{{/key}} blocks (show when empty)
|
|
$pattern = '/{{\^' . preg_quote($key, '/') . '}}(.*?){{\/' . preg_quote($key, '/') . '}}/s';
|
|
if (preg_match_all($pattern, $template, $matches)) {
|
|
foreach ($matches[1] as $match) {
|
|
$template = preg_replace('/{{\^' . preg_quote($key, '/') . '}}.*?{{\/' . preg_quote($key, '/') . '}}/s', $match, $template, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle variable replacements
|
|
foreach ($this->data as $key => $value) {
|
|
// Handle triple braces for unescaped HTML content
|
|
if (strpos($template, '{{{' . $key . '}}}') !== false) {
|
|
$template = str_replace('{{{' . $key . '}}}', is_string($value) ? $value : print_r($value, true), $template);
|
|
}
|
|
// Handle double braces for escaped content
|
|
elseif (strpos($template, '{{' . $key . '}}') !== false) {
|
|
if (is_string($value)) {
|
|
$template = str_replace('{{' . $key . '}}', htmlspecialchars($value, ENT_QUOTES, 'UTF-8'), $template);
|
|
} elseif (is_array($value)) {
|
|
// For arrays, convert to JSON string for display
|
|
$template = str_replace('{{' . $key . '}}', htmlspecialchars(json_encode($value), ENT_QUOTES, 'UTF-8'), $template);
|
|
} else {
|
|
// Convert other types to string
|
|
$template = str_replace('{{' . $key . '}}', htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'), $template);
|
|
}
|
|
}
|
|
}
|
|
return $template;
|
|
}
|
|
|
|
/**
|
|
* Replace partial includes with data values
|
|
*
|
|
* @param array $matches Regex matches from preg_replace_callback
|
|
* @return string Replacement content
|
|
*/
|
|
private function replacePartial($matches) {
|
|
$partialName = $matches[1];
|
|
return isset($this->data[$partialName]) ? $this->data[$partialName] : $matches[0];
|
|
}
|
|
} |