' . esc_html( $title ) . '

'; echo '

' . wp_kses_post( sprintf( /* translators: %s: URL */ __( 'Please connect your shop first.', 'eazign' ), esc_url( admin_url( 'admin.php?page=eazign' ) ) ) ) . '

'; return false; } /** * Stops AJAX requests of users without the WooCommerce capability. */ private static function ajax_guard() { if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( array( 'message' => __( 'Sorry, you are not allowed to do this.', 'eazign' ) ), 403 ); } } // ---- motifs ---------------------------------------------------------------- /** * Motif gallery. */ public static function page_motifs() { if ( ! self::connected_or_hint( __( 'Motifs', 'eazign' ) ) ) { return; } $data = Eazign_Client::get( 'motifs' ); $motifs = is_wp_error( $data ) ? array() : $data['motifs']; $categories = array_values( array_unique( wp_list_pluck( $motifs, 'category' ) ) ); ?>

%s

', esc_html( $data->get_error_message() ) ); } ?>

__( 'Please choose a file.', 'eazign' ) ) ); } $bytes = file_get_contents( $_FILES['file']['tmp_name'] ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents, WordPress.Security.ValidatedSanitizedInput $result = Eazign_Client::post( 'motifs', array( 'name' => isset( $_FILES['file']['name'] ) ? sanitize_file_name( wp_unslash( $_FILES['file']['name'] ) ) : '', 'category' => isset( $_POST['category'] ) ? sanitize_text_field( wp_unslash( $_POST['category'] ) ) : '', 'data' => base64_encode( $bytes ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- binary upload in JSON. ), array( 'timeout' => 120 ) ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } wp_send_json_success( $result ); } /** * Rename / recategorise a motif. */ public static function save_motif() { if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die( esc_html__( 'Sorry, you are not allowed to do this.', 'eazign' ) ); } $id = isset( $_POST['motif'] ) ? sanitize_key( wp_unslash( $_POST['motif'] ) ) : ''; check_admin_referer( 'eazign_save_motif_' . $id ); $result = Eazign_Client::post( 'motifs/' . rawurlencode( $id ), array( 'name' => isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '', 'category' => isset( $_POST['category'] ) ? sanitize_text_field( wp_unslash( $_POST['category'] ) ) : '', ) ); Eazign_Admin::notice( is_wp_error( $result ) ? 'error' : 'success', is_wp_error( $result ) ? $result->get_error_message() : __( 'Motif saved.', 'eazign' ) ); wp_safe_redirect( admin_url( 'admin.php?page=eazign-motifs' ) ); exit; } /** * Delete a motif. */ public static function delete_motif() { if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die( esc_html__( 'Sorry, you are not allowed to do this.', 'eazign' ) ); } $id = isset( $_GET['motif'] ) ? sanitize_key( wp_unslash( $_GET['motif'] ) ) : ''; check_admin_referer( 'eazign_delete_motif_' . $id ); $result = Eazign_Client::post( 'motifs/' . rawurlencode( $id ) . '/delete' ); Eazign_Admin::notice( is_wp_error( $result ) ? 'error' : 'success', is_wp_error( $result ) ? $result->get_error_message() : __( 'Motif deleted.', 'eazign' ) ); wp_safe_redirect( admin_url( 'admin.php?page=eazign-motifs' ) ); exit; } // ---- generator ------------------------------------------------------------- /** * Generator: choose motifs, blanks with colours, placement; then runs. */ public static function page_generator() { if ( ! self::connected_or_hint( __( 'Generator', 'eazign' ) ) ) { return; } $motifs = Eazign_Client::get( 'motifs' ); $blanks = Eazign_Client::get( 'blanks' ); $ids = (array) get_option( self::JOBS, array() ); $jobs = $ids ? Eazign_Client::get( 'generator?ids=' . rawurlencode( implode( ',', $ids ) ) ) : array( 'jobs' => array() ); echo '

' . esc_html__( 'Generator', 'eazign' ) . '

'; echo '

' . esc_html__( 'Prints each selected motif on each selected blank and creates one variable product per combination (colour × size) with prices, SKUs and a mockup per colour. Orders of these products get print files automatically.', 'eazign' ) . '

