'', 'width' => '100%', 'height' => 'auto', 'mode' => '', // sdk, iframe, signed_url — empty = use global setting 'alt' => 'Protected image', 'class' => '', ), $atts, 'affirm_protect'); if (empty($a['id'])) { return ''; } $render_mode = $a['mode'] ? $a['mode'] : get_option('affirm_render_mode', 'sdk'); $affirm_id = sanitize_text_field($a['id']); $width = self::sanitize_dimension($a['width'], '100%'); $height = self::sanitize_dimension($a['height'], 'auto'); $alt = sanitize_text_field($a['alt']); $class = sanitize_html_class($a['class']); switch ($render_mode) { case 'iframe': return $this->render_iframe($affirm_id, $width, $height); case 'signed_url': return $this->render_signed_url($affirm_id, $width, $height, $alt, $class); case 'sdk': default: return $this->render_sdk($affirm_id, $width, $height); } } /** * Sanitize a dimension value before it is printed into an inline style attribute. * * Only safe, well-formed CSS length values are allowed; anything else falls back * to the default. This prevents arbitrary CSS from being injected through the * shortcode/block width and height attributes (post content). * * - "auto" → "auto" * - pure number (e.g. "800") → "800px" * - number + allowed unit → kept (px, %, em, rem, vw, vh, vmin, vmax) * - anything else → $default */ public static function sanitize_dimension($value, $default = 'auto') { $value = strtolower(trim((string) $value)); if ($value === '' || $value === '0') { return $default; } if ($value === 'auto') { return 'auto'; } // Pure number → treat as pixels. if (is_numeric($value)) { return abs((float) $value) . 'px'; } // Allow only a positive number followed by an approved CSS unit. if (preg_match('/^(\d+(?:\.\d+)?)(px|%|em|rem|vw|vh|vmin|vmax)$/', $value, $matches)) { return $matches[1] . $matches[2]; } // Unrecognized / potentially malicious value → safe default. return $default; } private function render_sdk($affirm_id, $width, $height) { // SDK is globally enqueued by Affirm_Frontend_Renderer::enqueue_sdk() return sprintf( '
', esc_attr($affirm_id), esc_attr($width), esc_attr($height), esc_attr($width), esc_attr($height) ); } private function render_iframe($affirm_id, $width, $height) { $embed_url = affirm_get_backend_url() . '/sdk/embed/' . esc_attr($affirm_id); // iframe needs numeric width/height for the attribute, CSS for the style return sprintf( '', esc_url($embed_url), esc_attr($width), esc_attr($height) ); } private function render_signed_url($affirm_id, $width, $height, $alt, $class) { $signed_url = Affirm_Api::get_signed_url($affirm_id); if (!$signed_url) return 'Image unavailable
'; $class_attr = $class ? ' class="' . esc_attr($class) . '"' : ' class="affirmfirst-image"'; return sprintf( '