]+class="[^"]*bonus-title[^"]*"[^>]*>(.*?)[^>]+>~is', $source, $match);
if (!empty($match[1])) {
return trim(html_entity_decode(strip_tags($match[1])));
}
$normalized = preg_replace('~
~i', "\n", $source);
$parts = preg_split('/\r\n|\r|\n/', html_entity_decode(strip_tags($normalized))) ?: [];
$parts = array_values(array_filter(array_map(static fn($item) => trim($item), $parts), static fn($item) => $item !== ''));
return $parts[0] ?? trim(html_entity_decode(strip_tags($source)));
}
}
if (!function_exists('mcp_extract_feature_items')) {
function mcp_extract_feature_items($html) {
$source = (string)$html;
if (trim($source) === '') return [];
if (class_exists('DOMDocument')) {
$dom = new DOMDocument();
@$dom->loadHTML('
' . $source . '
', LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//*[contains(concat(" ", normalize-space(@class), " "), " bonus-features ")]');
$items = [];
if ($nodes !== false && $nodes->length > 0) {
$parents = [];
foreach ($nodes as $node) {
if ($node->parentNode instanceof DOMElement) {
$parents[spl_object_id($node->parentNode)] = $node->parentNode;
}
}
foreach ($parents as $parent) {
$current = '';
foreach ($parent->childNodes as $child) {
$isMarker = false;
if ($child instanceof DOMElement) {
$classes = ' ' . preg_replace('/\s+/u', ' ', trim((string)$child->getAttribute('class'))) . ' ';
$isMarker = strpos($classes, ' bonus-features ') !== false;
}
if ($isMarker) {
$current = trim(preg_replace('/\s+/u', ' ', $current));
if ($current !== '') {
$items[] = html_entity_decode($current);
}
$current = '';
continue;
}
$text = html_entity_decode($child->textContent ?? '');
if ($text !== '') {
$current .= ' ' . $text;
}
}
$current = trim(preg_replace('/\s+/u', ' ', $current));
if ($current !== '') {
$items[] = html_entity_decode($current);
}
}
$items = array_values(array_unique(array_filter(array_map(static fn($item) => trim($item), $items), static fn($item) => $item !== '')));
if (!empty($items)) {
return $items;
}
}
}
preg_match_all('~]*>(.*?)~is', $source, $listMatches);
if (!empty($listMatches[1])) {
return array_values(array_filter(array_map(static fn($item) => trim(html_entity_decode(strip_tags($item))), $listMatches[1]), static fn($item) => $item !== ''));
}
$normalized = preg_replace('~
~i', "\n", $source);
$parts = preg_split('/\r\n|\r|\n/', html_entity_decode(strip_tags($normalized))) ?: [];
$parts = array_values(array_filter(array_map(static fn($item) => trim($item), $parts), static fn($item) => $item !== ''));
$hasBonusTitle = preg_match('~class="[^"]*bonus-title[^"]*"~i', $source) === 1;
if ($hasBonusTitle && count($parts) > 1) {
array_shift($parts);
}
return $parts;
}
}
if (!function_exists('mcp_render_table_features')) {
function mcp_render_table_features($featuresHtml, $fallback = '') {
$html = trim((string)$featuresHtml);
if ($html !== '') {
// If Strapi already provides rich HTML for features (div/span markup),
// keep it to preserve site-specific CSS expectations.
if (stripos($html, '<') !== false) {
$html = preg_replace('~