'', 'model_id' => 0, 'height' => 0, 'material' => '',
'fallback_url' => '', 'auto_rotate' => '', 'force_selector' => 'no',
], $attributes, 'ds82_3d_print_showcase');
$modelUrl = esc_url_raw((string) $attributes['model_url']);
$modelId = absint($attributes['model_id']);
$fallbackUrl = esc_url_raw((string) $attributes['fallback_url']);
$attachmentPath = '';
if (!$modelUrl && $modelId) {
$modelUrl = (string) wp_get_attachment_url($modelId);
$attachmentPath = (string) get_attached_file($modelId);
}
$urlPath = (string) wp_parse_url($modelUrl, PHP_URL_PATH);
$formatSource = $attachmentPath !== '' ? $attachmentPath : $urlPath;
$modelFormat = $modelUrl !== '' ? strtolower((string) pathinfo($formatSource, PATHINFO_EXTENSION)) : 'default';
$supportedFormats = ['stl', '3mf', 'glb', 'gltf'];
if ($modelUrl !== '' && !in_array($modelFormat, $supportedFormats, true)) {
$message = sprintf(
/* translators: 1: attachment ID, 2: detected file extension */
__('Attachment ID %1$d does not point to a supported 3D model. Detected format: %2$s. Supported formats are STL, 3MF, GLB and GLTF.', '3d-print-showcase'),
$modelId,
$modelFormat !== '' ? strtoupper($modelFormat) : __('unknown', '3d-print-showcase')
);
return $this->renderFallbackOrError($fallbackUrl, $message, $attributes);
}
$settings = Settings::all();
$height = absint($attributes['height']) ?: (int) $settings['height'];
// The material attribute acts as an optional filter. When omitted, all
// published materials from the active provider are available. A single
// identifier keeps backwards compatibility and becomes the default.
$requestedMaterialIds = $this->parseMaterialIdentifiers((string) $attributes['material']);
$availableMaterials = $this->resolveMaterials($requestedMaterialIds);
$material = $availableMaterials ? reset($availableMaterials) : null;
$colors = $material ? $material->colors() : [(string) $settings['default_model_color']];
$autoRotate = $attributes['auto_rotate'] === '' ? $settings['auto_rotate'] === 'yes' : in_array(strtolower((string) $attributes['auto_rotate']), ['1', 'yes', 'true'], true);
$instanceId = 'ds82-3dps-shortcode-' . wp_rand(1000, 999999);
$config = [
'viewerId' => $instanceId,
'productId' => 0,
'modelUrl' => $modelUrl, 'modelFormat' => $modelFormat,
'height' => min(1200, max(240, $height)), 'backgroundColor' => $material?->backgroundColor ?: (string) $settings['background_color'],
'globalBackgroundColor' => (string) $settings['background_color'],
'defaultMaterial' => $material?->identifier() ?? '',
'materialEndpoint' => rest_url('ds82-3dps/v1/materials/'),
'materials' => array_map(static fn (Material $item): array => $item->jsonSerialize(), $availableMaterials),
'defaultModelColor' => $colors[0] ?? (string) $settings['default_model_color'], 'colors' => $colors,
'colorMode' => $material?->colorMode ?? 'single', 'colorModeType' => $material?->colorModeType ?? 'standard',
'appearanceType' => $material?->appearanceType ?? 'standard', 'roughness' => $material?->roughness ?? 0.55,
'metalness' => $material?->metalness ?? 0.0, 'opacity' => $material?->opacity ?? 1.0,
'textureUrl' => $material?->textureUrl ?? '', 'normalMapUrl' => $material?->normalMapUrl ?? '',
'fallbackImageUrl' => $fallbackUrl, 'autoRotate' => $autoRotate,
'fullscreen' => $settings['fullscreen'] === 'yes', 'lazyLoading' => $settings['lazy_loading'] === 'yes',
'maxPixelRatio' => (float) $settings['max_pixel_ratio'], 'fpsLimit' => (int) $settings['fps_limit'],
'strings' => [
'loading' => __('Loading 3D model…', '3d-print-showcase'),
'materialLoading' => __('Loading selected color…', '3d-print-showcase'),
'error' => __('The 3D model could not be displayed.', '3d-print-showcase'),
'webglError' => __('WebGL is not supported by this browser.', '3d-print-showcase'),
'slicerProject3mf' => __('This 3MF file is a slicer project (Bambu Studio, OrcaSlicer, PrusaSlicer, or similar), not a standard 3D model. Export the model as a standard 3MF, GLB, or STL file.', '3d-print-showcase'),
],
];
$this->enqueue_assets(!empty($availableMaterials) && count($availableMaterials) > 1);
$json = wp_json_encode($config, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES);
$disclaimer = $settings['disclaimer_enabled'] === 'yes' ? (string) $settings['disclaimer_text'] : '';
ob_start(); ?>
' . esc_html($message) . '
' : ''; } public function module_script_tag(string $tag, string $handle, string $src): string { return $handle === 'ds82-3dps-viewer' && !str_contains($tag, 'type=') ? str_replace('