Changeset 3431054
- Timestamp:
- 01/02/2026 01:22:32 PM (7 weeks ago)
- Location:
- artidomo-print-on-demand/trunk
- Files:
-
- 4 added
- 7 deleted
- 4 edited
-
admin/class-admin-interface.php (modified) (22 diffs)
-
artidomo-print.php (modified) (3 diffs)
-
assets/banner-1544x500.png (deleted)
-
assets/banner-772x250.png (deleted)
-
assets/icon-256x256.png (deleted)
-
assets/screenshot-1.jpg (deleted)
-
assets/screenshot-2.jpg (deleted)
-
assets/screenshot-3.jpg (deleted)
-
assets/screenshot-4.jpg (deleted)
-
includes/class-one-click-connect.php (modified) (73 diffs)
-
languages (added)
-
languages/artidomo-print-on-demand-de_DE.mo (added)
-
languages/artidomo-print-on-demand-de_DE.po (added)
-
languages/artidomo-print-on-demand.pot (added)
-
readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
artidomo-print-on-demand/trunk/admin/class-admin-interface.php
r3430729 r3431054 2 2 /** 3 3 * Admin Interface Class 4 * Produ ktzuordnung und Einstellungen imWordPress Admin4 * Product mapping and settings in WordPress Admin 5 5 */ 6 6 … … 17 17 $instance = new self(); 18 18 19 // WooCommerce Product Data Tab (statt Sidebar Meta Box!)19 // WooCommerce Product Data Tab 20 20 add_filter('woocommerce_product_data_tabs', array($instance, 'add_artidomo_product_tab')); 21 21 add_action('woocommerce_product_data_panels', array($instance, 'render_artidomo_product_panel')); … … 43 43 44 44 /** 45 * Füge artidomo Tab zu WooCommerce Product Data hinzu 46 * NUR für Simple/Grouped/External Products - NICHT für Variable Products! 47 * (Bei Variable Products erfolgt die Zuordnung auf Varianten-Ebene) 45 * Add artidomo tab to WooCommerce Product Data 48 46 */ 49 47 public function add_artidomo_product_tab($tabs) { 50 48 $tabs['artidomo'] = array( 51 'label' => __('artidomo', 'artidomo- connector'),49 'label' => __('artidomo', 'artidomo-print-on-demand'), 52 50 'target' => 'artidomo_product_data', 53 51 'class' => array('show_if_simple', 'show_if_grouped', 'show_if_external'), … … 68 66 woocommerce_wp_text_input(array( 69 67 'id' => '_artidomo_sku', 70 'label' => __('artidomo SKU', 'artidomo-connector'), 71 'placeholder' => 'z.B. A001-POSTER', 68 'label' => __('artidomo SKU', 'artidomo-print-on-demand'), 69 /* translators: Example SKU format */ 70 'placeholder' => __('e.g. A001-POSTER', 'artidomo-print-on-demand'), 72 71 'desc_tip' => true, 73 'description' => __(' Die SKU des Produkts im artidomo System', 'artidomo-connector'),72 'description' => __('The SKU of the product in the artidomo system', 'artidomo-print-on-demand'), 74 73 'value' => get_post_meta($post->ID, '_artidomo_sku', true), 75 74 )); … … 77 76 woocommerce_wp_text_input(array( 78 77 'id' => '_artidomo_printfilename', 79 'label' => __(' Druckdatei', 'artidomo-connector'),78 'label' => __('Print file', 'artidomo-print-on-demand'), 80 79 'placeholder' => 'design-001.pdf', 81 80 'desc_tip' => true, 82 'description' => __(' Dateiname der Druckdatei', 'artidomo-connector'),81 'description' => __('Filename of the print file', 'artidomo-print-on-demand'), 83 82 'value' => get_post_meta($post->ID, '_artidomo_printfilename', true), 84 83 )); 85 86 // Info: Dateiquelle wird automatisch auf "Druckfilezuordnung" gesetzt87 84 ?> 88 85 <p class="form-field" style="padding-left: 12px;"> 89 86 <em style="color: #666;"> 90 ℹ️ Dateiquelle: <strong>Druckfilezuordnung</strong> (automatisch für WooCommerce)87 ℹ️ <?php esc_html_e('File source:', 'artidomo-print-on-demand'); ?> <strong><?php esc_html_e('Print file mapping', 'artidomo-print-on-demand'); ?></strong> (<?php esc_html_e('automatic for WooCommerce', 'artidomo-print-on-demand'); ?>) 91 88 </em> 92 89 </p> 93 90 <?php 94 95 // Hinweis für variable Produkte96 91 $product = wc_get_product($post->ID); 97 92 if ($product && $product->is_type('variable')): … … 99 94 <p class="form-field" style="padding-left: 12px;"> 100 95 <em style="color: #666;"> 101 ℹ️ Bei variablen Produkten kann jede Variante eigene Zuordnungen haben. 102 Diese Werte gelten nur wenn Varianten keine eigenen haben. 96 ℹ️ <?php esc_html_e('For variable products, each variation can have its own mappings. These values only apply if variations have no own mappings.', 'artidomo-print-on-demand'); ?> 103 97 </em> 104 98 </p> … … 110 104 111 105 /** 112 * S peichere artidomo Product Data106 * Save artidomo Product Data 113 107 */ 114 108 public function save_artidomo_product_data($post_id) { 115 // Security Checks116 109 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 117 110 return; … … 122 115 } 123 116 124 // Speichere Felder125 117 if (isset($_POST['_artidomo_sku'])) { 126 118 update_post_meta($post_id, '_artidomo_sku', sanitize_text_field($_POST['_artidomo_sku'])); 127 // Automatisch "Druckfilezuordnung" setzen für WooCommerce128 119 update_post_meta($post_id, '_artidomo_personalization_provider', 'Druckfilezuordnung'); 129 120 } else { … … 140 131 141 132 /** 142 * Füge Felder zu Variationen hinzu133 * Add fields to variations 143 134 */ 144 135 public function add_variation_fields($loop, $variation_data, $variation) { … … 147 138 $artidomo_sku = get_post_meta($variation_id, '_artidomo_sku', true); 148 139 $printfilename = get_post_meta($variation_id, '_artidomo_printfilename', true); 149 $personalization_provider = get_post_meta($variation_id, '_artidomo_personalization_provider', true);150 140 151 141 ?> 152 142 <div class="form-row form-row-full artidomo-variation-fields"> 153 143 <h4 style="margin-top: 20px; padding-top: 20px; border-top: 1px solid #ddd;"> 154 artidomo Zuordnung144 <?php esc_html_e('artidomo Mapping', 'artidomo-print-on-demand'); ?> 155 145 </h4> 156 146 157 147 <p class="form-field"> 158 <label> artidomo SKU:</label>148 <label><?php esc_html_e('artidomo SKU:', 'artidomo-print-on-demand'); ?></label> 159 149 <input type="text" 160 name="artidomo_sku[<?php echo $loop; ?>]"150 name="artidomo_sku[<?php echo esc_attr($loop); ?>]" 161 151 value="<?php echo esc_attr($artidomo_sku); ?>" 162 placeholder=" z.B. A001-POSTER">152 placeholder="<?php esc_attr_e('e.g. A001-POSTER', 'artidomo-print-on-demand'); ?>"> 163 153 </p> 164 154 165 155 <p class="form-field"> 166 <label> Druckdatei:</label>156 <label><?php esc_html_e('Print file:', 'artidomo-print-on-demand'); ?></label> 167 157 <input type="text" 168 name="artidomo_printfilename[<?php echo $loop; ?>]"158 name="artidomo_printfilename[<?php echo esc_attr($loop); ?>]" 169 159 value="<?php echo esc_attr($printfilename); ?>" 170 160 placeholder="design-001.pdf"> … … 172 162 173 163 <p class="form-field"> 174 <em style="color: #666;">ℹ️ Dateiquelle: <strong>Druckfilezuordnung</strong> (automatisch)</em>164 <em style="color: #666;">ℹ️ <?php esc_html_e('File source:', 'artidomo-print-on-demand'); ?> <strong><?php esc_html_e('Print file mapping', 'artidomo-print-on-demand'); ?></strong> (<?php esc_html_e('automatic', 'artidomo-print-on-demand'); ?>)</em> 175 165 </p> 176 166 </div> … … 179 169 180 170 /** 181 * S peichere Variation Fields171 * Save Variation Fields 182 172 */ 183 173 public function save_variation_fields($variation_id, $loop) { … … 185 175 $sku = sanitize_text_field($_POST['artidomo_sku'][$loop]); 186 176 update_post_meta($variation_id, '_artidomo_sku', $sku); 187 // Automatisch "Druckfilezuordnung" setzen für WooCommerce188 177 if (!empty($sku)) { 189 178 update_post_meta($variation_id, '_artidomo_personalization_provider', 'Druckfilezuordnung'); … … 197 186 198 187 /** 199 * Füge Spalten zur Produktliste hinzu188 * Add columns to product list 200 189 */ 201 190 public function add_product_columns($columns) { 202 // Füge vor der letzten Spalte (Datum) ein203 191 $new_columns = array(); 204 192 … … 237 225 238 226 /** 239 * Füge Bulk Actions hinzu227 * Add Bulk Actions 240 228 */ 241 229 public function add_bulk_actions($actions) { 242 $actions['artidomo_export_selected'] = 'artidomo: Exportieren';230 $actions['artidomo_export_selected'] = __('artidomo: Export', 'artidomo-print-on-demand'); 243 231 return $actions; 244 232 } … … 252 240 } 253 241 254 // TODO: Implementiere selektiven Export255 // Aktuell: Redirect zur normalen Export-Funktion256 257 242 return add_query_arg('artidomo_bulk_export', count($post_ids), $redirect_to); 258 243 } 259 244 260 245 /** 261 * Füge Settings Submenu hinzu246 * Add Settings Submenu 262 247 */ 263 248 public function add_settings_submenu() { 264 249 add_submenu_page( 265 250 'woocommerce', 266 'artidomo CSV Import/Export',267 'artidomo CSV',251 __('artidomo CSV Import/Export', 'artidomo-print-on-demand'), 252 __('artidomo CSV', 'artidomo-print-on-demand'), 268 253 'manage_woocommerce', 269 254 'artidomo-csv', … … 276 261 */ 277 262 public function render_csv_page() { 278 // Import Success Message279 263 if (isset($_GET['import']) && $_GET['import'] === 'success') { 280 264 $imported = isset($_GET['imported']) ? intval($_GET['imported']) : 0; … … 282 266 ?> 283 267 <div class="notice notice-success is-dismissible"> 284 <p><strong>✅ Import erfolgreich!</strong></p> 285 <p><?php echo $imported; ?> Produkte importiert. 286 <?php if ($errors > 0): ?> 287 (<?php echo $errors; ?> Fehler) 288 <?php endif; ?> 268 <p><strong>✅ <?php esc_html_e('Import successful!', 'artidomo-print-on-demand'); ?></strong></p> 269 <p> 270 <?php 271 /* translators: %d: number of products imported */ 272 printf(esc_html__('%d products imported.', 'artidomo-print-on-demand'), $imported); 273 if ($errors > 0) { 274 /* translators: %d: number of errors */ 275 printf(' (' . esc_html__('%d errors', 'artidomo-print-on-demand') . ')', $errors); 276 } 277 ?> 289 278 </p> 290 279 </div> … … 292 281 } 293 282 294 // Statistiken295 283 $stats = Artidomo_CSV_Handler::get_statistics(); 296 297 284 ?> 298 285 <div class="wrap"> 299 <h1> artidomo CSV Import/Export</h1>300 301 <!-- Statisti ken-->286 <h1><?php esc_html_e('artidomo CSV Import/Export', 'artidomo-print-on-demand'); ?></h1> 287 288 <!-- Statistics --> 302 289 <div class="artidomo-stats-box" style="background: #f9f9f9; padding: 20px; margin: 20px 0; border-radius: 5px;"> 303 <h2>📊 Statistiken</h2>304 <p><strong><?php echo $stats['total_all']; ?></strong> Produkte/Varianten gesamt</p>305 <p><strong><?php echo $stats['total_mapped']; ?></strong> davon mit artidomo SKU zugeordnet</p>306 <p><strong><?php echo $stats['with_printfile']; ?></strong> davon mit Druckdatei</p>290 <h2>📊 <?php esc_html_e('Statistics', 'artidomo-print-on-demand'); ?></h2> 291 <p><strong><?php echo esc_html($stats['total_all']); ?></strong> <?php esc_html_e('products/variations total', 'artidomo-print-on-demand'); ?></p> 292 <p><strong><?php echo esc_html($stats['total_mapped']); ?></strong> <?php esc_html_e('mapped with artidomo SKU', 'artidomo-print-on-demand'); ?></p> 293 <p><strong><?php echo esc_html($stats['with_printfile']); ?></strong> <?php esc_html_e('with print file', 'artidomo-print-on-demand'); ?></p> 307 294 </div> 308 295 309 <!-- 3- Spalten Layout für Export, Import und Info-->296 <!-- 3-Column Layout --> 310 297 <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin: 20px 0;"> 311 298 312 299 <!-- Export --> 313 300 <div class="artidomo-export-box" style="background: white; padding: 20px; border: 1px solid #ddd; border-radius: 5px;"> 314 <h2 style="margin-top: 0;">📤 Export</h2>315 <p> Exportiere alle Produktzuordnungen als CSV-Datei.</p>316 317 <form method="post" action="<?php echo admin_url('admin-post.php'); ?>">301 <h2 style="margin-top: 0;">📤 <?php esc_html_e('Export', 'artidomo-print-on-demand'); ?></h2> 302 <p><?php esc_html_e('Export all product mappings as CSV file.', 'artidomo-print-on-demand'); ?></p> 303 304 <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>"> 318 305 <?php wp_nonce_field('artidomo_export_csv'); ?> 319 306 <input type="hidden" name="action" value="artidomo_export_csv"> 320 307 <button type="submit" class="button button-primary"> 321 CSV exportieren (<?php echo $stats['total_all']; ?> Produkte) 308 <?php 309 /* translators: %d: number of products */ 310 printf(esc_html__('Export CSV (%d products)', 'artidomo-print-on-demand'), $stats['total_all']); 311 ?> 322 312 </button> 323 313 </form> … … 326 316 <!-- Import --> 327 317 <div class="artidomo-import-box" style="background: white; padding: 20px; border: 1px solid #ddd; border-radius: 5px;"> 328 <h2 style="margin-top: 0;">📥 Import</h2>329 <p> Importiere Produktzuordnungen aus einer CSV-Datei.</p>318 <h2 style="margin-top: 0;">📥 <?php esc_html_e('Import', 'artidomo-print-on-demand'); ?></h2> 319 <p><?php esc_html_e('Import product mappings from a CSV file.', 'artidomo-print-on-demand'); ?></p> 330 320 331 321 <div class="notice notice-info inline" style="margin: 10px 0;"> 332 <p style="margin: 5px 0;"><strong>ℹ️ CSV Format:</strong></p>322 <p style="margin: 5px 0;"><strong>ℹ️ <?php esc_html_e('CSV Format:', 'artidomo-print-on-demand'); ?></strong></p> 333 323 <ul style="list-style: disc; margin-left: 20px; font-size: 12px;"> 334 <li> Semikolon-getrennt (;)</li>335 <li> UTF-8 Kodierung</li>336 <li> Header-Zeile erforderlich</li>324 <li><?php esc_html_e('Semicolon-separated (;)', 'artidomo-print-on-demand'); ?></li> 325 <li><?php esc_html_e('UTF-8 encoding', 'artidomo-print-on-demand'); ?></li> 326 <li><?php esc_html_e('Header row required', 'artidomo-print-on-demand'); ?></li> 337 327 </ul> 338 328 </div> 339 329 340 330 <form method="post" 341 action="<?php echo admin_url('admin-post.php'); ?>"331 action="<?php echo esc_url(admin_url('admin-post.php')); ?>" 342 332 enctype="multipart/form-data"> 343 333 <?php wp_nonce_field('artidomo_import_csv'); ?> … … 348 338 </p> 349 339 350 <button type="submit" class="button button-primary"> CSV importieren</button>340 <button type="submit" class="button button-primary"><?php esc_html_e('Import CSV', 'artidomo-print-on-demand'); ?></button> 351 341 </form> 352 342 </div> 353 343 354 <!-- Info : Portal-Zuordnung (NEU!)-->344 <!-- Info --> 355 345 <div class="artidomo-info-box" style="background: #fff3cd; padding: 20px; border: 1px solid #ffc107; border-radius: 5px;"> 356 <h2 style="margin-top: 0; color: #856404;">💡 Empfehlung</h2>346 <h2 style="margin-top: 0; color: #856404;">💡 <?php esc_html_e('Recommendation', 'artidomo-print-on-demand'); ?></h2> 357 347 <p style="font-size: 14px; line-height: 1.6;"> 358 <strong> Produktzuordnungen im Portal verwalten!</strong>348 <strong><?php esc_html_e('Manage product mappings in the Portal!', 'artidomo-print-on-demand'); ?></strong> 359 349 </p> 360 350 <p style="font-size: 13px; color: #856404; line-height: 1.5;"> 361 Hier in WooCommerce können Zuordnungen manuell gesetzt werden, aber es besteht die Gefahr von Fehlern.351 <?php esc_html_e('Mappings can be set manually here in WooCommerce, but there is a risk of errors.', 'artidomo-print-on-demand'); ?> 362 352 </p> 363 353 <p style="font-size: 13px; color: #856404; line-height: 1.5; margin-bottom: 15px;"> 364 <strong> Besser:</strong> Nutze die zentrale Produktverwaltung im artidomo Portal unter <em>Shop-Verbindungen → Produktzuordnung</em>.354 <strong><?php esc_html_e('Better:', 'artidomo-print-on-demand'); ?></strong> <?php esc_html_e('Use the central product management in the artidomo Portal under Shop Connections → Product Mapping.', 'artidomo-print-on-demand'); ?> 365 355 </p> 366 356 <a href="https://portal.artidomo.eu/shops" target="_blank" class="button button-secondary" style="width: 100%; text-align: center;"> 367 Zum Portal→357 <?php esc_html_e('Go to Portal', 'artidomo-print-on-demand'); ?> → 368 358 </a> 369 359 </div> … … 378 368 */ 379 369 public function enqueue_admin_assets($hook) { 380 // Nur auf relevanten Seiten381 370 if (!in_array($hook, array('post.php', 'post-new.php', 'edit.php', 'woocommerce_page_artidomo-connection', 'woocommerce_page_artidomo-csv'))) { 382 371 return; 383 372 } 384 373 385 // Inline CSS386 374 wp_add_inline_style('wp-admin', ' 387 375 .artidomo-variation-fields input[type="text"], -
artidomo-print-on-demand/trunk/artidomo-print.php
r3430729 r3431054 67 67 <div class="notice notice-error"> 68 68 <p> 69 <strong>artidomo Print on Demand</strong> benötigt WooCommerce.70 Bitte installiere und aktiviere <a href="<?php echo admin_url('plugin-install.php?s=woocommerce&tab=search&type=term'); ?>">WooCommerce</a> zuerst.69 <strong>artidomo Print on Demand</strong> <?php esc_html_e('requires WooCommerce. Please install and activate', 'artidomo-print-on-demand'); ?> 70 <a href="<?php echo esc_url(admin_url('plugin-install.php?s=woocommerce&tab=search&type=term')); ?>">WooCommerce</a> <?php esc_html_e('first.', 'artidomo-print-on-demand'); ?> 71 71 </p> 72 72 </div> … … 82 82 } 83 83 }); 84 85 /** 86 * Load plugin text domain for translations 87 */ 88 function artidomo_pod_load_textdomain() { 89 load_plugin_textdomain( 90 'artidomo-print-on-demand', 91 false, 92 dirname(ARTIDOMO_POD_PLUGIN_BASENAME) . '/languages' 93 ); 94 } 95 add_action('init', 'artidomo_pod_load_textdomain'); 84 96 85 97 /** … … 120 132 deactivate_plugins(ARTIDOMO_POD_PLUGIN_BASENAME); 121 133 wp_die( 122 'artidomo Print on Demand benötigt WooCommerce. Bitte installiere WooCommerce zuerst.',123 'Plugin Activation Error',134 esc_html__('artidomo Print on Demand requires WooCommerce. Please install WooCommerce first.', 'artidomo-print-on-demand'), 135 esc_html__('Plugin Activation Error', 'artidomo-print-on-demand'), 124 136 array('back_link' => true) 125 137 ); -
artidomo-print-on-demand/trunk/includes/class-one-click-connect.php
r3430729 r3431054 2 2 /** 3 3 * One-Click Connect Class 4 * Implement iert Token-basierte Verbindung zwischen WooCommerce Shop und artidomo Backend4 * Implements token-based connection between WooCommerce Shop and artidomo Backend 5 5 */ 6 6 … … 17 17 $instance = new self(); 18 18 19 // REST API Endpoint f ür Connection Callback19 // REST API Endpoint for Connection Callback 20 20 add_action('rest_api_init', array($instance, 'register_rest_routes')); 21 21 22 // Admin Menu f ür manuelle Verbindung22 // Admin Menu for manual connection 23 23 add_action('admin_menu', array($instance, 'add_connection_page')); 24 24 add_action('admin_menu', array($instance, 'add_all_mappings_page')); 25 25 26 // AJAX Handler f ür Token-Validierung26 // AJAX Handler for Token Validation 27 27 add_action('wp_ajax_artidomo_validate_token', array($instance, 'ajax_validate_token')); 28 28 29 // Admin Post Handler f ür Disconnect (Form Submission)29 // Admin Post Handler for Disconnect (Form Submission) 30 30 add_action('admin_post_artidomo_disconnect', array($instance, 'admin_post_disconnect')); 31 31 } 32 32 33 33 /** 34 * Regist riere REST API Routes für One-Click Connect34 * Register REST API Routes for One-Click Connect 35 35 */ 36 36 public function register_rest_routes() { … … 55 55 56 56 /** 57 * Verif iziere Connect Request Signatur57 * Verify Connect Request Signature 58 58 */ 59 59 public function verify_connect_signature($request) { … … 63 63 return new WP_Error( 64 64 'missing_token', 65 'Token fehlt',65 __('Token missing', 'artidomo-print-on-demand'), 66 66 array('status' => 400) 67 67 ); 68 68 } 69 69 70 // Token wird vom Backend signiert - validiere überBackend API71 return true; // Backend valid iert imhandle_connect_request72 } 73 74 /** 75 * Verif iziereDisconnect Permission70 // Token is signed by backend - validate via Backend API 71 return true; // Backend validates in handle_connect_request 72 } 73 74 /** 75 * Verify Disconnect Permission 76 76 */ 77 77 public function verify_disconnect_permission($request) { … … 80 80 81 81 /** 82 * Handle Connection Request vom artidomo Backend82 * Handle Connection Request from artidomo Backend 83 83 */ 84 84 public function handle_connect_request($request) { … … 88 88 return new WP_Error( 89 89 'missing_token', 90 'Token fehlt',90 __('Token missing', 'artidomo-print-on-demand'), 91 91 array('status' => 400) 92 92 ); 93 93 } 94 94 95 // Valid iere Token überBackend API95 // Validate Token via Backend API 96 96 $response = wp_remote_post(ARTIDOMO_API_URL . '/woocommerce/validate-connection-token', array( 97 97 'headers' => array('Content-Type' => 'application/json'), … … 106 106 return new WP_Error( 107 107 'api_error', 108 'Verbindung zum artidomo Backend fehlgeschlagen: ' . $response->get_error_message(), 108 /* translators: %s: error message */ 109 sprintf(__('Connection to artidomo backend failed: %s', 'artidomo-print-on-demand'), $response->get_error_message()), 109 110 array('status' => 500) 110 111 ); … … 117 118 return new WP_Error( 118 119 'invalid_token', 119 $body['error'] ?? 'Token ungültig oder abgelaufen',120 $body['error'] ?? __('Token invalid or expired', 'artidomo-print-on-demand'), 120 121 array('status' => 401) 121 122 ); 122 123 } 123 124 124 // ✨ NEUE LOGIK: Generiere WooCommerce REST API Keys lokal im Shop125 // Generate WooCommerce REST API Keys locally in the shop 125 126 $api_keys = $this->create_woocommerce_api_keys(); 126 127 127 128 if (is_wp_error($api_keys)) { 128 return $api_keys; // Fehler zurückgeben129 } 130 131 // Gener iere Webhook Secret129 return $api_keys; // Return error 130 } 131 132 // Generate Webhook Secret 132 133 $webhook_secret = wp_generate_password(32, false); 133 134 134 // ✨ Sende Credentials AN das Backend (nicht umgekehrt!)135 // Send Credentials TO the Backend (not the other way around!) 135 136 $credentials_response = wp_remote_post(ARTIDOMO_API_URL . '/woocommerce/exchange-token', array( 136 137 'headers' => array('Content-Type' => 'application/json'), … … 138 139 'token' => $token, 139 140 'shop_url' => get_site_url(), 140 'consumer_key' => $api_keys['consumer_key'], // ✅ JETZT MITGESENDET!141 'consumer_secret' => $api_keys['consumer_secret'], // ✅ JETZT MITGESENDET!141 'consumer_key' => $api_keys['consumer_key'], 142 'consumer_secret' => $api_keys['consumer_secret'], 142 143 'webhook_secret' => $webhook_secret 143 144 )), … … 148 149 return new WP_Error( 149 150 'backend_error', 150 'Fehler beim Speichern im Backend: ' . $credentials_response->get_error_message(), 151 /* translators: %s: error message */ 152 sprintf(__('Error saving to backend: %s', 'artidomo-print-on-demand'), $credentials_response->get_error_message()), 151 153 array('status' => 500) 152 154 ); … … 159 161 return new WP_Error( 160 162 'backend_failed', 161 $credentials_body['error'] ?? 'Backend konnte Shop nicht erstellen',163 $credentials_body['error'] ?? __('Backend could not create shop', 'artidomo-print-on-demand'), 162 164 array('status' => 500) 163 165 ); 164 166 } 165 167 166 // S peichere Credentials lokal168 // Save Credentials locally 167 169 update_option('artidomo_connected', true); 168 170 update_option('artidomo_shop_id', sanitize_text_field($credentials_body['shop_id'])); … … 173 175 update_option('artidomo_connected_at', current_time('mysql')); 174 176 175 // Regist riere Webhooks automatisch177 // Register Webhooks automatically 176 178 $this->register_webhooks($webhook_secret); 177 179 178 180 return rest_ensure_response(array( 179 181 'success' => true, 180 'message' => 'Verbindung erfolgreich hergestellt',182 'message' => __('Connection established successfully', 'artidomo-print-on-demand'), 181 183 'shop_url' => get_site_url(), 182 184 'connected_at' => current_time('mysql'), … … 185 187 186 188 /** 187 * Erstelle WooCommerce REST API Keys programmatisch189 * Create WooCommerce REST API Keys programmatically 188 190 */ 189 191 private function create_woocommerce_api_keys() { 190 192 global $wpdb; 191 193 192 // Prüfe ob WooCommerce aktiv ist194 // Check if WooCommerce is active 193 195 if (!class_exists('WooCommerce')) { 194 196 return new WP_Error( 195 197 'woocommerce_missing', 196 'WooCommerce ist nicht installiert oder aktiviert',198 __('WooCommerce is not installed or activated', 'artidomo-print-on-demand'), 197 199 array('status' => 500) 198 200 ); 199 201 } 200 202 201 // Hole Admin User ID (für REST API Calls ohne eingeloggten User)202 // get_current_user_id() is t 0 beiREST API Calls!203 // Get Admin User ID (for REST API Calls without logged in user) 204 // get_current_user_id() is 0 for REST API Calls! 203 205 $user_id = get_current_user_id(); 204 206 if ($user_id === 0) { 205 // Find e erstenAdministrator207 // Find first Administrator 206 208 $admin_users = get_users(array( 207 209 'role' => 'administrator', … … 214 216 return new WP_Error( 215 217 'no_admin_user', 216 'Kein Administrator-Account gefunden',218 __('No administrator account found', 'artidomo-print-on-demand'), 217 219 array('status' => 500) 218 220 ); … … 222 224 } 223 225 224 // Gener iere Consumer Key & Secret226 // Generate Consumer Key & Secret 225 227 $consumer_key = 'ck_' . wc_rand_hash(); 226 228 $consumer_secret = 'cs_' . wc_rand_hash(); 227 229 228 // Erstelle API Key in WooCommerce Datenbank230 // Create API Key in WooCommerce Database 229 231 $key_id = $wpdb->insert( 230 232 $wpdb->prefix . 'woocommerce_api_keys', … … 243 245 return new WP_Error( 244 246 'key_creation_failed', 245 'Fehler beim Erstellen der WooCommerce API Keys',247 __('Error creating WooCommerce API Keys', 'artidomo-print-on-demand'), 246 248 array('status' => 500) 247 249 ); … … 259 261 */ 260 262 public function handle_disconnect_request($request) { 261 // Lösche WooCommerce API Keys263 // Delete WooCommerce API Keys 262 264 $api_key_id = get_option('artidomo_api_key_id'); 263 265 if ($api_key_id) { … … 270 272 } 271 273 272 // Lösche alle gespeicherten Credentials274 // Delete all saved credentials 273 275 delete_option('artidomo_connected'); 274 276 delete_option('artidomo_shop_id'); … … 279 281 delete_option('artidomo_connected_at'); 280 282 281 // DeregistriereWebhooks283 // Unregister Webhooks 282 284 $this->unregister_webhooks(); 283 285 284 286 return rest_ensure_response(array( 285 287 'success' => true, 286 'message' => 'Verbindung getrennt und API Keys gelöscht',288 'message' => __('Connection disconnected and API Keys deleted', 'artidomo-print-on-demand'), 287 289 )); 288 290 } 289 291 290 292 /** 291 * Admin Post Handler f ür Disconnect (von Form aufgerufen)293 * Admin Post Handler for Disconnect (called from Form) 292 294 */ 293 295 public function admin_post_disconnect() { 294 // Nonce Prüfung296 // Nonce Check 295 297 if (!isset($_POST['_wpnonce']) || !wp_verify_nonce($_POST['_wpnonce'], 'artidomo_disconnect')) { 296 wp_die( 'Sicherheitsprüfung fehlgeschlagen');297 } 298 299 // Prüfe Berechtigung298 wp_die(esc_html__('Security check failed', 'artidomo-print-on-demand')); 299 } 300 301 // Check Permission 300 302 if (!current_user_can('manage_woocommerce')) { 301 wp_die( 'Keine Berechtigung');302 } 303 304 // Führe Disconnect-Logik aus303 wp_die(esc_html__('No permission', 'artidomo-print-on-demand')); 304 } 305 306 // Execute Disconnect Logic 305 307 $api_key_id = get_option('artidomo_api_key_id'); 306 308 if ($api_key_id) { … … 313 315 } 314 316 315 // Lösche alle gespeicherten Credentials317 // Delete all saved credentials 316 318 delete_option('artidomo_connected'); 317 319 delete_option('artidomo_shop_id'); … … 322 324 delete_option('artidomo_connected_at'); 323 325 324 // DeregistriereWebhooks326 // Unregister Webhooks 325 327 $this->unregister_webhooks(); 326 328 327 // Redirect zurück zur Connection Page mit Erfolgs-Meldung329 // Redirect back to Connection Page with success message 328 330 wp_redirect(add_query_arg( 329 331 array('page' => 'artidomo-connection', 'disconnected' => '1'), … … 350 352 351 353 /** 352 * Regist riereWooCommerce Webhooks354 * Register WooCommerce Webhooks 353 355 */ 354 356 private function register_webhooks($webhook_secret) { 355 // Prüfe ob WooCommerce aktiv ist357 // Check if WooCommerce is active 356 358 if (!function_exists('wc_get_webhook')) { 357 return new WP_Error('woocommerce_missing', 'WooCommerce nicht gefunden');359 return new WP_Error('woocommerce_missing', __('WooCommerce not found', 'artidomo-print-on-demand')); 358 360 } 359 361 360 362 $webhook_url = ARTIDOMO_API_URL . '/webhooks/woocommerce/order-updated'; 361 363 362 // Erstelle Order Updated Webhook364 // Create Order Updated Webhook 363 365 $webhook = new WC_Webhook(); 364 366 $webhook->set_name('artidomo Order Updated'); … … 375 377 376 378 /** 377 * DeregistriereWooCommerce Webhooks379 * Unregister WooCommerce Webhooks 378 380 */ 379 381 private function unregister_webhooks() { … … 391 393 392 394 /** 393 * Füge Connection Page zum Admin Menu hinzu395 * Add Connection Page to Admin Menu 394 396 */ 395 397 public function add_connection_page() { 396 398 add_submenu_page( 397 399 'woocommerce', 398 'artidomo Verbindung',400 __('artidomo Connection', 'artidomo-print-on-demand'), 399 401 'artidomo', 400 402 'manage_woocommerce', … … 414 416 // Format connected_at for display 415 417 if ($connected_at) { 416 $connected_at_display = date ('d.m.Y H:i', strtotime($connected_at));418 $connected_at_display = date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($connected_at)); 417 419 } else { 418 $connected_at_display = 'Unbekannt';420 $connected_at_display = __('Unknown', 'artidomo-print-on-demand'); 419 421 } 420 422 … … 437 439 ?> 438 440 <div class="notice notice-success is-dismissible"> 439 <p><strong>✅ Update-Prüfung durchgeführt!</strong></p> 440 <p>WordPress wurde über verfügbare Updates informiert. Gehe zu <a href="<?php echo admin_url('plugins.php'); ?>">Plugins</a> um Updates zu installieren.</p> 441 <p><strong>✅ <?php esc_html_e('Update check completed!', 'artidomo-print-on-demand'); ?></strong></p> 442 <p><?php 443 /* translators: %s: URL to plugins page */ 444 printf( 445 esc_html__('WordPress has been notified about available updates. Go to %s to install updates.', 'artidomo-print-on-demand'), 446 '<a href="' . esc_url(admin_url('plugins.php')) . '">' . esc_html__('Plugins', 'artidomo-print-on-demand') . '</a>' 447 ); 448 ?></p> 441 449 </div> 442 450 <?php … … 447 455 ?> 448 456 <div class="notice notice-success is-dismissible"> 449 <p><strong>✅ Verbindung erfolgreich getrennt!</strong></p>450 <p> API Keys wurden gelöscht und Webhooks deregistriert.</p>457 <p><strong>✅ <?php esc_html_e('Connection successfully disconnected!', 'artidomo-print-on-demand'); ?></strong></p> 458 <p><?php esc_html_e('API Keys have been deleted and Webhooks unregistered.', 'artidomo-print-on-demand'); ?></p> 451 459 </div> 452 460 <?php … … 459 467 ?> 460 468 <div class="notice notice-success is-dismissible"> 461 <p><strong>✅ Import erfolgreich!</strong></p> 462 <p><?php echo $imported; ?> Produkte importiert. 463 <?php if ($errors > 0): ?> 464 (<?php echo $errors; ?> Fehler) 465 <?php endif; ?> 466 </p> 469 <p><strong>✅ <?php esc_html_e('Import successful!', 'artidomo-print-on-demand'); ?></strong></p> 470 <p><?php 471 /* translators: %d: number of products imported */ 472 printf(esc_html__('%d products imported.', 'artidomo-print-on-demand'), $imported); 473 if ($errors > 0) { 474 /* translators: %d: number of errors */ 475 printf(' (' . esc_html__('%d errors', 'artidomo-print-on-demand') . ')', $errors); 476 } 477 ?></p> 467 478 </div> 468 479 <?php … … 524 535 <div style="display: flex; align-items: center; gap: 16px;"> 525 536 <img src="https://portal.artidomo.eu/artidomo400px.png" alt="artidomo Logo" style="height: 48px;"> 526 <h1 style="margin: 0;"> Fulfillment Verbindung</h1>537 <h1 style="margin: 0;"><?php esc_html_e('Fulfillment Connection', 'artidomo-print-on-demand'); ?></h1> 527 538 </div> 528 <a href="<?php echo add_query_arg('force_update_check', '1'); ?>" class="button button-secondary">529 🔄 Nach Plugin-Updates suchen539 <a href="<?php echo esc_url(add_query_arg('force_update_check', '1')); ?>" class="button button-secondary"> 540 🔄 <?php esc_html_e('Check for Plugin Updates', 'artidomo-print-on-demand'); ?> 530 541 </a> 531 542 </div> … … 533 544 <div class="artidomo-grid"> 534 545 <?php if (!$is_connected): ?> 535 <!-- Connection Status Card (n icht verbunden) -->546 <!-- Connection Status Card (not connected) --> 536 547 <div class="artidomo-card"> 537 <h3>🔗 Verbindungsstatus</h3>548 <h3>🔗 <?php esc_html_e('Connection Status', 'artidomo-print-on-demand'); ?></h3> 538 549 <div class="artidomo-card-content"> 539 550 <div style="text-align: center; padding: 20px 0;"> 540 551 <div style="font-size: 48px; margin-bottom: 16px;">🔌</div> 541 <span class="artidomo-badge badge-info" style="font-size: 14px; padding: 8px 16px;"> Noch nicht verbunden</span>552 <span class="artidomo-badge badge-info" style="font-size: 14px; padding: 8px 16px;"><?php esc_html_e('Not yet connected', 'artidomo-print-on-demand'); ?></span> 542 553 <p style="margin-top: 16px; color: #666; font-size: 14px;"> 543 Um deinen WooCommerce Shop mit artidomo zu verbinden, gehe zu deinem artidomo Portal und wähle "Shop hinzufügen".554 <?php esc_html_e('To connect your WooCommerce shop with artidomo, go to your artidomo Portal and select "Add Shop".', 'artidomo-print-on-demand'); ?> 544 555 </p> 545 556 </div> … … 547 558 </div> 548 559 549 <!-- DatenschutzCard -->560 <!-- Privacy Card --> 550 561 <div class="artidomo-card" style="border-left: 4px solid #ff9800;"> 551 <h3>🔐 Datenschutz-Hinweis</h3>562 <h3>🔐 <?php esc_html_e('Privacy Notice', 'artidomo-print-on-demand'); ?></h3> 552 563 <div class="artidomo-card-content"> 553 <p><strong> Durch die Verbindung mit artidomo werden folgende Daten an portal.artidomo.eu übermittelt:</strong></p>564 <p><strong><?php esc_html_e('By connecting to artidomo, the following data will be transmitted to portal.artidomo.eu:', 'artidomo-print-on-demand'); ?></strong></p> 554 565 <ul style="list-style: disc; margin-left: 20px; margin-top: 12px;"> 555 <li> WooCommerce REST API Zugangsdaten (Consumer Key & Consumer Secret)</li>556 <li> Shop-URL und Bestelldaten</li>557 <li> Produktinformationen und Personalisierungsdaten</li>566 <li><?php esc_html_e('WooCommerce REST API credentials (Consumer Key & Consumer Secret)', 'artidomo-print-on-demand'); ?></li> 567 <li><?php esc_html_e('Shop URL and order data', 'artidomo-print-on-demand'); ?></li> 568 <li><?php esc_html_e('Product information and personalization data', 'artidomo-print-on-demand'); ?></li> 558 569 </ul> 559 <p style="margin-top: 16px;"><strong> Diese Verbindung ist nur möglich wenn:</strong></p>570 <p style="margin-top: 16px;"><strong><?php esc_html_e('This connection is only possible if:', 'artidomo-print-on-demand'); ?></strong></p> 560 571 <ul style="list-style: disc; margin-left: 20px; margin-top: 12px;"> 561 <li> Ein aktiver Vertrag mit artidomo besteht</li>562 <li> Die Auftragsverarbeitungsvereinbarung (ADV) unterzeichnet wurde</li>572 <li><?php esc_html_e('An active contract with artidomo exists', 'artidomo-print-on-demand'); ?></li> 573 <li><?php esc_html_e('The Data Processing Agreement (DPA) has been signed', 'artidomo-print-on-demand'); ?></li> 563 574 </ul> 564 575 <p style="margin-top: auto; padding: 12px; background: #fff3cd; border-radius: 4px; font-size: 13px;"> 565 Die Daten werden ausschließlich zur Abwicklung Ihrer Druckaufträge verwendet.<br> 566 Bei Fragen kontaktieren Sie bitte: <a href="mailto:[email protected]">[email protected]</a> 576 <?php esc_html_e('The data is used exclusively for processing your print orders.', 'artidomo-print-on-demand'); ?><br> 577 <?php 578 /* translators: %s: support email address */ 579 printf(esc_html__('For questions, please contact: %s', 'artidomo-print-on-demand'), '<a href="mailto:[email protected]">[email protected]</a>'); 580 ?> 567 581 </p> 568 582 </div> … … 571 585 <!-- Token Input Card --> 572 586 <div class="artidomo-card" style="border-left: 4px solid #3c8735;"> 573 <h3>🔑 Manuelle Verbindung via Token</h3>587 <h3>🔑 <?php esc_html_e('Manual Connection via Token', 'artidomo-print-on-demand'); ?></h3> 574 588 <div class="artidomo-card-content"> 575 <p style="margin-bottom: 16px;"> Falls du einen Connection Token hast, kannst du ihn hier eingeben:</p>589 <p style="margin-bottom: 16px;"><?php esc_html_e('If you have a connection token, you can enter it here:', 'artidomo-print-on-demand'); ?></p> 576 590 577 591 <?php if ($portal_token): ?> 578 592 <div style="background: #d4edda; padding: 12px; border-radius: 4px; margin-bottom: 16px;"> 579 <strong>✓ Token automatisch aus dem Portal übernommen</strong>593 <strong>✓ <?php esc_html_e('Token automatically received from Portal', 'artidomo-print-on-demand'); ?></strong> 580 594 </div> 581 595 <?php endif; ?> … … 585 599 <input type="text" 586 600 id="artidomo-token" 587 placeholder=" Token hier einfügen"601 placeholder="<?php esc_attr_e('Paste token here', 'artidomo-print-on-demand'); ?>" 588 602 value="<?php echo esc_attr($portal_token); ?>" 589 603 style="width: 100%; padding: 10px; font-family: monospace; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 12px;"> 590 604 <button type="submit" class="button button-primary" style="width: 100%; padding: 10px; font-size: 14px;"> 591 🔗 Verbinden605 🔗 <?php esc_html_e('Connect', 'artidomo-print-on-demand'); ?> 592 606 </button> 593 607 </form> … … 597 611 </div> 598 612 599 <!-- German ized und German Market Erkennung-->613 <!-- German Market / Germanized Detection --> 600 614 <div class="artidomo-card"> 601 <h3>🔌 Germanized und German Market Erkennung</h3>615 <h3>🔌 <?php esc_html_e('German Market & Germanized Detection', 'artidomo-print-on-demand'); ?></h3> 602 616 <div class="artidomo-card-content"> 603 617 <?php if (!empty($detected_plugins)): ?> … … 605 619 <div style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px;"> 606 620 <span class="artidomo-badge badge-success">✓ <?php echo esc_html($plugin['name']); ?></span> 607 <span style="color: #666; font-size: 12px;">(Version: <?php echo esc_html($plugin['version']); ?>)</span> 621 <span style="color: #666; font-size: 12px;">(<?php 622 /* translators: %s: plugin version number */ 623 printf(esc_html__('Version: %s', 'artidomo-print-on-demand'), esc_html($plugin['version'])); 624 ?>)</span> 608 625 </div> 609 626 <?php endforeach; ?> … … 611 628 <div style="margin-top: 16px; padding: 12px; background: #fff3cd; border-left: 4px solid #ffc107; border-radius: 4px;"> 612 629 <p style="margin: 0; font-size: 13px; color: #856404;"> 613 <strong>⚠️ Wichtig:</strong> <?php echo esc_html($detected_plugins[0]['name']); ?> ändert den Status "Bezahlt" anders als Standard-WooCommerce.630 <strong>⚠️ <?php esc_html_e('Important:', 'artidomo-print-on-demand'); ?></strong> <?php echo esc_html($detected_plugins[0]['name']); ?> <?php esc_html_e('changes the "Paid" status differently than standard WooCommerce.', 'artidomo-print-on-demand'); ?> 614 631 </p> 615 632 <p style="margin: 8px 0 0 0; font-size: 12px; color: #856404;"> 616 <strong> Nur Bestellungen die als "Bezahlt" markiert sind werden zu artidomo übertragen.</strong> Dies gewährleistet, dass nur tatsächlich bezahlte Bestellungen produziert werden.633 <strong><?php esc_html_e('Only orders marked as "Paid" will be transferred to artidomo.', 'artidomo-print-on-demand'); ?></strong> <?php esc_html_e('This ensures that only actually paid orders are produced.', 'artidomo-print-on-demand'); ?> 617 634 </p> 618 635 </div> 619 636 620 637 <p style="margin-top: 12px; color: #666; font-size: 13px;"> 621 <em> Diese Informationen werden automatisch an das artidomo Backend übermittelt für optimale Bestellverarbeitung.</em>638 <em><?php esc_html_e('This information is automatically sent to the artidomo backend for optimal order processing.', 'artidomo-print-on-demand'); ?></em> 622 639 </p> 623 640 <?php else: ?> 624 <p style="color: #666; font-size: 13px;"> Keine German Market oder Germanized Plugins erkannt.</p>641 <p style="color: #666; font-size: 13px;"><?php esc_html_e('No German Market or Germanized plugins detected.', 'artidomo-print-on-demand'); ?></p> 625 642 <div style="margin-top: 12px; padding: 12px; background: #d1ecf1; border-left: 4px solid #0c5460; border-radius: 4px;"> 626 643 <p style="margin: 0; font-size: 12px; color: #0c5460;"> 627 <strong> Standard-WooCommerce:</strong> Nur Bestellungen die als "Bezahlt" markiert sind werden zu artidomo übertragen.644 <strong><?php esc_html_e('Standard WooCommerce:', 'artidomo-print-on-demand'); ?></strong> <?php esc_html_e('Only orders marked as "Paid" will be transferred to artidomo.', 'artidomo-print-on-demand'); ?> 628 645 </p> 629 646 </div> … … 632 649 </div> 633 650 <?php else: ?> 634 <!-- Zuordnungs-StatistikCard -->651 <!-- Product Mapping Statistics Card --> 635 652 <?php 636 653 $stats = Artidomo_CSV_Handler::get_statistics(); 637 654 ?> 638 655 <div class="artidomo-card" style="border-left: 4px solid #3c8735;"> 639 <h3>📊 Produktzuordnungs-Statistik</h3>656 <h3>📊 <?php esc_html_e('Product Mapping Statistics', 'artidomo-print-on-demand'); ?></h3> 640 657 <div class="artidomo-card-content"> 641 658 <div style="display: flex; gap: 24px; justify-content: space-around; padding: 20px 0;"> 642 659 <div style="text-align: center;"> 643 <div style="font-size: 36px; font-weight: 700; color: #3c8735;"><?php echo $stats['total_mapped']; ?></div>644 <div style="color: #666; font-size: 13px; margin-top: 8px;"> Produkte mit SKU</div>660 <div style="font-size: 36px; font-weight: 700; color: #3c8735;"><?php echo esc_html($stats['total_mapped']); ?></div> 661 <div style="color: #666; font-size: 13px; margin-top: 8px;"><?php esc_html_e('Products with SKU', 'artidomo-print-on-demand'); ?></div> 645 662 </div> 646 663 <div style="text-align: center;"> 647 <div style="font-size: 36px; font-weight: 700; color: #3c8735;"><?php echo $stats['with_printfile']; ?></div>648 <div style="color: #666; font-size: 13px; margin-top: 8px;"> mit Druckdatei</div>664 <div style="font-size: 36px; font-weight: 700; color: #3c8735;"><?php echo esc_html($stats['with_printfile']); ?></div> 665 <div style="color: #666; font-size: 13px; margin-top: 8px;"><?php esc_html_e('with print file', 'artidomo-print-on-demand'); ?></div> 649 666 </div> 650 667 </div> 651 668 <div style="margin-top: auto; text-align: center;"> 652 <a href="<?php echo admin_url('admin.php?page=artidomo-all-mappings'); ?>" class="button button-primary" style="width: 100%;">653 Alle Zuordnungen anzeigen669 <a href="<?php echo esc_url(admin_url('admin.php?page=artidomo-all-mappings')); ?>" class="button button-primary" style="width: 100%;"> 670 <?php esc_html_e('Show all mappings', 'artidomo-print-on-demand'); ?> 654 671 </a> 655 672 </div> … … 657 674 </div> 658 675 659 <!-- Connection Status Card ( verbunden) -->676 <!-- Connection Status Card (connected) --> 660 677 <div class="artidomo-card"> 661 <h3>🔗 Verbindungsstatus</h3>678 <h3>🔗 <?php esc_html_e('Connection Status', 'artidomo-print-on-demand'); ?></h3> 662 679 <div class="artidomo-card-content"> 663 680 <div style="text-align: center; padding: 20px 0;"> 664 681 <div style="font-size: 48px; margin-bottom: 16px;">✅</div> 665 <span class="artidomo-badge badge-success" style="font-size: 14px; padding: 8px 16px;"> Verbunden</span>682 <span class="artidomo-badge badge-success" style="font-size: 14px; padding: 8px 16px;"><?php esc_html_e('Connected', 'artidomo-print-on-demand'); ?></span> 666 683 <p style="margin-top: 16px; color: #666;"> 667 Webhooks aktiv und<br>668 API Keys konfiguriert684 <?php esc_html_e('Webhooks active and', 'artidomo-print-on-demand'); ?><br> 685 <?php esc_html_e('API Keys configured', 'artidomo-print-on-demand'); ?> 669 686 </p> 670 687 <p style="color: #888; font-size: 12px; margin-top: 8px;"> 671 Verbunden seit: <?php echo esc_html($connected_at_display); ?> 688 <?php 689 /* translators: %s: connection date */ 690 printf(esc_html__('Connected since: %s', 'artidomo-print-on-demand'), esc_html($connected_at_display)); 691 ?> 672 692 </p> 673 693 </div> 674 <form method="post" action="<?php echo admin_url('admin-post.php'); ?>" style="text-align: center; margin-top: auto;">694 <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" style="text-align: center; margin-top: auto;"> 675 695 <?php wp_nonce_field('artidomo_disconnect'); ?> 676 696 <input type="hidden" name="action" value="artidomo_disconnect"> 677 697 <button type="submit" class="button button-secondary" style="width: 100%;"> 678 Verbindung trennen698 <?php esc_html_e('Disconnect', 'artidomo-print-on-demand'); ?> 679 699 </button> 680 700 </form> … … 682 702 </div> 683 703 684 <!-- German ized und German Market Erkennung-->704 <!-- German Market / Germanized Detection (connected) --> 685 705 <div class="artidomo-card"> 686 <h3>🔌 Germanized und German Market Erkennung</h3>706 <h3>🔌 <?php esc_html_e('German Market & Germanized Detection', 'artidomo-print-on-demand'); ?></h3> 687 707 <div class="artidomo-card-content"> 688 708 <?php if (!empty($detected_plugins)): ?> … … 690 710 <div style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px;"> 691 711 <span class="artidomo-badge badge-success">✓ <?php echo esc_html($plugin['name']); ?></span> 692 <span style="color: #666; font-size: 12px;">(Version: <?php echo esc_html($plugin['version']); ?>)</span> 712 <span style="color: #666; font-size: 12px;">(<?php 713 /* translators: %s: plugin version number */ 714 printf(esc_html__('Version: %s', 'artidomo-print-on-demand'), esc_html($plugin['version'])); 715 ?>)</span> 693 716 </div> 694 717 <?php endforeach; ?> … … 696 719 <div style="margin-top: 16px; padding: 12px; background: #fff3cd; border-left: 4px solid #ffc107; border-radius: 4px;"> 697 720 <p style="margin: 0; font-size: 13px; color: #856404;"> 698 <strong>⚠️ Wichtig:</strong> <?php echo esc_html($detected_plugins[0]['name']); ?> ändert den Status "Bezahlt" anders als Standard-WooCommerce.721 <strong>⚠️ <?php esc_html_e('Important:', 'artidomo-print-on-demand'); ?></strong> <?php echo esc_html($detected_plugins[0]['name']); ?> <?php esc_html_e('changes the "Paid" status differently than standard WooCommerce.', 'artidomo-print-on-demand'); ?> 699 722 </p> 700 723 <p style="margin: 8px 0 0 0; font-size: 12px; color: #856404;"> 701 <strong> Nur Bestellungen die als "Bezahlt" markiert sind werden zu artidomo übertragen.</strong> Dies gewährleistet, dass nur tatsächlich bezahlte Bestellungen produziert werden.724 <strong><?php esc_html_e('Only orders marked as "Paid" will be transferred to artidomo.', 'artidomo-print-on-demand'); ?></strong> <?php esc_html_e('This ensures that only actually paid orders are produced.', 'artidomo-print-on-demand'); ?> 702 725 </p> 703 726 </div> 704 727 705 728 <p style="margin-top: 12px; color: #666; font-size: 13px;"> 706 <em> Diese Informationen werden automatisch an das artidomo Backend übermittelt für optimale Bestellverarbeitung.</em>729 <em><?php esc_html_e('This information is automatically sent to the artidomo backend for optimal order processing.', 'artidomo-print-on-demand'); ?></em> 707 730 </p> 708 731 <?php else: ?> 709 <p style="color: #666; font-size: 13px;"> Keine German Market oder Germanized Plugins erkannt.</p>732 <p style="color: #666; font-size: 13px;"><?php esc_html_e('No German Market or Germanized plugins detected.', 'artidomo-print-on-demand'); ?></p> 710 733 <div style="margin-top: 12px; padding: 12px; background: #d1ecf1; border-left: 4px solid #0c5460; border-radius: 4px;"> 711 734 <p style="margin: 0; font-size: 12px; color: #0c5460;"> 712 <strong> Standard-WooCommerce:</strong> Nur Bestellungen die als "Bezahlt" markiert sind werden zu artidomo übertragen.735 <strong><?php esc_html_e('Standard WooCommerce:', 'artidomo-print-on-demand'); ?></strong> <?php esc_html_e('Only orders marked as "Paid" will be transferred to artidomo.', 'artidomo-print-on-demand'); ?> 713 736 </p> 714 737 </div> … … 719 742 <!-- CSV Export Box --> 720 743 <div class="artidomo-card"> 721 <h3>📤 CSV Export</h3>744 <h3>📤 <?php esc_html_e('CSV Export', 'artidomo-print-on-demand'); ?></h3> 722 745 <div class="artidomo-card-content"> 723 746 <p style="color: #666; font-size: 13px; margin-bottom: 16px;"> 724 Exportiere alle Produktzuordnungen als CSV-Datei mit artidomo SKU, Druckdateien und Personalisierungs-Einstellungen.747 <?php esc_html_e('Export all product mappings as CSV file with artidomo SKU, print files, and personalization settings.', 'artidomo-print-on-demand'); ?> 725 748 </p> 726 749 727 <form method="post" action="<?php echo admin_url('admin-post.php'); ?>" style="margin-top: auto;">750 <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" style="margin-top: auto;"> 728 751 <?php wp_nonce_field('artidomo_export_csv'); ?> 729 752 <input type="hidden" name="action" value="artidomo_export_csv"> … … 732 755 style="width: 100%; padding: 10px; background: #28a745; border-color: #28a745;" 733 756 <?php if ($stats['total_mapped'] === 0) echo 'disabled'; ?>> 734 📥 CSV exportieren (<?php echo $stats['total_mapped']; ?> Produkte) 757 📥 <?php 758 /* translators: %d: number of products */ 759 printf(esc_html__('Export CSV (%d products)', 'artidomo-print-on-demand'), $stats['total_mapped']); 760 ?> 735 761 </button> 736 762 </form> … … 740 766 <!-- CSV Import Box --> 741 767 <div class="artidomo-card"> 742 <h3>📥 CSV Import</h3>768 <h3>📥 <?php esc_html_e('CSV Import', 'artidomo-print-on-demand'); ?></h3> 743 769 <div class="artidomo-card-content"> 744 770 <p style="color: #666; font-size: 13px; margin-bottom: 12px;"> 745 Importiere Produktzuordnungen aus einer CSV-Datei.771 <?php esc_html_e('Import product mappings from a CSV file.', 'artidomo-print-on-demand'); ?> 746 772 </p> 747 773 748 774 <details style="margin-bottom: 12px;"> 749 775 <summary style="cursor: pointer; color: #2271b1; font-size: 12px; font-weight: 600;"> 750 ℹ️ CSV Format-Anforderungen776 ℹ️ <?php esc_html_e('CSV Format Requirements', 'artidomo-print-on-demand'); ?> 751 777 </summary> 752 778 <ul style="list-style: disc; margin: 8px 0 0 20px; font-size: 11px; color: #666;"> 753 <li> Semikolon-getrennt (;)</li>754 <li> UTF-8 Kodierung</li>755 <li> Header-Zeile erforderlich</li>756 <li> Spalten: Produkt ID, Varianten ID, Produktname, Variantenname, WooCommerce SKU, artidomo SKU, Druckdatei, Dateiquelle</li>779 <li><?php esc_html_e('Semicolon-separated (;)', 'artidomo-print-on-demand'); ?></li> 780 <li><?php esc_html_e('UTF-8 encoding', 'artidomo-print-on-demand'); ?></li> 781 <li><?php esc_html_e('Header row required', 'artidomo-print-on-demand'); ?></li> 782 <li><?php esc_html_e('Columns: Product ID, Variation ID, Product Name, Variation Name, WooCommerce SKU, artidomo SKU, Print File, File Source', 'artidomo-print-on-demand'); ?></li> 757 783 </ul> 758 784 </details> 759 785 760 786 <form method="post" 761 action="<?php echo admin_url('admin-post.php'); ?>"787 action="<?php echo esc_url(admin_url('admin-post.php')); ?>" 762 788 enctype="multipart/form-data" 763 789 style="margin-top: auto;"> … … 766 792 <input type="file" name="csv_file" accept=".csv" required style="width: 100%; margin-bottom: 8px;"> 767 793 <button type="submit" class="button button-primary" style="width: 100%; padding: 10px; background: #2271b1; border-color: #2271b1;"> 768 📤 CSV importieren794 📤 <?php esc_html_e('Import CSV', 'artidomo-print-on-demand'); ?> 769 795 </button> 770 796 </form> 771 797 772 798 <div style="margin-top: 12px; padding: 12px; background: #fff3cd; border-left: 4px solid #ffc107; border-radius: 4px; font-size: 12px;"> 773 <strong>💡 Tipp:</strong> Exportiere zuerst eine CSV um das Format zu sehen.799 <strong>💡 <?php esc_html_e('Tip:', 'artidomo-print-on-demand'); ?></strong> <?php esc_html_e('Export a CSV first to see the format.', 'artidomo-print-on-demand'); ?> 774 800 </div> 775 801 </div> … … 783 809 <?php endif; ?> 784 810 785 <!-- Impr essum-->811 <!-- Imprint --> 786 812 <div style="margin-top: 40px; padding: 24px; background: #f9f9f9; border-top: 3px solid #3c8735; border-radius: 8px;"> 787 <h3 style="margin-top: 0; color: #3c8735;">📄 Impressum</h3>813 <h3 style="margin-top: 0; color: #3c8735;">📄 <?php esc_html_e('Imprint', 'artidomo-print-on-demand'); ?></h3> 788 814 <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 24px;"> 789 815 <div> 790 816 <p style="margin: 0 0 8px 0;"><strong>artidomo</strong></p> 791 <p style="margin: 0; color: #666;"> Inhaberin: Marina Scheubly</p>817 <p style="margin: 0; color: #666;"><?php esc_html_e('Owner: Marina Scheubly', 'artidomo-print-on-demand'); ?></p> 792 818 <p style="margin: 4px 0 0 0; color: #666;"> 793 819 Wittener Str. 75<br> 794 820 44789 Bochum<br> 795 Deutschland821 <?php esc_html_e('Germany', 'artidomo-print-on-demand'); ?> 796 822 </p> 797 823 </div> 798 824 <div> 799 <p style="margin: 0 0 8px 0;"><strong> Kontakt</strong></p>825 <p style="margin: 0 0 8px 0;"><strong><?php esc_html_e('Contact', 'artidomo-print-on-demand'); ?></strong></p> 800 826 <p style="margin: 0; color: #666;"> 801 Tel:+49-(0)234-52009829<br>802 E-Mail:<a href="mailto:[email protected]">[email protected]</a><br>803 Web:<a href="https://www.artidomo.eu" target="_blank">www.artidomo.eu</a>827 <?php esc_html_e('Phone:', 'artidomo-print-on-demand'); ?> +49-(0)234-52009829<br> 828 <?php esc_html_e('Email:', 'artidomo-print-on-demand'); ?> <a href="mailto:[email protected]">[email protected]</a><br> 829 <?php esc_html_e('Web:', 'artidomo-print-on-demand'); ?> <a href="https://www.artidomo.eu" target="_blank">www.artidomo.eu</a> 804 830 </p> 805 831 </div> 806 832 <div> 807 <p style="margin: 0 0 8px 0;"><strong> Rechtliches</strong></p>833 <p style="margin: 0 0 8px 0;"><strong><?php esc_html_e('Legal', 'artidomo-print-on-demand'); ?></strong></p> 808 834 <p style="margin: 0; color: #666;"> 809 USt-ID:DE304587715835 <?php esc_html_e('VAT ID:', 'artidomo-print-on-demand'); ?> DE304587715 810 836 </p> 811 837 </div> 812 838 </div> 813 839 <p style="margin-top: 16px; font-size: 12px; color: #888; border-top: 1px solid #ddd; padding-top: 16px;"> 814 artidomo ist eine eingetragene Wort- und Bildmarke.840 <?php esc_html_e('artidomo is a registered word and image mark.', 'artidomo-print-on-demand'); ?> 815 841 </p> 816 842 </div> … … 819 845 <script> 820 846 jQuery(document).ready(function($) { 821 // Auto-submit w enn Token aus URL kommt (nach 2 Sekunden)847 // Auto-submit when Token comes from URL (after 2 seconds) 822 848 <?php if ($portal_token): ?> 823 849 setTimeout(function() { 824 if (confirm(' Token aus Portal erkannt. Jetzt verbinden?')) {850 if (confirm('<?php echo esc_js(__('Token from Portal detected. Connect now?', 'artidomo-print-on-demand')); ?>')) { 825 851 $('#artidomo-manual-connect-form').submit(); 826 852 } … … 833 859 var token = $('#artidomo-token').val(); 834 860 if (!token) { 835 alert(' Bitte Token eingeben');861 alert('<?php echo esc_js(__('Please enter a token', 'artidomo-print-on-demand')); ?>'); 836 862 return; 837 863 } 838 864 839 $('#artidomo-connect-result').html('<p style="text-align: center; padding: 12px; background: #fff3cd; border-radius: 4px;">🔄 Verbinde mit artidomo...</p>');865 $('#artidomo-connect-result').html('<p style="text-align: center; padding: 12px; background: #fff3cd; border-radius: 4px;">🔄 <?php echo esc_js(__('Connecting to artidomo...', 'artidomo-print-on-demand')); ?></p>'); 840 866 841 867 $.ajax({ 842 url: '<?php echo rest_url('artidomo/v1/connect'); ?>',868 url: '<?php echo esc_url(rest_url('artidomo/v1/connect')); ?>', 843 869 method: 'POST', 844 870 data: JSON.stringify({ token: token }), … … 853 879 }, 854 880 error: function(xhr) { 855 var error = xhr.responseJSON?.message || ' Verbindung fehlgeschlagen';881 var error = xhr.responseJSON?.message || '<?php echo esc_js(__('Connection failed', 'artidomo-print-on-demand')); ?>'; 856 882 $('#artidomo-connect-result').html( 857 883 '<div style="background: #f8d7da; padding: 12px; border-radius: 4px; text-align: center;"><strong>❌ ' + error + '</strong></div>' … … 872 898 global $wpdb; 873 899 874 // Hole alle Produkte mit artidomo SKU (maximal5)900 // Get all products with artidomo SKU (max 5) 875 901 $products = $wpdb->get_results( 876 902 "SELECT DISTINCT pm.post_id, pm.meta_value as artidomo_sku … … 889 915 <div class="artidomo-card" style="margin-top: 24px; text-align: center; padding: 40px 24px;"> 890 916 <div style="font-size: 48px; margin-bottom: 16px; opacity: 0.5;">🏷️</div> 891 <h3> Produkt-Zuordnungen</h3>917 <h3><?php esc_html_e('Product Mappings', 'artidomo-print-on-demand'); ?></h3> 892 918 <p style="color: #666; margin-top: 16px;"> 893 Noch keine Produkte zugeordnet. Gehe zu einem Produkt und füge eine artidomo SKU hinzu.919 <?php esc_html_e('No products mapped yet. Go to a product and add an artidomo SKU.', 'artidomo-print-on-demand'); ?> 894 920 </p> 895 <a href="<?php echo admin_url('edit.php?post_type=product'); ?>" class="button button-primary" style="margin-top: 16px;">896 Zu den Produkten→921 <a href="<?php echo esc_url(admin_url('edit.php?post_type=product')); ?>" class="button button-primary" style="margin-top: 16px;"> 922 <?php esc_html_e('Go to Products', 'artidomo-print-on-demand'); ?> → 897 923 </a> 898 924 </div> … … 904 930 <div class="artidomo-card" style="margin-top: 24px;"> 905 931 <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;"> 906 <h3 style="margin: 0;">🏷️ Produkt-Zuordnungen</h3>932 <h3 style="margin: 0;">🏷️ <?php esc_html_e('Product Mappings', 'artidomo-print-on-demand'); ?></h3> 907 933 <div style="display: flex; gap: 8px;"> 908 <a href="<?php echo admin_url('admin.php?page=artidomo-all-mappings'); ?>" class="button button-primary">909 Alle Produktzuordnungen anzeigen934 <a href="<?php echo esc_url(admin_url('admin.php?page=artidomo-all-mappings')); ?>" class="button button-primary"> 935 <?php esc_html_e('Show all product mappings', 'artidomo-print-on-demand'); ?> 910 936 </a> 911 <a href="<?php echo admin_url('edit.php?post_type=product'); ?>" class="button button-secondary">912 zur WooCommerce Produktverwaltung937 <a href="<?php echo esc_url(admin_url('edit.php?post_type=product')); ?>" class="button button-secondary"> 938 <?php esc_html_e('Go to WooCommerce Product Management', 'artidomo-print-on-demand'); ?> 913 939 </a> 914 940 </div> … … 916 942 917 943 <p style="color: #666; margin-bottom: 20px; font-size: 13px;"> 918 Hier werden nur die letzten 5 Zuordnungen angezeigt. Du kannst die Zuordnung besser im Fulfillment-Portal vornehmen. Aber es geht auch in WooCommerce unter den Produkten: Bei Einzelprodukten unter dem Reiter "artidomo" und bei Varianten-Produkten direkt in der Variante selbst.944 <?php esc_html_e('Only the last 5 mappings are shown here. You can manage mappings better in the Fulfillment Portal. But you can also do it in WooCommerce under Products: For simple products under the "artidomo" tab and for variable products directly in the variation.', 'artidomo-print-on-demand'); ?> 919 945 </p> 920 946 … … 923 949 <thead> 924 950 <tr style="background: #f9f9f9;"> 925 <th style="width: 60px; padding: 12px; font-weight: 600;"> ID</th>926 <th style="padding: 12px; font-weight: 600;"> Produktname</th>927 <th style="padding: 12px; font-weight: 600;"> WooCommerce SKU</th>928 <th style="width: 150px; padding: 12px; font-weight: 600;"> artidomo SKU</th>929 <th style="width: 150px; padding: 12px; font-weight: 600;"> Druckdatei</th>930 <th style="width: 100px; padding: 12px; font-weight: 600;"> Aktion</th>951 <th style="width: 60px; padding: 12px; font-weight: 600;"><?php esc_html_e('ID', 'artidomo-print-on-demand'); ?></th> 952 <th style="padding: 12px; font-weight: 600;"><?php esc_html_e('Product Name', 'artidomo-print-on-demand'); ?></th> 953 <th style="padding: 12px; font-weight: 600;"><?php esc_html_e('WooCommerce SKU', 'artidomo-print-on-demand'); ?></th> 954 <th style="width: 150px; padding: 12px; font-weight: 600;"><?php esc_html_e('artidomo SKU', 'artidomo-print-on-demand'); ?></th> 955 <th style="width: 150px; padding: 12px; font-weight: 600;"><?php esc_html_e('Print File', 'artidomo-print-on-demand'); ?></th> 956 <th style="width: 100px; padding: 12px; font-weight: 600;"><?php esc_html_e('Action', 'artidomo-print-on-demand'); ?></th> 931 957 </tr> 932 958 </thead> … … 940 966 $artidomo_sku = get_post_meta($product_id, '_artidomo_sku', true); 941 967 $printfilename = get_post_meta($product_id, '_artidomo_printfilename', true); 942 $personalization_provider = get_post_meta($product_id, '_artidomo_personalization_provider', true);943 968 944 969 $is_variation = $product->get_type() === 'variation'; … … 948 973 ?> 949 974 <tr style="border-bottom: 1px solid #eee;"> 950 <td style="padding: 12px;"><?php echo $product_id; ?></td>975 <td style="padding: 12px;"><?php echo esc_html($product_id); ?></td> 951 976 <td style="padding: 12px;"> 952 977 <strong><?php echo esc_html($product->get_name()); ?></strong> 953 978 <?php if ($is_variation): ?> 954 <br><small style="color: #999;">↳ Variante von #<?php echo $product->get_parent_id(); ?></small> 979 <br><small style="color: #999;">↳ <?php 980 /* translators: %d: parent product ID */ 981 printf(esc_html__('Variation of #%d', 'artidomo-print-on-demand'), $product->get_parent_id()); 982 ?></small> 955 983 <?php endif; ?> 956 984 </td> … … 959 987 <td style="padding: 12px; font-size: 12px; color: #666;"><?php echo esc_html($printfilename ?: '—'); ?></td> 960 988 <td style="padding: 12px;"> 961 <a href="<?php echo $edit_url; ?>" class="button button-small" style="font-size: 11px; padding: 4px 8px;">962 ✏️ Bearbeiten989 <a href="<?php echo esc_url($edit_url); ?>" class="button button-small" style="font-size: 11px; padding: 4px 8px;"> 990 ✏️ <?php esc_html_e('Edit', 'artidomo-print-on-demand'); ?> 963 991 </a> 964 992 </td> … … 971 999 <?php if (count($products) >= 5): ?> 972 1000 <p style="margin-top: 16px; text-align: center; color: #888; font-size: 12px; padding: 12px; background: #f9f9f9; border-radius: 4px;"> 973 Zeige die letzten 5 Produkte. <a href="<?php echo admin_url('admin.php?page=artidomo-all-mappings'); ?>" style="color: #3c8735; font-weight: 600;">Alle Produktzuordnungen anzeigen→</a>1001 <?php esc_html_e('Showing the last 5 products.', 'artidomo-print-on-demand'); ?> <a href="<?php echo esc_url(admin_url('admin.php?page=artidomo-all-mappings')); ?>" style="color: #3c8735; font-weight: 600;"><?php esc_html_e('Show all product mappings', 'artidomo-print-on-demand'); ?> →</a> 974 1002 </p> 975 1003 <?php endif; ?> … … 979 1007 980 1008 /** 981 * Füge "Alle Produktzuordnungen" Submenu hinzu1009 * Add "All Product Mappings" Submenu 982 1010 */ 983 1011 public function add_all_mappings_page() { 984 1012 add_submenu_page( 985 1013 'artidomo-connection', 986 'artidomo Produktzuordnungen',987 'Zuordnungen',1014 __('artidomo Product Mappings', 'artidomo-print-on-demand'), 1015 __('Mappings', 'artidomo-print-on-demand'), 988 1016 'manage_woocommerce', 989 1017 'artidomo-all-mappings', … … 993 1021 994 1022 /** 995 * Render "All e Produktzuordnungen" Page mit Paginierung1023 * Render "All Product Mappings" Page with Pagination 996 1024 */ 997 1025 public function render_all_mappings_page() { 998 1026 global $wpdb; 999 1027 1000 // Hole artidomo Preise aus der Datenbank(Backend)1028 // Get artidomo prices from database (Backend) 1001 1029 $artidomo_prices = $this->get_artidomo_prices(); 1002 1030 1003 // Pagin ierung1031 // Pagination 1004 1032 $per_page = 20; 1005 1033 $current_page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1; 1006 1034 $offset = ($current_page - 1) * $per_page; 1007 1035 1008 // Zähle alle Produkte mitartidomo SKU1036 // Count all products with artidomo SKU 1009 1037 $total_products = $wpdb->get_var( 1010 1038 "SELECT COUNT(DISTINCT pm.post_id) … … 1016 1044 ); 1017 1045 1018 // Hole Produkte für aktuelle Seite1046 // Get products for current page 1019 1047 $products = $wpdb->get_results( 1020 1048 $wpdb->prepare( … … 1051 1079 margin-bottom: 16px; 1052 1080 } 1053 .artidomo-badge {1054 display: inline-block;1055 padding: 4px 12px;1056 border-radius: 12px;1057 font-size: 11px;1058 font-weight: 600;1059 text-transform: uppercase;1060 letter-spacing: 0.5px;1061 }1062 .badge-success {1063 background: #d4edda;1064 color: #155724;1065 }1066 .badge-info {1067 background: #d1ecf1;1068 color: #0c5460;1069 }1070 .badge-warning {1071 background: #fff3cd;1072 color: #856404;1073 }1074 1081 </style> 1075 1082 … … 1078 1085 <div style="display: flex; align-items: center; gap: 16px;"> 1079 1086 <img src="https://portal.artidomo.eu/artidomo400px.png" alt="artidomo Logo" style="height: 48px;"> 1080 <h1 style="margin: 0;"> Alle Produktzuordnungen</h1>1087 <h1 style="margin: 0;"><?php esc_html_e('All Product Mappings', 'artidomo-print-on-demand'); ?></h1> 1081 1088 </div> 1082 <a href="<?php echo admin_url('admin.php?page=artidomo-connection'); ?>" class="button button-secondary">1083 ← Zurück zur Übersicht1089 <a href="<?php echo esc_url(admin_url('admin.php?page=artidomo-connection')); ?>" class="button button-secondary"> 1090 ← <?php esc_html_e('Back to Overview', 'artidomo-print-on-demand'); ?> 1084 1091 </a> 1085 1092 </div> 1086 1093 1087 1094 <div class="artidomo-card"> 1088 <h3>🏷️ Alle Produktzuordnungen (<?php echo $total_products; ?> Produkte)</h3> 1095 <h3>🏷️ <?php 1096 /* translators: %d: number of products */ 1097 printf(esc_html__('All Product Mappings (%d products)', 'artidomo-print-on-demand'), $total_products); 1098 ?></h3> 1089 1099 1090 1100 <p style="color: #666; margin-bottom: 20px; font-size: 13px;"> 1091 Hier kannst Du alle Produktzuordnungen einsehen. Du kannst die Zuordnung besser im Fulfillment-Portal vornehmen. Aber es geht auch in WooCommerce unter den Produkten: Bei Einzelprodukten unter dem Reiter "artidomo" und bei Varianten-Produkten direkt in der Variante selbst.1101 <?php esc_html_e('Here you can view all product mappings. You can manage mappings better in the Fulfillment Portal. But you can also do it in WooCommerce under Products: For simple products under the "artidomo" tab and for variable products directly in the variation.', 'artidomo-print-on-demand'); ?> 1092 1102 </p> 1093 1103 1094 1104 <?php if (empty($products)): ?> 1095 1105 <p style="text-align: center; padding: 40px; color: #999;"> 1096 Keine Produktzuordnungen gefunden.1106 <?php esc_html_e('No product mappings found.', 'artidomo-print-on-demand'); ?> 1097 1107 </p> 1098 1108 <?php else: ?> … … 1101 1111 <thead> 1102 1112 <tr style="background: #f9f9f9;"> 1103 <th style="width: 60px; padding: 12px; font-weight: 600;"> ID</th>1104 <th style="padding: 12px; font-weight: 600;"> Produktname</th>1105 <th style="padding: 12px; font-weight: 600;"> WooCommerce SKU</th>1106 <th style="width: 150px; padding: 12px; font-weight: 600;"> artidomo SKU</th>1107 <th style="width: 120px; padding: 12px; font-weight: 600;"> WooCommerce Preis (netto)</th>1108 <th style="width: 120px; padding: 12px; font-weight: 600;"> artidomo Preis (netto)</th>1109 <th style="width: 150px; padding: 12px; font-weight: 600;"> Druckdatei</th>1110 <th style="width: 100px; padding: 12px; font-weight: 600;"> Aktion</th>1113 <th style="width: 60px; padding: 12px; font-weight: 600;"><?php esc_html_e('ID', 'artidomo-print-on-demand'); ?></th> 1114 <th style="padding: 12px; font-weight: 600;"><?php esc_html_e('Product Name', 'artidomo-print-on-demand'); ?></th> 1115 <th style="padding: 12px; font-weight: 600;"><?php esc_html_e('WooCommerce SKU', 'artidomo-print-on-demand'); ?></th> 1116 <th style="width: 150px; padding: 12px; font-weight: 600;"><?php esc_html_e('artidomo SKU', 'artidomo-print-on-demand'); ?></th> 1117 <th style="width: 120px; padding: 12px; font-weight: 600;"><?php esc_html_e('WooCommerce Price (net)', 'artidomo-print-on-demand'); ?></th> 1118 <th style="width: 120px; padding: 12px; font-weight: 600;"><?php esc_html_e('artidomo Price (net)', 'artidomo-print-on-demand'); ?></th> 1119 <th style="width: 150px; padding: 12px; font-weight: 600;"><?php esc_html_e('Print File', 'artidomo-print-on-demand'); ?></th> 1120 <th style="width: 100px; padding: 12px; font-weight: 600;"><?php esc_html_e('Action', 'artidomo-print-on-demand'); ?></th> 1111 1121 </tr> 1112 1122 </thead> … … 1120 1130 $artidomo_sku = get_post_meta($product_id, '_artidomo_sku', true); 1121 1131 $printfilename = get_post_meta($product_id, '_artidomo_printfilename', true); 1122 $personalization_provider = get_post_meta($product_id, '_artidomo_personalization_provider', true); 1123 1124 // WooCommerce Preis (netto) 1132 1133 // WooCommerce Price (net) 1125 1134 $woo_price_incl = $product->get_price(); 1126 1135 $woo_price_net = $this->calculate_net_price($woo_price_incl, $product); 1127 1136 1128 // artidomo Pr eis1137 // artidomo Price 1129 1138 $artidomo_price = isset($artidomo_prices[$artidomo_sku]) ? $artidomo_prices[$artidomo_sku] : null; 1130 1139 … … 1135 1144 ?> 1136 1145 <tr style="border-bottom: 1px solid #eee;"> 1137 <td style="padding: 12px;"><?php echo $product_id; ?></td>1146 <td style="padding: 12px;"><?php echo esc_html($product_id); ?></td> 1138 1147 <td style="padding: 12px;"> 1139 1148 <strong><?php echo esc_html($product->get_name()); ?></strong> 1140 1149 <?php if ($is_variation): ?> 1141 <br><small style="color: #999;">↳ Variante von #<?php echo $product->get_parent_id(); ?></small> 1150 <br><small style="color: #999;">↳ <?php 1151 /* translators: %d: parent product ID */ 1152 printf(esc_html__('Variation of #%d', 'artidomo-print-on-demand'), $product->get_parent_id()); 1153 ?></small> 1142 1154 <?php endif; ?> 1143 1155 </td> … … 1145 1157 <td style="padding: 12px;"><code style="background: #f0f0f0; padding: 4px 8px; border-radius: 3px; font-size: 11px;"><?php echo esc_html($artidomo_sku); ?></code></td> 1146 1158 <td style="padding: 12px; font-weight: 600; color: #2271b1;"> 1147 <?php echo $woo_price_net !== null ? w c_price($woo_price_net) : '—'; ?>1159 <?php echo $woo_price_net !== null ? wp_kses_post(wc_price($woo_price_net)) : '—'; ?> 1148 1160 </td> 1149 1161 <td style="padding: 12px; font-weight: 600; color: #3c8735;"> 1150 1162 <?php 1151 1163 if ($artidomo_price !== null) { 1152 echo w c_price($artidomo_price);1164 echo wp_kses_post(wc_price($artidomo_price)); 1153 1165 } else { 1154 1166 echo '<span style="color: #999;">—</span>'; … … 1158 1170 <td style="padding: 12px; font-size: 12px; color: #666;"><?php echo esc_html($printfilename ?: '—'); ?></td> 1159 1171 <td style="padding: 12px;"> 1160 <a href="<?php echo $edit_url; ?>" class="button button-small" style="font-size: 11px; padding: 4px 8px;">1161 ✏️ Bearbeiten1172 <a href="<?php echo esc_url($edit_url); ?>" class="button button-small" style="font-size: 11px; padding: 4px 8px;"> 1173 ✏️ <?php esc_html_e('Edit', 'artidomo-print-on-demand'); ?> 1162 1174 </a> 1163 1175 </td> … … 1173 1185 <div class="tablenav-pages"> 1174 1186 <?php 1175 echo paginate_links(array(1187 echo wp_kses_post(paginate_links(array( 1176 1188 'base' => add_query_arg('paged', '%#%'), 1177 1189 'format' => '', 1178 1190 'current' => $current_page, 1179 1191 'total' => $total_pages, 1180 'prev_text' => '« Zurück',1181 'next_text' => 'Weiter»',1182 )) ;1192 'prev_text' => '« ' . __('Back', 'artidomo-print-on-demand'), 1193 'next_text' => __('Next', 'artidomo-print-on-demand') . ' »', 1194 ))); 1183 1195 ?> 1184 1196 </div> … … 1193 1205 1194 1206 /** 1195 * Berechne Netto-Preis aus WooCommerce Preis1207 * Calculate Net Price from WooCommerce Price 1196 1208 */ 1197 1209 private function calculate_net_price($price, $product) { … … 1200 1212 } 1201 1213 1202 // Prüfe ob WooCommerce Preis inkl. MwSt. ist1214 // Check if WooCommerce price includes tax 1203 1215 $tax_status = $product->get_tax_status(); 1204 1216 $tax_class = $product->get_tax_class(); 1205 1217 1206 1218 if ($tax_status === 'taxable' && wc_prices_include_tax()) { 1207 // Pr eis ist brutto, konvertiere zu netto1219 // Price is gross, convert to net 1208 1220 $tax_rates = WC_Tax::get_rates($tax_class); 1209 1221 … … 1216 1228 } 1217 1229 1218 // Pr eis ist bereits netto oder keine Steuer1230 // Price is already net or no tax 1219 1231 return floatval($price); 1220 1232 } 1221 1233 1222 1234 /** 1223 * Hole artidomo Preise aus dem Backend1235 * Get artidomo prices from Backend 1224 1236 */ 1225 1237 private function get_artidomo_prices() { 1226 // Cache f ür 5 Minuten1238 // Cache for 5 minutes 1227 1239 $cache_key = 'artidomo_prices_cache'; 1228 1240 $cached = get_transient($cache_key); … … 1232 1244 } 1233 1245 1234 // Hole Preise vom artidomo Backend1246 // Get prices from artidomo Backend 1235 1247 $response = wp_remote_get(ARTIDOMO_API_URL . '/products/prices', array( 1236 1248 'timeout' => 10, -
artidomo-print-on-demand/trunk/readme.txt
r3430729 r3431054 1 1 === artidomo Print on Demand === 2 2 Contributors: artidomo 3 Tags: print on demand, woocommerce, fulfillment, poster, print 3 Tags: print on demand, woocommerce, fulfillment, poster, print, dropshipping, german 4 4 Requires at least: 5.8 5 5 Tested up to: 6.7 … … 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 10 11 Verbindet WooCommerce mit dem artidomo Fulfillment System. Automatische Auftragsverarbeitung für Poster, Leinwände und personalisierte Druckprodukte.11 Connect WooCommerce to the artidomo Fulfillment System. Automatic order processing for posters, canvases, and personalized print products. 12 12 13 13 == Description == 14 14 15 **artidomo Print on Demand** is t die offizielle Erweiterung zur Anbindung deines WooCommerce-Shops an das artidomo Fulfillment-System.15 **artidomo Print on Demand** is the official extension for connecting your WooCommerce shop to the artidomo fulfillment system. 16 16 17 = Was ist artidomo? = 17 **Fully translated: English and German (Deutsch)** 18 18 19 artidomo ist ein deutscher Print-on-Demand Dienstleister spezialisiert auf: 19 = What is artidomo? = 20 20 21 * **Poster & Fine Art Prints** - Museum-Qualität auf verschiedenen Papieren 22 * **Leinwandbilder** - Fertig bespannt, verschiedene Formate 23 * **Wandbilder** - Alu-Dibond, Acrylglas, Forex 24 * **Personalisierte Produkte** - Mit Kundentext, Namen oder Bildern 21 artidomo is a German Print-on-Demand service provider specializing in: 25 22 26 = Funktionen = 23 * **Posters & Fine Art Prints** - Museum quality on various papers 24 * **Canvas Prints** - Ready-to-hang, various sizes 25 * **Wall Art** - Aluminum Dibond, Acrylic Glass, Forex 26 * **Personalized Products** - With customer text, names, or images 27 27 28 * **One-Click-Verbindung** - Verbinde deinen Shop in Sekunden mit dem artidomo Portal 29 * **Automatische Auftragsübertragung** - Bezahlte Bestellungen werden automatisch an artidomo gesendet 30 * **Produktzuordnung** - Einfache Zuordnung deiner Produkte zu artidomo-Artikeln 31 * **Webhook-Integration** - Echtzeit-Statusaktualisierungen 32 * **German Market & Germanized Support** - Volle Kompatibilität mit deutschen WooCommerce-Plugins 33 * **HPOS-Kompatibel** - Unterstützt WooCommerce High-Performance Order Storage 34 * **CSV Import/Export** - Massenzuordnung von Produkten 28 = Features = 35 29 36 = Voraussetzungen = 30 * **One-Click Connection** - Connect your shop to the artidomo Portal in seconds 31 * **Automatic Order Transfer** - Paid orders are automatically sent to artidomo 32 * **Product Mapping** - Easily map your products to artidomo items 33 * **Webhook Integration** - Real-time status updates 34 * **German Market & Germanized Support** - Full compatibility with German WooCommerce plugins 35 * **HPOS Compatible** - Supports WooCommerce High-Performance Order Storage 36 * **CSV Import/Export** - Bulk product mapping 37 37 38 * WooCommerce 5.0 oder höher 39 * PHP 7.4 oder höher 40 * WordPress 5.8 oder höher 41 * Ein aktiver artidomo-Vertrag ([portal.artidomo.eu](https://portal.artidomo.eu)) 38 = Requirements = 42 39 43 = Datenschutz = 40 * WooCommerce 5.0 or higher 41 * PHP 7.4 or higher 42 * WordPress 5.8 or higher 43 * An active artidomo contract ([portal.artidomo.eu](https://portal.artidomo.eu)) 44 44 45 Durch die Verbindung mit artidomo werden Bestelldaten (Lieferadresse, Bestellpositionen) an die Server von artidomo (portal.artidomo.eu) übermittelt. Dies ist für die Auftragsabwicklung erforderlich. Eine Auftragsverarbeitungsvereinbarung (AVV) ist Bestandteil des artidomo-Vertrags. 45 = Privacy = 46 47 By connecting to artidomo, order data (shipping address, order items) is transmitted to artidomo servers (portal.artidomo.eu). This is required for order fulfillment. A Data Processing Agreement (DPA) is part of the artidomo contract. 48 49 = Sprache / Language = 50 51 This plugin is fully translated into German. The admin interface will automatically display in German when your WordPress installation uses German (de_DE). 52 53 Dieses Plugin ist vollständig auf Deutsch übersetzt. Die Admin-Oberfläche wird automatisch auf Deutsch angezeigt, wenn deine WordPress-Installation Deutsch verwendet. 46 54 47 55 == Installation == 48 56 49 = Automati scheInstallation =57 = Automatic Installation = 50 58 51 1. G ehe im WordPress-Admin zu **Plugins → Installieren**52 2. S uche nach"artidomo"53 3. Klicke auf **Jetzt installieren**54 4. A ktiviere das Plugin59 1. Go to **Plugins → Add New** in WordPress Admin 60 2. Search for "artidomo" 61 3. Click **Install Now** 62 4. Activate the plugin 55 63 56 = Manu elleInstallation =64 = Manual Installation = 57 65 58 1. Lade die ZIP-Datei herunter59 2. G ehe zu **Plugins → Installieren → Plugin hochladen**60 3. Wähle die ZIP-Datei aus und klicke auf **Jetzt installieren**61 4. A ktiviere das Plugin66 1. Download the ZIP file 67 2. Go to **Plugins → Add New → Upload Plugin** 68 3. Select the ZIP file and click **Install Now** 69 4. Activate the plugin 62 70 63 = Nach der Installation =71 = After Installation = 64 72 65 1. G ehe zu**WooCommerce → artidomo**66 2. Melde dich im artidomo Portal an oder registriere dich67 3. Klicke im Portal auf "Shop hinzufügen" und wähleWooCommerce68 4. Die Verbindung wird automatisch hergestellt69 5. Ordne deine Produkte den artidomo-Artikeln zu73 1. Go to **WooCommerce → artidomo** 74 2. Log in to the artidomo Portal or register 75 3. Click "Add Shop" in the Portal and select WooCommerce 76 4. The connection will be established automatically 77 5. Map your products to artidomo items 70 78 71 79 == Frequently Asked Questions == 72 80 73 = Benötige ich einen artidomo-Account? =81 = Do I need an artidomo account? = 74 82 75 Ja, du benötigst einen aktiven Vertrag mit artidomo. Registriere dich kostenlos unter[portal.artidomo.eu](https://portal.artidomo.eu).83 Yes, you need an active contract with artidomo. Register for free at [portal.artidomo.eu](https://portal.artidomo.eu). 76 84 77 = Wie funktioniert die Auftragsübertragung? =85 = How does order transfer work? = 78 86 79 Sobald eine Bestellung in WooCommerce als "bezahlt" markiert wird (Status "Processing" oder "Completed"), wird sie automatisch per Webhook an artidomo übertragen. Dort wird sie produziert und direkt an deinen Kunden versendet.87 When an order is marked as "paid" in WooCommerce (status "Processing" or "Completed"), it is automatically transferred to artidomo via webhook. There it is produced and shipped directly to your customer. 80 88 81 = W elche Produkte kann ich mit artidomo verkaufen? =89 = What products can I sell with artidomo? = 82 90 83 artidomo bietet eine große Auswahl an Druckprodukten:91 artidomo offers a wide range of print products: 84 92 85 * Poster (Matt, Glanz, Fine Art)86 * Leinwandbilder (verschiedene Größen und Rahmen)87 * Wa ndbilder (Alu-Dibond, Acrylglas, Forex)88 * Personali sierte Produkte mit Kundentext oder -bild93 * Posters (Matte, Glossy, Fine Art) 94 * Canvas Prints (various sizes and frames) 95 * Wall Art (Aluminum Dibond, Acrylic Glass, Forex) 96 * Personalized products with customer text or images 89 97 90 = Funktioniert das Plugin mit German Market oder Germanized? =98 = Does the plugin work with German Market or Germanized? = 91 99 92 Ja! Das Plugin erkennt automatisch German Market und Germanized und passt sich an die spezifischen Bestellstatus dieser Plugins an.100 Yes! The plugin automatically detects German Market and Germanized and adapts to the specific order statuses of these plugins. 93 101 94 = Kann ich eigene Druckdateien verwenden? =102 = Can I use my own print files? = 95 103 96 Ja, du kannst deine eigenen Druckdateien im artidomo Portal hochladen und mit deinen Produkten verknüpfen.104 Yes, you can upload your own print files in the artidomo Portal and link them to your products. 97 105 98 = Wie werden die Versandkosten berechnet? =106 = How are shipping costs calculated? = 99 107 100 Die Versandkosten werden nach dem artidomo-Preissystem berechnet. Details findest du in deinem artidomo-Vertrag.108 Shipping costs are calculated according to the artidomo pricing system. Details can be found in your artidomo contract. 101 109 102 = W as passiert bei Retouren? =110 = What happens with returns? = 103 111 104 Ret ouren und Reklamationen werden über das artidomo Portal abgewickelt. Bei Druckfehlern erfolgt eine kostenlose Neuproduktion.112 Returns and complaints are handled through the artidomo Portal. Printing errors result in free reproduction. 105 113 106 114 == Screenshots == 107 115 108 1. Shop -Verbindung - Einfache Anbindung an das artidomo System109 2. Produ ktzuordnung - Verknüpfe WooCommerce-Produkte mit artidomo-Artikeln110 3. Bestellübersicht - Alle übertragenen Bestellungen im Blick111 4. Einstellungen - Webhook-Konfiguration und Plugin-Status116 1. Shop Connection - Easy connection to the artidomo system 117 2. Product Mapping - Link WooCommerce products to artidomo items 118 3. Order Overview - Track all transferred orders 119 4. Settings - Webhook configuration and plugin status 112 120 113 121 == Changelog == 114 122 115 123 = 2.0.0 = 116 * Neu: Vollständige Überarbeitung für wordpress.org 117 * Neu: Verbesserter Update-Mechanismus 118 * Neu: HPOS-Kompatibilität (WooCommerce High-Performance Order Storage) 119 * Neu: Erweiterte German Market & Germanized Unterstützung 120 * Neu: CSV-Massenimport/-export für Produktzuordnungen 121 * Neu: Verbesserte Admin-Oberfläche 122 * Fix: Block-Checkout-Kompatibilität verbessert 123 * Fix: Hausnummer-Extraktion optimiert 124 * New: Complete redesign for wordpress.org 125 * New: Improved update mechanism 126 * New: HPOS compatibility (WooCommerce High-Performance Order Storage) 127 * New: Extended German Market & Germanized support 128 * New: CSV bulk import/export for product mappings 129 * New: Improved admin interface 130 * New: Full English and German translations 131 * Fix: Block checkout compatibility improved 132 * Fix: House number extraction optimized 124 133 125 134 = 1.0.0 = 126 * Erste Version135 * Initial release 127 136 128 137 == Upgrade Notice == 129 138 130 139 = 2.0.0 = 131 Große Überarbeitung mit verbesserter Kompatibilität und neuen Funktionen. Empfohlenes Update für alle Nutzer.140 Major redesign with improved compatibility and new features. Recommended update for all users. 132 141 133 142 == Additional Info == … … 135 144 = Support = 136 145 137 Bei Fragen wende dich an [[email protected]](mailto:[email protected]) oder besuche das[artidomo Portal](https://portal.artidomo.eu).146 For questions, contact [[email protected]](mailto:[email protected]) or visit the [artidomo Portal](https://portal.artidomo.eu). 138 147 139 = Überartidomo =148 = About artidomo = 140 149 141 artidomo is t ein deutscher Print-on-Demand Dienstleister mit Sitz in Bochum. Wir produzieren hochwertige Druckprodukte und versenden diese direkt an deine Kunden - weltweit.150 artidomo is a German Print-on-Demand service provider based in Bochum, Germany. We produce high-quality print products and ship them directly to your customers - worldwide. 142 151 143 ** Kontakt:**144 artidomo - Inhaberin: Marina Scheubly145 Wittener Str. 75, 44789 Bochum 146 Tel: +49-(0)234-52009829147 E -Mail: [email protected]152 **Contact:** 153 artidomo - Owner: Marina Scheubly 154 Wittener Str. 75, 44789 Bochum, Germany 155 Phone: +49-(0)234-52009829 156 Email: [email protected] 148 157 Web: [www.artidomo.eu](https://www.artidomo.eu)
Note: See TracChangeset
for help on using the changeset viewer.