'; foreach ( array( $motifs, $blanks, $jobs ) as $result ) { if ( is_wp_error( $result ) ) { printf( '

%s

', esc_html( $result->get_error_message() ) ); return; } } $motifs = $motifs['motifs']; $blanks = $blanks['blanks']; if ( ! $motifs || ! $blanks ) { echo '

' . wp_kses_post( sprintf( /* translators: 1: motifs URL, 2: blanks URL */ __( 'The generator needs at least one motif and one blank with a base photo.', 'eazign' ), esc_url( admin_url( 'admin.php?page=eazign-motifs' ) ), esc_url( admin_url( 'admin.php?page=eazign-blanks' ) ) ) ) . '

'; return; } $view_names = array(); foreach ( $blanks as $blank ) { foreach ( $blank['views'] as $view ) { $view_names[ $view['name'] ] = true; } } $categories = get_terms( array( 'taxonomy' => 'product_cat', 'hide_empty' => false, ) ); $sizes = array(); foreach ( $blanks as $blank ) { $sizes[ $blank['id'] ] = max( 1, count( $blank['sizes'] ) ); } ?>

' . esc_html( $date ) . ' · '; /* translators: 1: done, 2: total */ echo esc_html( sprintf( __( '%1$d of %2$d products', 'eazign' ), $job['done'], $job['total'] ) ); if ( 'running' === $job['status'] ) { echo ' · ' . esc_html__( 'running…', 'eazign' ); } echo ''; } /** * Starts a generator run (background job at the service). */ public static function ajax_generate() { check_ajax_referer( 'eazign_sync' ); self::ajax_guard(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON, every field is sanitized below. $items_in = isset( $_POST['items'] ) ? json_decode( wp_unslash( $_POST['items'] ), true ) : array(); $placement = isset( $_POST['placement'] ) ? json_decode( sanitize_text_field( wp_unslash( $_POST['placement'] ) ), true ) : array(); $items = array(); foreach ( is_array( $items_in ) ? $items_in : array() as $item ) { $items[] = array( 'motifId' => sanitize_key( $item['motifId'] ?? '' ), 'darkMotifId' => sanitize_key( $item['darkMotifId'] ?? '' ), 'blankId' => sanitize_key( $item['blankId'] ?? '' ), 'colors' => array_map( 'sanitize_text_field', (array) ( $item['colors'] ?? array() ) ), ); } $placement = is_array( $placement ) ? $placement : array(); $result = Eazign_Client::post( 'generator', array( 'items' => $items, 'placement' => array( 'view' => sanitize_text_field( $placement['view'] ?? '' ), 'align' => sanitize_key( $placement['align'] ?? 'center' ), 'topMm' => (float) ( $placement['topCm'] ?? 3 ) * 10, 'widthMm' => (float) ( $placement['widthCm'] ?? 26 ) * 10, ), 'status' => isset( $_POST['status'] ) && 'publish' === $_POST['status'] ? 'publish' : 'draft', 'categoryIds' => isset( $_POST['categories'] ) ? array_map( 'absint', explode( ',', sanitize_text_field( wp_unslash( $_POST['categories'] ) ) ) ) : array(), ) ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } $ids = (array) get_option( self::JOBS, array() ); array_unshift( $ids, sanitize_key( $result['jobId'] ) ); update_option( self::JOBS, array_slice( $ids, 0, 10 ), false ); wp_send_json_success( $result ); } /** * Progress of a generator run. */ public static function ajax_status() { check_ajax_referer( 'eazign_sync' ); self::ajax_guard(); $job = isset( $_POST['job'] ) ? sanitize_key( wp_unslash( $_POST['job'] ) ) : ''; $result = Eazign_Client::get( 'generator/' . rawurlencode( $job ) ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } foreach ( $result['job']['results'] as &$entry ) { if ( ! empty( $entry['productId'] ) && get_post( (int) $entry['productId'] ) ) { $entry['editUrl'] = get_edit_post_link( (int) $entry['productId'], 'raw' ); } } unset( $entry ); wp_send_json_success( $result['job'] ); } }