Changeset 3383399
- Timestamp:
- 10/23/2025 12:49:28 PM (5 months ago)
- Location:
- printess-editor/trunk
- Files:
-
- 9 edited
-
includes/js/printessEditor.js (modified) (5 diffs)
-
includes/js/printessWoocommerce.js (modified) (8 diffs)
-
includes/printess-admin-settings.php (modified) (2 diffs)
-
includes/printess-api.php (modified) (4 diffs)
-
includes/printess-product-helpers.php (modified) (6 diffs)
-
includes/printess-saved-design-repository.php (modified) (2 diffs)
-
includes/printess-table.php (modified) (1 diff)
-
printess.php (modified) (4 diffs)
-
readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
printess-editor/trunk/includes/js/printessEditor.js
r3362973 r3383399 599 599 } 600 600 static async getOrGenerateBasketId(context) { 601 let ret = typeof context .getBasketId === "function" ? context.getBasketId() : "";602 if (!ret && typeof context .getBasketIdAsync === "function") {601 let ret = typeof context?.getBasketId === "function" ? context.getBasketId() : ""; 602 if (!ret && typeof context?.getBasketIdAsync === "function") { 603 603 ret = await context.getBasketIdAsync() || null; 604 604 } … … 649 649 } 650 650 static closeAllHtmlDialogs() { 651 document.querySelectorAll(":not( printess-owned) dialog").forEach((x) => {652 if ( typeof x.close === "function") {651 document.querySelectorAll(":not(.printess-owned) dialog,dialog:not(.printess-owned)").forEach((x) => { 652 if (x && !x.classList.contains("printess-owned") && typeof x.close === "function") { 653 653 try { 654 654 x.close(); … … 707 707 if (printessComponent && printessComponent.editor) { 708 708 printessComponent.style.display = "block"; 709 await printessComponent.editor.api.loadTemplateAndFormFields(context.templateNameOrSaveToken, mergeTemplates, formFields, null );709 await printessComponent.editor.api.loadTemplateAndFormFields(context.templateNameOrSaveToken, mergeTemplates, formFields, null, null, true); 710 710 if (!isSaveToken && pageCount !== null && pageCount > 0) { 711 711 await printessComponent.editor.api.setBookInsidePages(pageCount); … … 773 773 snippetPriceCategoryLabels: priceInfo && priceInfo.snippetPrices ? priceInfo.snippetPrices : null, 774 774 theme: theme, 775 skipExchangeStateApplication: true, 775 776 addToBasketCallback: (token, thumbnailUrl) => { 776 777 const addToBasket = (saveToken, thumbnailUrl) => { … … 997 998 formFields: formFields, 998 999 snippetPriceCategoryLabels: priceInfo && priceInfo.snippetPrices ? priceInfo.snippetPrices : null, 999 mergeTemplates: mergeTemplates 1000 mergeTemplates: mergeTemplates, 1001 skipExchangeStateApplication: true 1000 1002 }; 1001 1003 if (typeof context.showSplitterGridSizeButton !== "undefined" && context.showSplitterGridSizeButton !== null) { -
printess-editor/trunk/includes/js/printessWoocommerce.js
r3365959 r3383399 1 const printessFocusListeners = []; 2 const printessTrapFocus = function (root) { 1 class PrintessSharedTools { 2 static async createSaveToken(shopToken, params) { 3 const response = await fetch('https://api.printess.com/production/savetoken/create', { 4 method: 'POST', 5 redirect: "follow", 6 headers: { 7 "Content-Type": 'application/json', 8 "Authorization": `Bearer ${shopToken}`, 9 }, 10 body: JSON.stringify(params) 11 }); 12 if (!response.ok) { 13 console.error("Unable to create save token: [" + response.status + "] " + response.statusText); 14 return null; 15 } 16 return (await response.json()); 17 } 18 static decodeHTML(encoded) { 19 const textarea = document.createElement('textarea'); 20 textarea.innerHTML = encoded; 21 return textarea.value; 22 } 23 static parseMergeTemplate(template) { 24 let ret = []; 25 if (template) { 26 if (Array.isArray(template)) { 27 template.forEach((x) => { 28 ret = [ 29 ...ret, 30 ...PrintessSharedTools.parseMergeTemplate(x) 31 ]; 32 }); 33 } 34 else { 35 if (typeof template !== "string") { 36 ret.push(template); 37 } 38 else { 39 try { 40 let deserialized = JSON.parse(template); 41 ret = [ 42 ...ret, 43 ...PrintessSharedTools.parseMergeTemplate(deserialized) 44 ]; 45 } 46 catch { 47 try { 48 let deserialized = JSON.parse(PrintessSharedTools.decodeHTML(template)); 49 ret = [ 50 ...ret, 51 ...PrintessSharedTools.parseMergeTemplate(deserialized) 52 ]; 53 } 54 catch { 55 ret.push({ 56 templateName: template 57 }); 58 } 59 } 60 } 61 } 62 } 63 return ret; 64 } 65 static sleepAsync(timeoutMs) { 66 return new Promise((resolve) => setTimeout(resolve, timeoutMs)); 67 } 68 static queryItem(itemQuery, callback, failedCallback = null, timeout = 200, maxRetires = 20, retries = 0) { 69 if (retries >= maxRetires) { 70 if (typeof failedCallback === "function") { 71 failedCallback(); 72 } 73 return; 74 } 75 const element = itemQuery(); 76 if (element) { 77 callback(element); 78 return; 79 } 80 setTimeout(function () { 81 const element = itemQuery(); 82 if (element) { 83 callback(element); 84 } 85 else { 86 PrintessSharedTools.queryItem(itemQuery, callback, failedCallback, timeout, maxRetires, retries + 1); 87 } 88 }, timeout); 89 } 90 static async queryItemAsync(itemQuery, timeout = 50, maxRetires = 20) { 91 return new Promise((resolve, reject) => PrintessSharedTools.queryItem(itemQuery, resolve, reject, timeout, maxRetires)); 92 } 93 static forEach(items, callback) { 94 if (!items || typeof callback !== "function") { 95 return; 96 } 97 if (Array.isArray(items)) { 98 items.forEach(callback); 99 } 100 else { 101 let index = 0; 102 for (const prop in items) { 103 if (items.hasOwnProperty(prop)) { 104 callback(items[prop], index, items, prop); 105 ++index; 106 } 107 } 108 } 109 } 110 static map(items, callback) { 111 if (!items || typeof callback !== "function") { 112 return []; 113 } 114 if (Array.isArray(items)) { 115 return items.map(callback); 116 } 117 else { 118 const ret = []; 119 let index = 0; 120 for (const prop in items) { 121 if (items.hasOwnProperty(prop)) { 122 ret.push(callback(items[prop], index, items, prop)); 123 ++index; 124 } 125 } 126 return ret; 127 } 128 } 129 static filter(items, callback) { 130 const ret = {}; 131 PrintessSharedTools.forEach(items, (value, index, arr, key) => { 132 if (callback(value, items, key, index) === true) { 133 ret[key] = value; 134 } 135 }); 136 return ret; 137 } 138 static filterAsArray(items, callback) { 139 const ret = []; 140 PrintessSharedTools.forEach(items, (value, index, arr, key) => { 141 if (callback(value, items, key, index) === true) { 142 ret.push({ 143 key: key, 144 value: value 145 }); 146 } 147 }); 148 return ret; 149 } 150 static ensureHttpProtocol(domain) { 151 let ret = ((typeof domain !== "string" ? domain.apiDomain : domain) || "").trim(); 152 if (ret.indexOf("http://") !== 0 && ret.indexOf("https://")) { 153 if (ret.length > 1 && ret[0] === "/" && ret[1] === "/") { 154 ret = ret.substring(2); 155 } 156 else if (ret.length > 0 && ret[0] === "/") { 157 ret = ret.substring(1); 158 } 159 ret = "https://" + ret; 160 } 161 return ret; 162 } 163 static urlConcat(url, ...parts) { 164 let ret = url || ""; 165 const filteredParts = (parts || []).filter(x => x ? true : false); 166 filteredParts.forEach((part) => { 167 if (part.length > 1) { 168 if (ret && ret[ret.length - 1] !== "/") { 169 ret += "/"; 170 } 171 ret += part[0] !== "/" ? part : part.substring(1); 172 } 173 else if (part[0] !== "/") { 174 if (ret && ret[ret.length - 1] !== "/") { 175 ret += "/"; 176 } 177 ret += part; 178 } 179 }); 180 return ret; 181 } 182 static sanitizeHost(host) { 183 if (host) { 184 host = host.trim(); 185 if (host.endsWith("/")) { 186 return host; 187 } 188 return host + "/"; 189 } 190 return host || ""; 191 } 192 static async postJsonAsync(url, params, token, additionalHeaders) { 193 const headers = { 194 "Content-Type": 'application/json' 195 }; 196 if (token) { 197 headers["Authorization"] = "Bearer " + token; 198 } 199 if (additionalHeaders) { 200 PrintessSharedTools.forEach(additionalHeaders, (value, index, headers, key) => { 201 if (key && value) { 202 headers[key] = value; 203 } 204 }); 205 } 206 const response = await fetch('https://api.printess.com/shop/savetoken/split', { 207 method: 'POST', 208 redirect: "follow", 209 headers: headers, 210 body: JSON.stringify(params) 211 }); 212 if (!response.ok) { 213 throw `Unable to post json to ${url}: [${response.status}]: ${response.statusText}`; 214 } 215 return await response.json(); 216 } 217 loadTagsAsync(settings) { 218 return PrintessSharedTools.postJsonAsync(PrintessSharedTools.urlConcat(PrintessSharedTools.ensureHttpProtocol(settings), "snippets/tags/load"), { includeGlobal: settings.includeGlobalTags === true }, settings.serviceToken); 219 } 220 static generateUUID() { 221 var d = new Date().getTime(); //Timestamp 222 var d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now() * 1000)) || 0; //Time in microseconds since page-load or 0 if unsupported 223 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 224 var r = Math.random() * 16; //random number between 0 and 16 225 if (d > 0) { //Use timestamp until depleted 226 r = (d + r) % 16 | 0; 227 d = Math.floor(d / 16); 228 } 229 else { //Use microseconds since page-load if supported 230 r = (d2 + r) % 16 | 0; 231 d2 = Math.floor(d2 / 16); 232 } 233 return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); 234 }); 235 } 236 static getFileNameFromUrl(fileName) { 237 return (fileName || "").split('#')[0].split('?')[0].split('/').pop(); 238 } 239 static async downloadImages(images) { 240 const ret = []; 241 if (Array.isArray(images)) { 242 for (let i = 0; i < images.length; ++i) { 243 const response = await fetch(images[i].value); 244 if (response.ok) { 245 const blob = await response.blob(); 246 ret.push({ 247 name: images[i].name, 248 data: new File([blob], this.getFileNameFromUrl(images[i].value), { type: blob.type }) 249 }); 250 } 251 else { 252 console.error("Unable to download image " + images[i].value + "; [" + response.status.toString() + "] " + response.statusText + ": " + await response.text()); 253 } 254 } 255 } 256 else { 257 for (const fileName in images) { 258 if (images.hasOwnProperty(fileName)) { 259 const fileUrl = images[fileName]; 260 const response = await fetch(fileUrl); 261 if (response.ok) { 262 const blob = await response.blob(); 263 ret.push({ 264 name: fileName, 265 data: new File([blob], this.getFileNameFromUrl(fileUrl), { type: blob.type }) 266 }); 267 } 268 else { 269 console.error("Unable to download image " + images[fileName] + "; [" + response.status.toString() + "] " + response.statusText + ": " + await response.text()); 270 } 271 } 272 } 273 } 274 return ret; 275 } 276 } 277 278 const printessFocusListeners = []; 279 let printessSaveReminderActive = false; 280 function printessTrapFocus(root) { 3 281 const keyboardFocusableElements = root?.querySelectorAll('a[href], button, input, textarea, select, details, [tabindex]'); 4 282 if (keyboardFocusableElements && keyboardFocusableElements.length > 0) { … … 22 300 firstFocusableElement?.focus(); 23 301 } 24 } ;302 } 25 303 const printessFreeFocus = function () { 26 304 if (printessFocusListeners.length > 0) { … … 462 740 return name; 463 741 }; 464 const decodeHTMLEntities = (encoded) => {465 const textarea = document.createElement('textarea');466 textarea.innerHTML = encoded;467 return textarea.value;468 };469 const parseMergeTemplate = (template) => {470 let ret = [];471 if (template) {472 if (Array.isArray(template)) {473 template.forEach((x) => {474 ret = [475 ...ret,476 ...parseMergeTemplate(x)477 ];478 });479 }480 else {481 if (typeof template !== "string") {482 ret.push(template);483 }484 else {485 try {486 let deserialized = JSON.parse(template);487 ret = [488 ...ret,489 ...parseMergeTemplate(deserialized)490 ];491 }492 catch {493 try {494 let deserialized = JSON.parse(decodeHTMLEntities(template));495 ret = [496 ...ret,497 ...parseMergeTemplate(deserialized)498 ];499 }500 catch {501 ret.push({502 templateName: template503 });504 }505 }506 }507 }508 }509 return ret;510 };511 742 const createShopContext = function (settings) { 512 743 const context = { … … 531 762 ret = [ 532 763 ...ret, 533 ... parseMergeTemplate(settings.mergeTemplates)764 ...PrintessSharedTools.parseMergeTemplate(settings.mergeTemplates) 534 765 ]; 535 766 } … … 537 768 ret = [ 538 769 ...ret, 539 ... parseMergeTemplate(settings.product.mergeTemplates)770 ...PrintessSharedTools.parseMergeTemplate(settings.product.mergeTemplates) 540 771 ]; 541 772 } … … 545 776 ret = [ 546 777 ...ret, 547 ... parseMergeTemplate(selectedVariant.templateName)778 ...PrintessSharedTools.parseMergeTemplate(selectedVariant.templateName) 548 779 ]; 549 780 } … … 899 1130 onSaveTimer: () => { 900 1131 if (typeof settings.showSaveWarningAfter !== "undefined" && settings.showSaveWarningAfter > 0 && typeof context.save === "function") { 901 this.showDialog("printess_save_reminder", "", (okClicked, value) => { 902 value = (value || "").trim(); 903 if (okClicked) { 904 context.save(); 905 } 906 }); 1132 if (!printessSaveReminderActive) { 1133 this.showDialog("printess_save_reminder", "", (okClicked, value) => { 1134 value = (value || "").trim(); 1135 if (okClicked) { 1136 context.save(); 1137 } 1138 }); 1139 printessSaveReminderActive = true; 1140 } 907 1141 } 908 1142 }, … … 1303 1537 if (previouslyFocused && previouslyFocused instanceof HTMLElement) { 1304 1538 previouslyFocused.focus(); 1539 } 1540 if (printessSaveReminderActive) { 1541 printessSaveReminderActive = false; 1305 1542 } 1306 1543 }; -
printess-editor/trunk/includes/printess-admin-settings.php
r3341026 r3383399 323 323 */ 324 324 static function register_settings() { 325 include_once("printess-api.php");325 require_once(plugin_dir_path(__DIR__) . "includes/printess-api.php"); 326 326 327 327 add_settings_section( … … 973 973 __( 'Overwrite product drop shipper in case of template mode', 'printess-editor' ), 974 974 function() { 975 include_once("printess-api.php");975 require_once(plugin_dir_path(__DIR__) . "includes/printess-api.php"); 976 976 977 977 $dropshipping = array(); -
printess-editor/trunk/includes/printess-api.php
r3339767 r3383399 14 14 */ 15 15 static function send_post_request( $url, $token, $data ) { 16 include_once("printess-admin-settings.php");16 require_once(plugin_dir_path(__DIR__) . "includes/printess-admin-settings.php"); 17 17 18 18 $ssl_verify = ! PrintessAdminSettings::get_debug(); … … 48 48 */ 49 49 static function send_get_request($url) { 50 include_once("printess-admin-settings.php");50 require_once(plugin_dir_path(__DIR__) . "includes/includes/printess-admin-settings.php"); 51 51 52 52 $ssl_verify = ! PrintessAdminSettings::get_debug(); … … 76 76 */ 77 77 static function get_dropshipping_info() { 78 include_once("printess-admin-settings.php");78 require_once(plugin_dir_path(__DIR__) . "includes/printess-admin-settings.php"); 79 79 80 80 $printess_host = PrintessAdminSettings::get_host(); … … 141 141 142 142 static function get_save_token_info($save_token) { 143 include_once("printess-admin-settings.php");143 require_once(plugin_dir_path(__DIR__) . "includes/printess-admin-settings.php"); 144 144 145 145 $printess_host = PrintessAdminSettings::get_host(); -
printess-editor/trunk/includes/printess-product-helpers.php
r3325412 r3383399 46 46 } 47 47 48 private function get_attribute_definition($attribute_name, array $attrbutes = null) {48 private function get_attribute_definition($attribute_name, ?array $attrbutes = null) { 49 49 if(null === $attrbutes) { 50 50 $attributes = $this->get_attributes(); … … 130 130 } 131 131 132 /** 133 * Test if the given object is an array, check if the array has a key, produce a warning if not 134 */ 135 function transform_meta_value_to_template_name(mixed $item, string $key): string { 136 if(isset($item)) { 137 if(is_array($item)) { 138 if(array_key_exists($key, $item)) { 139 $name = $item[$key]; 140 141 if(isset($name) && is_string($name) && !empty($name)) { 142 return $name; 143 } 144 } 145 } else if(is_string($item) && !empty($item)) { 146 return $item; 147 } 148 } 149 150 if(isset($item) && !is_string($item)) { 151 try { 152 $logger = wc_get_logger(); 153 154 } catch(\Exception $e) { 155 //Intentionally left blank, nothing to do here 156 $logger->error( 'Printess Editor Integration: Unexpected data type in printess template name meta data: ' . json_encode( $item ), array( 'source' => 'my-custom-plugin' ) ); 157 } 158 } 159 160 return ""; 161 } 162 132 163 public function get_template_name($check_base_product = false): string { 133 $template_name = $this-> _product->get_meta( 'printess_template', true);164 $template_name = $this->transform_meta_value_to_template_name($this->_product->get_meta( 'printess_template', true ), "printess_template"); 134 165 135 166 $template_name = $template_name === null || empty($template_name) ? "" : $template_name; … … 150 181 } 151 182 } else { 152 $variation_template_name = $ variation->get_meta( 'printess_template_name', true);183 $variation_template_name = $this->transform_meta_value_to_template_name($variation->get_meta( 'printess_template_name', true ), "printess_template_name"); 153 184 } 154 185 … … 160 191 161 192 if(!$variant_has_template_name) { 162 $template_name = $this-> _base_product->get_meta( 'printess_template', true);193 $template_name = $this->transform_meta_value_to_template_name($this->_base_product->get_meta( 'printess_template', true ), "printess_template"); 163 194 $template_name = $template_name === null || empty($template_name) ? "" : $template_name; 164 195 } … … 191 222 */ 192 223 public static function render_product_option_pane() { 193 include_once("includes/printess-api.php");194 include_once("includes/printess-html-helpers.php");195 include_once("includes/printess-admin-settings.php");224 require_once(plugin_dir_path(__DIR__) . "includes/printess-api.php"); 225 require_once(plugin_dir_path(__DIR__) . "includes/printess-html-helpers.php"); 226 require_once(plugin_dir_path(__DIR__) . "includes/printess-admin-settings.php"); 196 227 197 228 $product_helpers = new PrintessProductHelpers(get_the_ID()); … … 400 431 'value' => get_post_meta( get_the_ID(), 'printess_ui_version', true ), 401 432 'label' => __( 'Buyer side user interface', 'printess-editor' ), 402 'description' => __( ' Classical or the new PanelUi (Beta!).', 'printess-editor' ),433 'description' => __( 'PanelUi or the old deprecated iframe intgeration', 'printess-editor' ), 403 434 'options' => array( 404 ' classical' => 'Classical',405 ' bcui' => 'PanelUi (Beta)',435 'bcui' => 'PanelUi', 436 'classical' => 'Deprecated iframe integration', 406 437 ), 407 438 ) -
printess-editor/trunk/includes/printess-saved-design-repository.php
r3073802 r3383399 141 141 } 142 142 143 function add_design(int $customer_id, string $save_token, string $thumbnail_url, int $product_id, string $product_name, string $display_name, array $product_options = null): int {143 function add_design(int $customer_id, string $save_token, string $thumbnail_url, int $product_id, string $product_name, string $display_name, ?array $product_options = null): int { 144 144 global $wpdb; 145 145 $table_name = $wpdb->prefix . "printess_saved_designs"; … … 255 255 } 256 256 257 function update_design(int $customer_id, int $design_id, string $save_token, string $thumbnail_url, array $options = null): bool {257 function update_design(int $customer_id, int $design_id, string $save_token, string $thumbnail_url, ?array $options = null): bool { 258 258 global $wpdb; 259 259 $table_name = $wpdb->prefix . "printess_saved_designs"; -
printess-editor/trunk/includes/printess-table.php
r3029359 r3383399 33 33 } 34 34 35 function add_row( array $values = null) {35 function add_row(?array $values = null) { 36 36 $new_row = array(); 37 37 -
printess-editor/trunk/printess.php
r3365959 r3383399 5 5 * Plugin URI: https://printess.com/kb/integrations/woo-commerce/index.html 6 6 * Developer: Bastian Kröger (support@printess.com); Alexander Oser (support@printess.com) 7 * Version: 1.6.6 57 * Version: 1.6.66 8 8 * Author: Printess 9 9 * Author URI: https://printess.com … … 12 12 * Requires at least: 5.9 13 13 * Requires PHP: 8.1 14 * Tested up to: 6.8 15 * 16 * Woo: 10000:92402 3dfsfhsf8429842386wdff234sfd14 * Tested up to: 6.8.3 15 * 16 * Woo: 10000:924024dfsfhsf8429842386wdff234sfd 17 17 * WC requires at least: 5.8 18 * WC tested up to: 9.8.218 * WC tested up to: 10.3.0 19 19 */ 20 20 … … 3750 3750 } 3751 3751 3752 $variation_id = $_REQUEST['variation_id']; 3752 $variation_id = null; 3753 3754 if(array_key_exists('variation_id', $_REQUEST)) { 3755 $variation_id = $_REQUEST['variation_id']; 3756 } 3757 3753 3758 $helper = new PrintessProductHelpers(null === $variation_id || empty($variation_id) ? $product_id : intval($variation_id) ); 3754 3759 $product_template_name = $helper->get_template_name(true); … … 3937 3942 } 3938 3943 3939 if ( in_array( $printess_global_plugin_path, wp_get_active_and_valid_plugins(), true ) || in_array( $printess_global_plugin_path, wp_get_active_network_plugins(), true ) ) { 3944 3945 if ( in_array( $printess_global_plugin_path, wp_get_active_and_valid_plugins(), true ) || (function_exists("wp_get_active_network_plugins") && in_array( $printess_global_plugin_path, wp_get_active_network_plugins(), true )) ) { 3940 3946 add_action( 'woocommerce_init', 'printess_register_hooks' ); 3941 3947 -
printess-editor/trunk/readme.txt
r3365959 r3383399 3 3 Tags: personalization, mug, calendar, t-shirt, photo products, customization, web2print, photo books, canvas, avatar, photo tiles, personalized children book, greeting cards, graphic design, configurator 4 4 Requires at least: 5.6 5 Tested up to: 6.8 6 WC Tested up to: 9.8.27 Stable tag: 1.6. 405 Tested up to: 6.8.3 6 WC Tested up to: 10.3.0 7 Stable tag: 1.6.66 8 8 Requires PHP: 8.1 9 9 License: GPLv2 or later … … 341 341 = 1.6.65 = 342 342 - Fixed: Fixed bug that saved a wrong variant in case the current user is not logged in and clicks on save. Before, the default variant was used instead of the current selected variant. 343 344 = 1.6.66 = 345 - Fixed bug that did not clear the exchange id cache when using panel Ui 346 - Fixed PHP warnings with referenced printess plugin files that could not be found by replacing include_once calls with require_once. 347 - Fixed broken add to cart when using specific product types or specific plugins that might chaneg the data type of product meta data 348 - PanelUi is now the standard for newly created products
Note: See TracChangeset
for help on using the changeset viewer.