false,
'html' => '',
'managed_html' => '',
'error' => $message,
];
}
function samtyk_cmp_normalize_embed_identity(string $identity, string $source, array $categories): string
{
$normalized = strtolower(trim($identity));
$normalized = preg_replace('/[^a-z0-9_-]+/', '-', $normalized) ?: '';
$normalized = trim($normalized, '-_');
return $normalized !== ''
? $normalized
: substr(hash('sha256', $source . '|' . implode(',', $categories)), 0, 12);
}
function samtyk_cmp_is_allowed_embed_attribute(string $name, string $tag): bool
{
if (strpos($name, 'data-') === 0 || strpos($name, 'aria-') === 0) {
return true;
}
$attributes = [
'script' => ['src', 'type', 'async', 'defer', 'crossorigin', 'integrity', 'referrerpolicy', 'nomodule'],
'iframe' => ['src', 'width', 'height', 'loading', 'allow', 'allowfullscreen', 'frameborder', 'referrerpolicy', 'scrolling', 'name', 'sandbox'],
'a' => ['href', 'target', 'rel'],
'img' => ['src', 'srcset', 'sizes', 'width', 'height', 'loading', 'alt', 'crossorigin', 'referrerpolicy'],
'source' => ['src', 'srcset', 'sizes', 'type', 'media'],
'video' => ['src', 'poster', 'width', 'height', 'controls', 'autoplay', 'loop', 'muted', 'playsinline', 'preload', 'crossorigin'],
'audio' => ['src', 'controls', 'autoplay', 'loop', 'muted', 'preload', 'crossorigin'],
];
return in_array($name, ['id', 'class', 'title', 'role', 'style', 'tabindex', 'dir', 'lang'], true)
|| in_array($name, $attributes[$tag] ?? [], true);
}
function samtyk_cmp_sanitize_embed_url(string $url, bool $is_link = false): string
{
$url = trim($url);
if ($url === '' || preg_match('/[\x00-\x20\x7f\\\\]/', $url)) {
return '';
}
$protocols = $is_link ? ['http', 'https', 'mailto', 'tel'] : ['http', 'https'];
$scheme = strtolower((string) wp_parse_url($url, PHP_URL_SCHEME));
if ($scheme !== '' && !in_array($scheme, $protocols, true)) {
return '';
}
if ($scheme === '' && !preg_match('~^(?:/|\./|\.\./|\?|\#)~', $url)) {
// Preserve relative resource paths instead of esc_url_raw() adding a host/scheme.
$url = './' . $url;
}
return esc_url_raw($url, $protocols);
}
function samtyk_cmp_sanitize_embed_srcset(string $srcset): string
{
$candidates = [];
foreach (explode(',', $srcset) as $candidate) {
$parts = preg_split('/\s+/', trim($candidate));
$url = samtyk_cmp_sanitize_embed_url($parts[0] ?? '');
if ($url === '' || count($parts) > 2 || (isset($parts[1]) && !preg_match('/^(?:[1-9][0-9]*w|(?:[0-9]+(?:\.[0-9]+)?)x)$/D', $parts[1]))) {
return '';
}
$candidates[] = $url . (isset($parts[1]) ? ' ' . $parts[1] : '');
}
return implode(', ', $candidates);
}
/** Serialize validated elements with escaping appropriate to each HTML context. */
function samtyk_cmp_escape_embed_node(DOMNode $node): string
{
if ($node instanceof DOMText) {
return esc_html($node->nodeValue);
}
if (!$node instanceof DOMElement) {
return '';
}
$tag = strtolower($node->tagName);
$html = '<' . $tag;
foreach ($node->attributes as $attribute) {
$html .= ' ' . $attribute->name . '="' . esc_attr($attribute->value) . '"';
}
$html .= '>';
if (in_array($tag, ['img', 'source', 'br'], true)) {
return $html;
}
if ($tag === 'script') {
// Executable source is intentionally preserved. Only signed, explicitly approved
// snippets reach frontend rendering; HTML escaping here would corrupt JavaScript.
$html .= $node->textContent;
} else {
foreach ($node->childNodes as $child) {
$html .= samtyk_cmp_escape_embed_node($child);
}
}
return $html . '' . $tag . '>';
}
/** Emit validated nodes using WordPress' script API and late HTML-context escaping. */
function samtyk_cmp_print_embed_node(DOMNode $node): void
{
if ($node instanceof DOMText) {
echo esc_html($node->nodeValue);
return;
}
if (!$node instanceof DOMElement) {
return;
}
$tag = strtolower($node->tagName);
if ($tag === 'script') {
$attributes = [];
foreach ($node->attributes as $attribute) {
$attributes[$attribute->name] = $attribute->value;
}
wp_print_inline_script_tag($node->textContent, $attributes);
return;
}
echo '<' . esc_html($tag);
foreach ($node->attributes as $attribute) {
echo ' ' . esc_attr($attribute->name) . '="' . esc_attr($attribute->value) . '"';
}
echo '>';
if (in_array($tag, ['img', 'source', 'br'], true)) {
return;
}
foreach ($node->childNodes as $child) {
samtyk_cmp_print_embed_node($child);
}
echo '' . esc_html($tag) . '>';
}
function samtyk_cmp_convert_embed_snippet(string $source, array $categories, string $identity, bool $print = false): array
{
if (trim($source) === '') {
return samtyk_cmp_embed_conversion_error(__('Enter a script or embed code.', 'samtyk-cmp'));
}
if (strlen($source) > SAMTYK_CMP_SNIPPET_MAX_BYTES) {
return samtyk_cmp_embed_conversion_error(__('The code is larger than the allowed 100 KB.', 'samtyk-cmp'));
}
if (!samtyk_cmp_valid_snippet_categories($categories)) {
return samtyk_cmp_embed_conversion_error(__('Select valid consent categories.', 'samtyk-cmp'));
}
$categories = samtyk_cmp_normalize_snippet_categories($categories);
if (strpos($source, "\0") !== false || !preg_match('//u', $source)) {
return samtyk_cmp_embed_conversion_error(__('The code must contain valid UTF-8 text without null bytes.', 'samtyk-cmp'));
}
if (!class_exists('DOMDocument')) {
return samtyk_cmp_embed_conversion_error(__('The server cannot process HTML embeds.', 'samtyk-cmp'));
}
$previous_errors = libxml_use_internal_errors(true);
$document = new DOMDocument('1.0', 'UTF-8');
$wrapper_id = 'samtyk-cmp-parser-root';
$loaded = $document->loadHTML(
'
' . $source . '
',
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
);
libxml_clear_errors();
libxml_use_internal_errors($previous_errors);
$wrapper = $document->getElementById($wrapper_id);
if (!$loaded || !$wrapper instanceof DOMElement) {
return samtyk_cmp_embed_conversion_error(__('The code could not be parsed as HTML.', 'samtyk-cmp'));
}
$allowed_tags = array_fill_keys(samtyk_cmp_get_embed_allowed_tags(), true);
$elements = [];
foreach ($wrapper->getElementsByTagName('*') as $element) {
$elements[] = $element;
}
$category_value = implode(',', $categories);
$normalized_identity = samtyk_cmp_normalize_embed_identity($identity, $source, $categories);
$resource_index = 0;
foreach ($elements as $element) {
$tag_name = strtolower($element->tagName);
if (!isset($allowed_tags[$tag_name])) {
return samtyk_cmp_embed_conversion_error(
/* translators: %s: Unsupported HTML tag name. */
sprintf(__('The HTML tag <%s> is not supported.', 'samtyk-cmp'), $tag_name)
);
}
$attribute_names = [];
foreach ($element->attributes as $attribute) {
$attribute_names[] = strtolower($attribute->name);
}
foreach ($attribute_names as $attribute_name) {
if (!preg_match('/^[a-z][a-z0-9_.:-]*$/D', $attribute_name)) {
$element->removeAttribute($attribute_name);
continue;
}
if (strpos($attribute_name, 'data-samtyk-') === 0 || strpos($attribute_name, 'data-cookiepopup-') === 0) {
return samtyk_cmp_embed_conversion_error(__('The code contains reserved consent-manager attributes.', 'samtyk-cmp'));
}
if (strpos($attribute_name, 'on') === 0 || !samtyk_cmp_is_allowed_embed_attribute($attribute_name, $tag_name)) {
$element->removeAttribute($attribute_name);
}
}
foreach (['href', 'src', 'poster', 'data-src', 'data-poster', 'srcset', 'data-srcset'] as $url_attribute) {
if (!$element->hasAttribute($url_attribute)) {
continue;
}
$value = $element->getAttribute($url_attribute);
$clean = strpos($url_attribute, 'srcset') !== false
? samtyk_cmp_sanitize_embed_srcset($value)
: samtyk_cmp_sanitize_embed_url($value, $url_attribute === 'href');
if ($clean === '') {
return samtyk_cmp_embed_conversion_error(__('The code contains an unsupported or unsafe URL.', 'samtyk-cmp'));
}
$element->setAttribute($url_attribute, $clean);
}
if ($element->hasAttribute('style')) {
$style = function_exists('safecss_filter_attr')
? safecss_filter_attr($element->getAttribute('style'))
: '';
if ($style === '') {
$element->removeAttribute('style');
} else {
$element->setAttribute('style', $style);
}
}
if ($element->hasAttribute('href')) {
$href = samtyk_cmp_sanitize_embed_url($element->getAttribute('href'), true);
if ($href === '') {
$element->removeAttribute('href');
} else {
$element->setAttribute('href', $href);
}
}
$is_resource = in_array($tag_name, ['script', 'iframe', 'img', 'source', 'video', 'audio'], true);
if (!$is_resource || $categories === []) {
continue;
}
$resource_index++;
if ($element->hasAttribute('src')) {
$source_url = samtyk_cmp_sanitize_embed_url($element->getAttribute('src'));
$element->removeAttribute('src');
if ($source_url !== '') {
$element->setAttribute('data-src', $source_url);
}
}
if (in_array($tag_name, ['img', 'source'], true) && $element->hasAttribute('srcset')) {
$element->setAttribute('data-srcset', $element->getAttribute('srcset'));
$element->removeAttribute('srcset');
}
if ($tag_name === 'video' && $element->hasAttribute('poster')) {
$poster = samtyk_cmp_sanitize_embed_url($element->getAttribute('poster'));
$element->removeAttribute('poster');
if ($poster !== '') {
$element->setAttribute('data-poster', $poster);
}
}
if ($tag_name === 'script') {
$element->setAttribute('type', 'text/plain');
}
$element->setAttribute('data-cookiepopup-category', $category_value);
$element->setAttribute('data-cookiepopup-id', 'samtyk-' . $normalized_identity . '-' . $resource_index);
}
$converted = '';
foreach ($wrapper->childNodes as $child) {
$converted .= samtyk_cmp_escape_embed_node($child);
}
if (trim($converted) === '') {
return samtyk_cmp_embed_conversion_error(__('The code does not contain supported HTML.', 'samtyk-cmp'));
}
$template_id = 'samtyk-' . $normalized_identity;
if ($print) {
if ($categories !== []) {
echo '';
}
foreach ($wrapper->childNodes as $child) {
samtyk_cmp_print_embed_node($child);
}
if ($categories !== []) {
echo '';
}
}
return [
'success' => true,
'html' => $converted,
'managed_html' => $categories === [] ? $converted : '' . $converted . '',
'error' => '',
];
}
function samtyk_cmp_register_snippet_post_type(): void
{
register_post_type(SAMTYK_CMP_SNIPPET_POST_TYPE, [
'labels' => [
'name' => __('Scripts and embeds', 'samtyk-cmp'),
'singular_name' => __('Script or embed', 'samtyk-cmp'),
],
'public' => false,
'publicly_queryable' => false,
'show_ui' => false,
'show_in_menu' => false,
'show_in_rest' => false,
'exclude_from_search' => true,
'rewrite' => false,
'query_var' => false,
'supports' => ['title', 'editor'],
// All writes use our nonce-protected handlers, never the default post editor/XML-RPC.
'map_meta_cap' => false,
'capabilities' => array_merge(
array_fill_keys(['edit_post', 'edit_posts', 'edit_others_posts', 'edit_published_posts', 'edit_private_posts', 'publish_posts', 'create_posts', 'delete_post', 'delete_posts', 'delete_others_posts', 'delete_published_posts', 'delete_private_posts'], 'do_not_allow'),
['read_post' => 'manage_options', 'read_private_posts' => 'manage_options']
),
]);
}
function samtyk_cmp_get_valid_public_content_ids($content_ids): array
{
if (!is_array($content_ids)) {
return [];
}
$valid_ids = [];
foreach ($content_ids as $content_id) {
$content_id = (int) $content_id;
if ($content_id <= 0 || isset($valid_ids[$content_id])) {
continue;
}
$post_type = get_post_type($content_id);
$post_type_object = $post_type !== '' ? get_post_type_object($post_type) : null;
if (
$post_type === 'attachment'
|| !$post_type_object
|| empty($post_type_object->public)
|| get_post_status($content_id) !== 'publish'
) {
continue;
}
$valid_ids[$content_id] = $content_id;
}
return array_values($valid_ids);
}
function samtyk_cmp_get_snippet(int $post_id): ?array
{
$post = get_post($post_id);
if (!$post || $post->post_type !== SAMTYK_CMP_SNIPPET_POST_TYPE) {
return null;
}
$categories = samtyk_cmp_normalize_snippet_categories(get_post_meta($post_id, '_samtyk_categories', true));
$location = (string) get_post_meta($post_id, '_samtyk_location', true);
$visibility = (string) get_post_meta($post_id, '_samtyk_visibility', true);
$snippet = [
'id' => (int) $post->ID,
'name' => (string) $post->post_title,
'source' => (string) $post->post_content,
'generated_code' => '',
'categories' => $categories,
'location' => in_array($location, ['head', 'body_open', 'footer', 'shortcode'], true) ? $location : 'head',
'shortcode_id' => (string) get_post_meta($post_id, '_samtyk_shortcode_id', true),
'placeholder_enabled' => (bool) get_post_meta($post_id, '_samtyk_placeholder_enabled', true),
'placeholder_text' => (string) get_post_meta($post_id, '_samtyk_placeholder_text', true),
'placeholder_icon' => (string) get_post_meta($post_id, '_samtyk_placeholder_icon', true),
'active' => $post->post_status === 'publish',
'visibility' => $visibility === 'selected' ? 'selected' : 'all',
'content_ids' => samtyk_cmp_get_valid_public_content_ids(get_post_meta($post_id, '_samtyk_content_ids', true)),
'modified' => isset($post->post_modified) ? (string) $post->post_modified : '',
];
$approval = (string) get_post_meta($post_id, '_samtyk_code_approval', true);
$snippet['approved'] = $approval !== '' && hash_equals(samtyk_cmp_snippet_approval($snippet), $approval);
if ($snippet['approved'] && samtyk_cmp_valid_snippet_categories(get_post_meta($post_id, '_samtyk_categories', true))) {
$conversion = samtyk_cmp_convert_embed_snippet($snippet['source'], $categories, '');
if ($conversion['success']) {
$snippet['generated_code'] = $conversion['managed_html'];
}
}
return $snippet;
}
/** Bind approval to the site secret, post, source and execution/placement settings. */
function samtyk_cmp_snippet_approval(array $snippet): string
{
return wp_hash(wp_json_encode([
SAMTYK_CMP_SNIPPET_POLICY_VERSION,
get_current_blog_id(),
$snippet['id'], $snippet['source'], $snippet['categories'], $snippet['location'],
$snippet['shortcode_id'], $snippet['visibility'],
// Approval tracks configured targets, independent of later publication changes.
get_post_meta($snippet['id'], '_samtyk_content_ids', true),
]), 'auth');
}
/** Late validation and context-aware escaping for both shortcode and automatic output. */
function samtyk_cmp_escape_snippet_output(int $post_id): string
{
ob_start();
samtyk_cmp_print_snippet_output($post_id);
return (string) ob_get_clean();
}
function samtyk_cmp_print_snippet_output(int $post_id): void
{
$snippet = samtyk_cmp_get_snippet($post_id);
if ($snippet && $snippet['active'] && $snippet['generated_code'] !== '') {
samtyk_cmp_convert_embed_snippet($snippet['source'], $snippet['categories'], '', true);
}
}
function samtyk_cmp_invalidate_shortcode_index(): void
{
unset($GLOBALS['samtyk_cmp_shortcode_index']);
}
function samtyk_cmp_invalidate_shortcode_meta_index($meta_id, $post_id, $meta_key): void
{
if ($meta_key === '_samtyk_shortcode_id') {
samtyk_cmp_invalidate_shortcode_index();
}
}
function samtyk_cmp_find_shortcode_post_id(string $shortcode_id): int
{
// Request-local only: fetch and prime metadata once instead of querying postmeta for each shortcode.
if (!isset($GLOBALS['samtyk_cmp_shortcode_index'])) {
$index = [];
$post_ids = get_posts([
'post_type' => SAMTYK_CMP_SNIPPET_POST_TYPE,
'post_status' => ['publish', 'draft'],
'posts_per_page' => -1,
'fields' => 'ids',
'orderby' => 'ID',
'order' => 'ASC',
'no_found_rows' => true,
]);
update_meta_cache('post', $post_ids);
foreach ($post_ids as $post_id) {
$id = (string) get_post_meta((int) $post_id, '_samtyk_shortcode_id', true);
if ($id !== '' && !isset($index[$id])) {
$index[$id] = (int) $post_id;
}
}
$GLOBALS['samtyk_cmp_shortcode_index'] = $index;
}
return $GLOBALS['samtyk_cmp_shortcode_index'][$shortcode_id] ?? 0;
}
function samtyk_cmp_save_snippet(array $input, int $post_id = 0): array
{
if (!samtyk_cmp_can_manage_snippet_code()) {
return ['success' => false, 'post_id' => 0, 'error' => __('Managing executable code requires the unfiltered_html capability.', 'samtyk-cmp')];
}
if (!empty($input['source_error'])) {
return ['success' => false, 'post_id' => 0, 'error' => $input['source_error']];
}
if (!samtyk_cmp_valid_snippet_categories($input['categories'] ?? [])) {
return ['success' => false, 'post_id' => 0, 'error' => __('Select valid consent categories.', 'samtyk-cmp')];
}
$name = isset($input['name']) ? trim(sanitize_text_field($input['name'])) : '';
$source = isset($input['source']) && is_string($input['source']) ? $input['source'] : '';
$categories = samtyk_cmp_normalize_snippet_categories($input['categories'] ?? []);
$location = isset($input['location']) && in_array($input['location'], ['head', 'body_open', 'footer', 'shortcode'], true)
? $input['location']
: '';
$visibility = ($input['visibility'] ?? 'all') === 'selected' ? 'selected' : 'all';
$content_ids = samtyk_cmp_get_valid_public_content_ids($input['content_ids'] ?? []);
$shortcode_id = $post_id > 0 ? (string) get_post_meta($post_id, '_samtyk_shortcode_id', true) : '';
if ($shortcode_id === '') {
$shortcode_id = isset($input['shortcode_id']) && is_string($input['shortcode_id']) ? $input['shortcode_id'] : '';
if (!preg_match('/^[a-f0-9]{32}$/D', $shortcode_id)) {
$shortcode_id = bin2hex(random_bytes(16));
}
if (samtyk_cmp_find_shortcode_post_id($shortcode_id) > 0) {
return ['success' => false, 'post_id' => 0, 'error' => __('This shortcode ID is already in use. Open a new form and try again.', 'samtyk-cmp')];
}
}
if ($name === '') {
return ['success' => false, 'post_id' => 0, 'error' => __('Enter a name.', 'samtyk-cmp')];
}
if ($location === '') {
return ['success' => false, 'post_id' => 0, 'error' => __('Select a valid placement.', 'samtyk-cmp')];
}
if ($location !== 'shortcode' && $visibility === 'selected' && $content_ids === []) {
return ['success' => false, 'post_id' => 0, 'error' => __('Select at least one public page or item.', 'samtyk-cmp')];
}
$initial_conversion = samtyk_cmp_convert_embed_snippet($source, $categories, '');
if (!$initial_conversion['success']) {
return ['success' => false, 'post_id' => 0, 'error' => $initial_conversion['error']];
}
$post_data = [
'post_type' => SAMTYK_CMP_SNIPPET_POST_TYPE,
'post_status' => !empty($input['active']) ? 'publish' : 'draft',
'post_title' => $name,
'post_content' => function_exists('wp_slash') ? wp_slash($source) : $source,
];
if ($post_id > 0) {
$existing = get_post($post_id);
if (!$existing || $existing->post_type !== SAMTYK_CMP_SNIPPET_POST_TYPE) {
return ['success' => false, 'post_id' => 0, 'error' => __('The script or embed could not be found.', 'samtyk-cmp')];
}
// Revoke approval before changing source or any execution settings.
update_post_meta($post_id, '_samtyk_code_approval', '');
$post_data['ID'] = $post_id;
$saved_post_id = wp_update_post($post_data, true);
} else {
$saved_post_id = wp_insert_post($post_data, true);
}
if (is_wp_error($saved_post_id) || (int) $saved_post_id <= 0) {
return ['success' => false, 'post_id' => 0, 'error' => __('The script or embed could not be saved.', 'samtyk-cmp')];
}
$saved_post_id = (int) $saved_post_id;
// Do not approve a different value after WordPress filters or storage transformations.
if ((string) get_post($saved_post_id)->post_content !== $source) {
return ['success' => false, 'post_id' => 0, 'error' => __('WordPress changed the code while saving. Review it and save again.', 'samtyk-cmp')];
}
// Retained only for compatibility; frontend always regenerates from approved source.
update_post_meta($saved_post_id, '_samtyk_generated_code', wp_slash($initial_conversion['managed_html']));
update_post_meta($saved_post_id, '_samtyk_categories', $categories);
update_post_meta($saved_post_id, '_samtyk_location', $location);
update_post_meta($saved_post_id, '_samtyk_visibility', $visibility);
update_post_meta($saved_post_id, '_samtyk_content_ids', $content_ids);
update_post_meta($saved_post_id, '_samtyk_shortcode_id', $shortcode_id);
update_post_meta($saved_post_id, '_samtyk_placeholder_enabled', $categories !== [] && !empty($input['placeholder_enabled']));
$placeholder_text = isset($input['placeholder_text']) && is_string($input['placeholder_text'])
? sanitize_textarea_field($input['placeholder_text'])
: '';
if (!empty($input['placeholder_default']) || samtyk_cmp_is_default_placeholder_text($placeholder_text)) {
$placeholder_text = '';
}
update_post_meta($saved_post_id, '_samtyk_placeholder_text', wp_slash($placeholder_text));
$placeholder_icon = isset($input['placeholder_icon']) && in_array($input['placeholder_icon'], ['samtyk', 'lock', 'shield', 'video'], true)
? $input['placeholder_icon']
: '';
update_post_meta($saved_post_id, '_samtyk_placeholder_icon', $placeholder_icon);
$saved = samtyk_cmp_get_snippet($saved_post_id);
if (!$saved || $saved['categories'] !== $categories || $saved['location'] !== $location
|| $saved['visibility'] !== $visibility || $saved['content_ids'] !== $content_ids
|| $saved['shortcode_id'] !== $shortcode_id) {
return ['success' => false, 'post_id' => 0, 'error' => __('The script or embed could not be saved.', 'samtyk-cmp')];
}
update_post_meta($saved_post_id, '_samtyk_code_approval', samtyk_cmp_snippet_approval($saved));
return ['success' => true, 'post_id' => $saved_post_id, 'error' => ''];
}
function samtyk_cmp_snippet_matches_request(array $snippet): bool
{
if (($snippet['location'] ?? '') === 'shortcode') {
return true;
}
if (($snippet['visibility'] ?? 'all') !== 'selected') {
return true;
}
if (!is_singular()) {
return false;
}
$queried_id = (int) get_queried_object_id();
return $queried_id > 0
&& in_array($queried_id, samtyk_cmp_get_valid_public_content_ids($snippet['content_ids'] ?? []), true);
}
function samtyk_cmp_get_placeholder_icon(string $icon): string
{
if ($icon === 'samtyk') {
return '
';
}
$paths = [
'lock' => '',
'shield' => '',
'video' => '',
];
if (!isset($paths[$icon])) {
return '';
}
return wp_kses('', [
'svg' => array_fill_keys(['class', 'viewbox', 'fill', 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin', 'aria-hidden', 'focusable'], true),
'path' => ['d' => true],
'rect' => array_fill_keys(['x', 'y', 'width', 'height', 'rx'], true),
]);
}
function samtyk_cmp_render_embed_shortcode($attributes = []): string
{
$settings = samtyk_cmp_get_settings();
$id = is_array($attributes) && isset($attributes['id']) && is_string($attributes['id']) ? $attributes['id'] : '';
if (empty($settings['enabled']) || !preg_match('/^[a-f0-9]{32}$/D', $id)) {
return '';
}
$post_id = samtyk_cmp_find_shortcode_post_id($id);
if ($post_id === 0) {
return '';
}
$snippet = samtyk_cmp_get_snippet($post_id);
if (!$snippet || !$snippet['active'] || $snippet['location'] !== 'shortcode' || $snippet['generated_code'] === '') {
return '';
}
if (!$snippet['placeholder_enabled'] || $snippet['categories'] === []) {
return samtyk_cmp_escape_snippet_output($post_id);
}
$text = samtyk_cmp_is_default_placeholder_text($snippet['placeholder_text'])
? samtyk_cmp_get_placeholder_default_text($snippet['categories'])
: $snippet['placeholder_text'];
return ''
. samtyk_cmp_get_placeholder_icon($snippet['placeholder_icon'])
. '
' . esc_html($text) . '
'
. '
'
. '
' . samtyk_cmp_escape_snippet_output($post_id) . '
';
}
function samtyk_cmp_render_managed_snippets(string $location): void
{
if (!in_array($location, ['head', 'body_open', 'footer'], true)) {
return;
}
$settings = samtyk_cmp_get_settings();
if (empty($settings['enabled'])) {
return;
}
$posts = get_posts([
'post_type' => SAMTYK_CMP_SNIPPET_POST_TYPE,
'post_status' => 'publish',
'posts_per_page' => -1,
'orderby' => ['menu_order' => 'ASC', 'ID' => 'ASC'],
'no_found_rows' => true,
]);
foreach ($posts as $post) {
$snippet = samtyk_cmp_get_snippet((int) $post->ID);
if (
!$snippet
|| $snippet['location'] !== $location
|| !samtyk_cmp_snippet_matches_request($snippet)
) {
continue;
}
samtyk_cmp_print_snippet_output((int) $post->ID);
}
}
function samtyk_cmp_has_applicable_managed_snippets(): bool
{
$posts = get_posts([
'post_type' => SAMTYK_CMP_SNIPPET_POST_TYPE,
'post_status' => 'publish',
'posts_per_page' => -1,
'no_found_rows' => true,
]);
foreach ($posts as $post) {
$snippet = samtyk_cmp_get_snippet((int) $post->ID);
if ($snippet && $snippet['generated_code'] !== '' && samtyk_cmp_snippet_matches_request($snippet)) {
return true;
}
}
return false;
}
function samtyk_cmp_enqueue_script_embed_manager(): void
{
$settings = samtyk_cmp_get_settings();
if (empty($settings['enabled']) || !samtyk_cmp_has_applicable_managed_snippets()) {
return;
}
wp_enqueue_script(
'samtyk-cmp-script-embed-manager',
SAMTYK_CMP_PLUGIN_URL . 'assets/script-embed-manager.js',
[],
SAMTYK_CMP_VERSION,
false
);
samtyk_cmp_enqueue_placeholder_styles();
}
add_action('init', 'samtyk_cmp_register_snippet_post_type');
add_action('save_post_' . SAMTYK_CMP_SNIPPET_POST_TYPE, 'samtyk_cmp_invalidate_shortcode_index');
add_action('before_delete_post', 'samtyk_cmp_invalidate_shortcode_index');
add_action('added_post_meta', 'samtyk_cmp_invalidate_shortcode_meta_index', 10, 3);
add_action('updated_post_meta', 'samtyk_cmp_invalidate_shortcode_meta_index', 10, 3);
add_action('deleted_post_meta', 'samtyk_cmp_invalidate_shortcode_meta_index', 10, 3);
add_shortcode('samtyk_embed', 'samtyk_cmp_render_embed_shortcode');
add_action('wp_enqueue_scripts', 'samtyk_cmp_enqueue_script_embed_manager');
add_action('wp_head', static function (): void {
samtyk_cmp_render_managed_snippets('head');
}, 20);
add_action('wp_body_open', static function (): void {
samtyk_cmp_render_managed_snippets('body_open');
}, 20);
add_action('wp_footer', static function (): void {
samtyk_cmp_render_managed_snippets('footer');
}, 20);