materials->find($identifier); if ($material) { $materialData[$identifier] = $material->jsonSerialize(); $materialData[$material->display_id()] = $material->jsonSerialize(); } } $fallbackId = absint(ProductMeta::get($productId, 'fallback_image_id', 0)) ?: get_post_thumbnail_id($productId); $height = absint(ProductMeta::get($productId, 'height', 0)) ?: (int) $settings['height']; if (!empty($overrides['height'])) { $height = min(1200, max(240, absint($overrides['height']))); } $autoRotateMeta = ProductMeta::get($productId, 'auto_rotate', ''); $autoRotate = '' !== $autoRotateMeta ? 'yes' === $autoRotateMeta : 'yes' === $settings['auto_rotate']; return [ 'productId' => $productId, 'modelUrl' => esc_url_raw((string) $modelUrl), 'modelFormat' => $this->resolve_model_format($productId, (string) $modelUrl), 'fallbackImageUrl' => $fallbackId ? wp_get_attachment_image_url($fallbackId, 'large') : null, 'height' => $height, 'backgroundColor' => sanitize_hex_color((string) $settings['background_color']) ?: '#f7f7f7', 'defaultModelColor' => sanitize_hex_color((string) ($settings['default_model_color'] ?? '')) ?: '#b7b7b7', 'autoRotate' => $autoRotate, 'maxPixelRatio' => (float) $settings['max_pixel_ratio'], 'fpsLimit' => (int) $settings['fps_limit'], 'fullscreen' => 'yes' === $settings['fullscreen'], 'lazyLoading' => 'yes' === $settings['lazy_loading'], 'defaultMaterial' => $defaultMaterial, 'materials' => $materialData, 'selectionMode' => sanitize_key((string) $settings['selection_mode']), 'materialEndpoint' => rest_url('ds82-3dps/v1/materials/'), 'nonce' => is_user_logged_in() ? wp_create_nonce('wp_rest') : '', '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' => __('This browser does not support WebGL.', '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'), 'reset' => __('Reset view', '3d-print-showcase'), 'fullscreen' => __('Fullscreen', '3d-print-showcase'), 'rotation' => __('Toggle auto rotation', '3d-print-showcase'), 'reason' => __('Reason', '3d-print-showcase'), 'unknownError' => __('Unknown error.', '3d-print-showcase'), 'networkError' => __('Network error or blocked access to the file (CORS).', '3d-print-showcase'), ], ]; } private function resolve_model_format(int $productId, string $modelUrl): string { $stored = sanitize_key((string) ProductMeta::get($productId, 'model_format', '')); if (in_array($stored, ['stl', '3mf', 'glb', 'gltf'], true)) { return $stored; } if ('' === trim($modelUrl)) { return 'default'; } $path = (string) wp_parse_url($modelUrl, PHP_URL_PATH); $extension = sanitize_key(strtolower((string) pathinfo($path, PATHINFO_EXTENSION))); return in_array($extension, ['stl', '3mf', 'glb', 'gltf'], true) ? $extension : '3mf'; } public function position(int $productId): string { $position = sanitize_key((string) ProductMeta::get($productId, 'position', '')); return $position ?: sanitize_key((string) Settings::get('position', 'after_gallery')); } }