__('Products', 'formipay'), 'singular_name' => __('Product', 'formipay'), 'menu_name' => 'Formipay', 'add_new' => __('Add New', 'formipay'), 'add_new_item' => __('Add New Product', 'formipay'), 'edit' => __('Edit', 'formipay'), 'edit_item' => __('Edit Product', 'formipay'), 'new_item' => __('New Product', 'formipay'), 'view' => __('View', 'formipay'), 'view_item' => __('View Product', 'formipay'), 'search_items' => __('Search Product', 'formipay'), 'not_found' => __('No products found', 'formipay'), 'not_found_in_trash' => __('No products found in trash', 'formipay'), 'parent' => __('Product Parent', 'formipay') ); $args = array( 'label' => 'Products', 'labels' => $labels, 'public' => true, 'supports' => array( 'title' ), 'hierarchical' => true, 'taxonomies' => array( 'formipay-product-category' ), 'has_archive' => true, 'rewrite' => array( 'slug' => 'product' ), 'show_ui' => true, 'show_in_menu' => false, 'show_in_rest' => true, 'query_var' => true ); register_post_type( 'formipay-product', $args ); } public function taxonomy() { register_taxonomy( 'formipay-product-category', 'formipay-product', array( 'rewrite' => array( 'slug' => 'product/category' ), 'hierarchical' => true ) ); } public function add_submenu() { add_submenu_page( 'formipay', __( 'Products', 'formipay' ), __( 'Products', 'formipay' ), 'manage_options', 'formipay-products', [$this, 'formipay_products'], ); add_submenu_page( 'formipay', __('Categories', 'formipay'), '└ ' . __('Categories', 'formipay'), 'manage_options', 'edit-tags.php?taxonomy=formipay-product-category&post_type=formipay-product', null, 5 ); } public function enqueue_admin() { global $current_screen; if($current_screen->id == 'formipay_page_formipay-products') { wp_enqueue_style( 'page-products', FORMIPAY_URL . 'admin/assets/css/page-products.css', [], FORMIPAY_VERSION, 'all' ); wp_enqueue_script( 'page-products', FORMIPAY_URL . 'admin/assets/js/page-products.js', ['jquery', 'gridjs'], FORMIPAY_VERSION, true ); wp_localize_script( 'page-products', 'formipay_products_page', [ 'ajax_url' => admin_url('admin-ajax.php'), 'site_url' => site_url(), 'columns' => [ 'id' => esc_html__( 'ID', 'formipay' ), 'title' => esc_html__( 'Title', 'formipay' ), 'price' => esc_html__( 'Price', 'formipay' ), 'type' => esc_html__( 'Type', 'formipay' ), 'stock' => esc_html__( 'Stock', 'formipay' ), 'status' => esc_html__( 'Status', 'formipay' ), ], 'filter_form' => [ 'categories' => [ 'placeholder' => esc_html__( 'Filter by Category', 'formipay' ), 'noresult_text' => esc_html__( 'No results found', 'formipay' ) ], 'currencies' => [ 'placeholder' => esc_html__( 'Filter by Currency', 'formipay' ), 'noresult_text' => esc_html__( 'No results found', 'formipay' ) ] ], 'modal' => [ 'form' => [ 'currency_options' => formipay_currency_as_options() ], 'add' => [ 'title' => esc_html__( 'Your New Product Data', 'formipay' ), 'validation' => esc_html__( '{{field}} is required', 'formipay' ), 'cancelButton' => esc_html__( 'Cancel', 'formipay' ), 'confirmButton' => esc_html__( 'Create New Product', 'formipay' ) ], 'delete' => [ 'question' => esc_html__( 'Do you want to delete the product?', 'formipay' ), 'cancelButton' => esc_html__( 'Cancel', 'formipay' ), 'confirmButton' => esc_html__( 'Delete Permanently', 'formipay' ) ], 'bulk_delete' => [ 'question' => esc_html__( 'Do you want to delete the selected the product(s)?', 'formipay' ), 'cancelButton' => esc_html__( 'Cancel', 'formipay' ), 'confirmButton' => esc_html__( 'Confirm', 'formipay' ) ], 'duplicate' => [ 'question' => esc_html__( 'Do you want to duplicate the product?', 'formipay' ), 'cancelButton' => esc_html__( 'Cancel', 'formipay' ), 'confirmButton' => esc_html__( 'Confirm', 'formipay' ) ], ], 'nonce' => wp_create_nonce('formipay-admin-product-page') ] ); } if($current_screen->base == 'post' && $current_screen->post_type == 'formipay-product'){ global $post; $product_id = $post->ID; // Get pricing method, default to 'auto' if not set $pricing_method = formipay_get_post_meta($product_id, 'product_pricing_method') ?: 'auto'; $has_variation = (bool) formipay_get_post_meta($product_id, 'product_has_variation', true); wp_enqueue_style( 'product-details', FORMIPAY_URL . 'admin/assets/css/admin-product-editor.css', [], FORMIPAY_VERSION, 'all' ); wp_enqueue_script( 'product-details', FORMIPAY_URL . 'admin/assets/js/admin-product-editor.js', ['jquery', 'vue.js'], FORMIPAY_VERSION, true ); wp_localize_script( 'product-details', 'product_details', [ 'default_currency' => formipay_default_currency(), 'default_currency_title' => formipay_default_currency('title'), 'default_currency_symbol' => formipay_default_currency('symbol'), 'default_currency_decimal_digits' => formipay_default_currency('decimal_digits'), 'default_currency_decimal_symbol' => formipay_default_currency('decimal_symbol'), 'default_currency_thousand_separator' => formipay_default_currency('thousand_separator'), 'product_type' => formipay_get_post_meta($product_id, 'product_type') ?: 'digital', 'product_is_physical' => formipay_get_post_meta($product_id, 'product_type') == 'physical', 'product_pricing_method' => $pricing_method, // Pass pricing method to JS 'product_has_variation' => $has_variation, 'variation_table' => [ 'th_toggle' => __('Active', 'formipay'), 'th_name' => __('Title', 'formipay'), 'th_stock' => __('Stock', 'formipay'), 'th_price' => __('Regular Price', 'formipay'), 'th_sale' => __('Sale Price', 'formipay'), 'th_weight' => __('Weight', 'formipay'), 'th_prices_overall' => __('Prices', 'formipay'), // New header for manual mode 'manual_price_hint' => __('Prices set manually below', 'formipay'), // New hint for manual mode cell 'child_th_currency' => __('Currency', 'formipay'), // Child table header 'child_th_regular' => __('Regular Price', 'formipay'), // Child table header 'child_th_sale' => __('Sale Price', 'formipay'), // Child table header 'no_variations' => __( 'No variations available', 'formipay' ) ] ] ); } $screen = get_current_screen(); if($current_screen->taxonomy == 'formipay-product-category') { wp_enqueue_style( 'formipay-admin-pages', FORMIPAY_URL . 'admin/assets/css/admin-pages.css', [], FORMIPAY_VERSION, 'all' ); wp_enqueue_style( 'gridjs', FORMIPAY_URL . 'vendor/GridJS/gridjs.mermaid.min.css', [], '6.2.0', 'all' ); wp_enqueue_style( 'page-product-taxonomy', FORMIPAY_URL . 'admin/assets/css/page-product-taxonomy.css', [], FORMIPAY_VERSION, 'all' ); wp_enqueue_script( 'formipay-admin-pages', FORMIPAY_URL . 'admin/assets/js/admin-pages.js', ['jquery'], FORMIPAY_VERSION, true ); wp_enqueue_script( 'gridjs', FORMIPAY_URL . 'vendor/GridJS/gridjs.production.min.js', ['jquery'], '6.2.0', true ); wp_enqueue_script( 'page-product-taxonomy', FORMIPAY_URL . 'admin/assets/js/page-product-taxonomy.js', ['jquery', 'gridjs'], FORMIPAY_VERSION, true ); wp_localize_script( 'page-product-taxonomy', 'formipay_product_taxonomy_page', [ 'site_url' => site_url(), 'page_title' => esc_html__( 'Product Categories', 'formipay' ) ] ); wp_enqueue_style( 'sweetalert2', FORMIPAY_URL . 'vendor/SweetAlert2/sweetalert2.min.css', [], '11.14.4', 'all'); wp_enqueue_script( 'sweetalert2', FORMIPAY_URL . 'vendor/SweetAlert2/sweetalert2.min.js', ['jquery'], '11.14.4', true); wp_localize_script( 'sweetalert2', 'formipay_admin', [ 'ajax_url' => admin_url('admin-ajax.php'), 'site_url' => site_url(), ] ); } } public function formipay_products() { include_once FORMIPAY_PATH . 'admin/page-products.php'; } public function cpt_post_fields_box($boxes) { $boxes['formipay_product_settings'] = array( 'post_type' => array('formipay-product'), 'label' => __('Config', 'formipay'), ); return $boxes; } public function cpt_post_fields_content($fields) { $fields['formipay_product_settings'] = array(); $fields = apply_filters( 'formipay/product-config', $fields ); return $fields; } public function general_config($fields) { // Product Details Group $product_details_group = array( 'setting_product_details' => array( 'type' => 'group_title', 'label' => __( 'Product Details', 'formipay' ), 'description' => __( 'All details about the products sold using this form.', 'formipay' ), 'group' => 'started' ), 'product_type' => array( 'type' => 'radio', 'label' => __('Product Type', 'formipay'), 'options' => array( 'digital' => 'Digital', 'physical' => 'Physical' ), 'value' => 'digital', 'required' => true ), 'product_description' => array( 'type' => 'tinymce', 'label' => __('Description', 'formipay'), ) ); $product_details_group = apply_filters( 'formipay/product-settings/tab:general/group:product-details', $product_details_group ); $last_product_details_group = array_key_last($product_details_group); $product_details_group[$last_product_details_group]['group'] = 'ended'; // Product Currency Group $product_currency_group = array( 'setting_product_pricing' => array( 'type' => 'group_title', 'label' => __( 'Pricing', 'formipay' ), 'description' => __( 'Carefully set these options below.', 'formipay' ), 'group' => 'started', ), 'product_pricing_method' => array( 'type' => 'radio', 'label' => __('Product Pricing Method', 'formipay'), 'options' => array( 'manual' => 'Manual Price Set', 'auto' => 'Auto via Currency Exchange API' ), 'value' => 'manual', 'required' => true ), 'product_regular_price' => array( 'type' => 'number', 'label' => sprintf( __('Regular Price (%s)', 'formipay'), formipay_default_currency('symbol') ), 'value' => 0, 'step' => 0.01, 'required' => true, 'dependency' => [ 'key' => 'product_pricing_method', 'value' => 'auto' ] ), 'product_sale_price' => array( 'type' => 'number', 'label' => sprintf( __('Sale Price (%s)', 'formipay'), formipay_default_currency('symbol') ), 'value' => 0, 'step' => 0.01, 'dependency' => [ 'key' => 'product_pricing_method', 'value' => 'auto' ] ), 'product_prices' => [ 'type' => 'repeater', 'label' => __( 'Prices', 'formipay' ), 'description' => __( 'You can set price with multiple currency', 'formipay' ), 'fields' => [ 'regular_price' => array( 'type' => 'number', 'label' => __('Regular Price', 'formipay'), 'value' => 0, 'step' => 0.01, 'required' => true ), 'sale_price' => array( 'type' => 'number', 'label' => __('Sale Price', 'formipay'), 'value' => 0, 'step' => 0.01 ), 'currency' => array( 'type' => 'select', 'label' => __('Currency', 'formipay'), 'value' => 'IDR:::Indonesian rupiah:::Rp', 'options' => formipay_currency_as_options(), 'required' => true, 'searchable' => true, 'is_group_title' => true ), 'currency_decimal_digits' => array( 'type' => 'number', 'label' => __('Decimal Digits', 'formipay'), 'value' => '2', 'required' => true ), 'currency_decimal_symbol' => array( 'type' => 'text', 'label' => __('Decimal Symbol', 'formipay'), 'value' => '.', 'required' => true ), 'currency_thousand_separator' => array( 'type' => 'text', 'label' => __('Thousand Separator Symbol', 'formipay'), 'value' => ',', 'required' => true ), ], 'dependency' => [ 'key' => 'product_pricing_method', 'value' => 'manual' ] ], ); $product_currency_group = apply_filters( 'formipay/product-settings/tab:general/group:product-currency', $product_currency_group ); $last_product_currency_group = array_key_last($product_currency_group); $product_currency_group[$last_product_currency_group]['group'] = 'ended'; $general_all_fields = array_merge($product_details_group, $product_currency_group); $general_all_fields = apply_filters( 'formipay/product-settings/tab:general', $general_all_fields ); $fields['formipay_product_settings']['general'] = array( 'name' => __('General', 'formipay'), 'fields' => $general_all_fields ); return $fields; } public function variations_config($fields) { // Product Variations Attribute Group $product_attributes_group = array( 'setting_product_variations' => array( 'type' => 'group_title', 'label' => __( 'Attributes', 'formipay' ), 'description' => __( 'First we need to build the attribute of this product. For example Color, Size, License Site Count.', 'formipay' ), 'group' => 'started' ), 'product_has_variation' => array( 'type' => 'checkbox', 'label' => __( 'Product has variations', 'formipay' ), ), 'product_variation_attributes' => array( 'type' => 'repeater', 'label' => __('Attributes', 'formipay'), 'description' => __( 'Your attributes will generate variation automatically.', 'formipay' ), 'fields' => [ 'attribute_name' => [ 'type' => 'text', 'label' => __( 'Attribute Name', 'formipay' ), 'description' => __( 'e.g. Color, Size, etc', 'formipay' ), 'is_group_title' => true ], 'attribute_variations' => [ 'type' => 'repeater', 'label' => esc_html__( 'Variation', 'formipay' ), 'fields' => [ 'variation_label' => [ 'type' => 'text', 'label' => __( 'Title', 'formipay' ), 'description' => __( 'e.g. Color, Size, etc', 'formipay' ), 'required' => true, 'is_group_title' => true ], 'variation_value_type' => [ 'type' => 'select', 'label' => __( 'Value Type', 'formipay' ), 'options' => [ 'text' => __( 'Text', 'formipay' ), 'number' => __( 'Number', 'formipay' ), 'color' => __( 'Color', 'formipay' ), ], 'value' => 'text' ], 'variation_value_text' => [ 'type' => 'text', 'label' => __( 'Value', 'formipay' ), 'required' => true, 'dependency' => array( 'key' => 'variation_value_type', 'value' => 'text' ), ], 'variation_value_number' => [ 'type' => 'number', 'label' => __( 'Value', 'formipay' ), 'required' => true, 'dependency' => array( 'key' => 'variation_value_type', 'value' => 'number' ), ], 'variation_value_color' => [ 'type' => 'color', 'label' => __( 'Value', 'formipay' ), 'required' => true, 'dependency' => array( 'key' => 'variation_value_type', 'value' => 'color' ), ], ], ], ], 'dependency' => array( 'key' => 'product_has_variation', 'value' => 'not_empty' ), ), ); $product_attributes_group = apply_filters( 'formipay/product-settings/tab:general/group:product-attributes', $product_attributes_group ); $last_product_attributes_group = array_key_last($product_attributes_group); $product_attributes_group[$last_product_attributes_group]['group'] = 'ended'; // Product Variations Attribute Group // Define your product variations field group somewhere in your plugin/theme $product_variations_table_html = file_get_contents(FORMIPAY_PATH . 'admin/templates/product-variations.php'); $product_variations_group = [ 'variation_table' => [ 'type' => 'html', 'label' => __( 'Variations', 'formipay' ), 'html' => $product_variations_table_html ], ]; $variation_all_fields = array_merge($product_attributes_group, $product_variations_group); $variation_all_fields = apply_filters( 'formipay/product-settings/tab:variations', $variation_all_fields ); $fields['formipay_product_settings']['variation'] = array( 'name' => __('Variations', 'formipay'), 'fields' => $variation_all_fields ); return $fields; } public function stock_config($fields) { // Product Quantity Group $product_quantity_group = array( 'setting_product_quantity' => array( 'type' => 'group_title', 'label' => __( 'Quantity Settings', 'formipay' ), 'description' => __( 'You can activate this if you will manage the stock.', 'formipay' ), 'group' => 'started' ), 'product_quantity_toggle' => array( 'type' => 'checkbox', 'label' => __( 'Activate Quantity', 'formipay' ), ), 'product_quantity_range' => array( 'type' => 'number', 'label' => __( 'Quantity Range Step', 'formipay' ), 'value' => 1, 'dependency' => array( 'key' => 'product_quantity_toggle', 'value' => 'not_empty' ) ), 'product_minimum_purchase' => array( 'type' => 'number', 'label' => __( 'Minimum Purchase', 'formipay' ), 'value' => 1, 'dependency' => array( 'key' => 'product_quantity_toggle', 'value' => 'not_empty' ) ), 'product_stock' => array( 'type' => 'number', 'label' => __( 'Stock', 'formipay' ), 'description' => __('Set -1 for unlimited stock', 'formipay'), 'value' => -1, 'dependency' => array( 'key' => 'product_quantity_toggle', 'value' => 'not_empty' ) ) ); $product_quantity_group = apply_filters( 'formipay/product-settings/tab:stock/group:product-quantity', $product_quantity_group ); $last_product_quantity_group = array_key_last($product_quantity_group); $product_quantity_group[$last_product_quantity_group]['group'] = 'ended'; $stock_all_fields = apply_filters( 'formipay/product-settings/tab:stock', $product_quantity_group ); $fields['formipay_product_settings']['stock'] = array( 'name' => __('Stock & Quantity', 'formipay'), 'fields' => $stock_all_fields ); return $fields; } public function formipay_tabledata_products() { check_ajax_referer( 'formipay-admin-product-page', '_wpnonce' ); global $wpdb; // Initialize default args $base_args = [ 'post_type' => 'formipay-product', 'post_status' => ['publish', 'draft', 'pending'], 'fields' => 'ids' // Optimize initial query ]; // Handle status filtering if (isset($_REQUEST['post_status']) && 'all' !== $_REQUEST['post_status']) { $base_args['post_status'] = [sanitize_key($_REQUEST['post_status'])]; } // Currency filtering if (!empty($_REQUEST['currency'])) { // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query $base_args['meta_query'] = [ [ 'key' => 'product_currency', 'value' => sanitize_text_field(wp_unslash($_REQUEST['currency'])), 'compare' => 'LIKE' ] ]; } // Category filtering if (!empty($_REQUEST['category'])) { // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query $base_args['tax_query'] = [ [ 'taxonomy' => 'formipay-product-category', 'field' => 'term_id', 'terms' => absint($_REQUEST['category']) ] ]; } // Search functionality if (!empty($_REQUEST['search'])) { $base_args['s'] = isset($_REQUEST['search']) ? sanitize_text_field(wp_unslash($_REQUEST['search'])) : ''; } // Sorting if (!empty($_REQUEST['orderby'])) { $orderby = sanitize_key($_REQUEST['orderby']); $order = isset($_REQUEST['sort']) ? sanitize_key($_REQUEST['sort']) : 'ASC'; if ('price' === $orderby) { // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key $base_args['meta_key'] = 'product_price'; $base_args['orderby'] = 'meta_value_num'; } else { $base_args['orderby'] = $orderby; } $base_args['order'] = $order; } // Pagination if (isset($_REQUEST['limit'])) { $base_args['posts_per_page'] = absint($_REQUEST['limit']); } if (isset($_REQUEST['offset'])) { $base_args['offset'] = intval($_REQUEST['offset']); } // Main query $query = new \WP_Query($base_args); $product_ids = $query->posts; $total_products = $query->found_posts; // Process results $products = []; foreach ($product_ids as $product_id) { $product = get_post($product_id); $currency = explode(':::', get_post_meta($product_id, 'product_currency', true)); $categories = wp_get_post_terms($product_id, 'formipay-product-category', ['fields' => 'names']); $products[] = [ 'ID' => $product_id, 'title' => $product->post_title, 'category' => implode(', ', $categories), 'type' => formipay_get_post_meta($product_id, 'product_type'), 'stock' => formipay_get_post_meta($product_id, 'stock') ?: '∞', 'price' => [ 'flag' => formipay_get_flag_by_currency($currency[0] ?? ''), 'name' => formipay_price_format( get_post_meta($product_id, 'price', true), $product_id ) ], 'status' => $product->post_status, ]; } // Get status counts using WordPress API $counts = wp_count_posts('formipay-product'); $status_counts = []; foreach ($counts as $status => $count) { $status_counts[$status] = $count; } $status_counts['all'] = array_sum($status_counts); wp_send_json([ 'results' => $products, 'total' => $total_products, 'posts_report' => array_map('intval', (array)$status_counts) ]); } public function formipay_create_product_post() { check_ajax_referer( 'formipay-admin-product-page', '_wpnonce' ); $title = isset($_REQUEST['title']) ? sanitize_text_field( wp_unslash($_REQUEST['title']) ) : ''; if( !empty($title) && '' !== $title ){ $post_id = wp_insert_post( [ 'post_title' => $title, 'post_type' => 'formipay-product', ], true ); if(is_wp_error($post_id)){ wp_send_json_error( [ 'message' => $post_id->get_error_message() ] ); } update_post_meta($post_id, 'product_currency', 'USD:::United States dollar:::$'); // Note:: Ganti dengan default currency dari global settings wp_send_json_success( [ 'edit_post_url' => admin_url('post.php?post='.$post_id.'&action=edit') ] ); } wp_send_json_error( [ 'message' => esc_html__( 'Product\'s title is empty.', 'formipay' ) ] ); } public function formipay_product_get_currencies() { check_ajax_referer( 'formipay-admin-product-page', '_wpnonce' ); $search = isset($_REQUEST['search']) ? sanitize_text_field( wp_unslash($_REQUEST['search']) ) : ''; $countries = formipay_currency_array(); $results = []; foreach($countries as $country){ $country_name = strtolower($country['name']); $country_search = strtolower($search); if(strpos($country_name, $country_search) !== false || $country_search == strtolower($country['code'])){ $results[] = [ 'value' => $country['code'], // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- This image is a plugin asset and not a WordPress attachment. 'label' => ' '.$country['name'] ]; } } wp_send_json( $results ); } public function formipay_delete_product() { check_ajax_referer( 'formipay-admin-product-page', '_wpnonce' ); $form_id = isset($_REQUEST['id']) ? intval($_REQUEST['id']) : ''; $delete = wp_delete_post($form_id, true); if(is_wp_error( $delete )){ wp_send_json_error( [ 'title' => esc_html__( 'Failed', 'formipay' ), 'message' => esc_html__( 'Failed to delete product. Please try again.', 'formipay' ), 'icon' => 'error' ] ); } wp_send_json_success( [ 'title' => esc_html__( 'Deleted', 'formipay' ), 'message' => esc_html__( 'Product is deleted permanently.', 'formipay' ), 'icon' => 'success' ] ); } public function formipay_bulk_delete_product() { check_ajax_referer( 'formipay-admin-product-page', '_wpnonce' ); if( empty($_REQUEST['ids']) ){ wp_send_json_error( [ 'title' => esc_html__( 'Failed', 'formipay' ), 'message' => esc_html__( 'There is no product selected. Please try again.', 'formipay' ), 'icon' => 'error' ] ); } $ids = isset($_REQUEST['ids']) ? $_REQUEST['ids'] : []; $success = 0; $failed = 0; if(!empty($ids)){ foreach($ids as $id){ $delete = wp_delete_post($id, true); if(is_wp_error( $delete )){ $failed++; }else{ $success++; } } } if($success > 0){ $report .= sprintf( __( ' Deleted %d product(s).', 'formipay' ), $success); } if($failed > 0){ $report .= sprintf( __( ' Failed %d product(s).', 'formipay' ), $failed); } wp_send_json_success( [ 'title' => esc_html__( 'Done!', 'formipay' ), 'message' => $report, 'icon' => 'info' ] ); } public function formipay_duplicate_product() { check_ajax_referer( 'formipay-admin-product-page', '_wpnonce' ); $post_id = isset($_REQUEST['id']) ? intval($_REQUEST['id']) : ''; $post = get_post($post_id); if (!$post) { wp_send_json_error( [ 'title' => esc_html__('Failed', 'formipay'), 'message' => esc_html__( 'Product is not defined.', 'formipay' ), 'icon' => 'error' ] ); } if (!in_array($post->post_type, ['formipay-product'])) { wp_send_json_error( [ 'title' => esc_html__('Failed', 'formipay'), 'message' => esc_html__( 'Wrong Post Type.', 'formipay' ), 'icon' => 'error' ] ); } $duplicate_post = [ 'post_title' => $post->post_title . ' (Copy)', 'post_content' => $post->post_content, 'post_status' => 'draft', // Set sebagai draft 'post_type' => $post->post_type, 'post_author' => $post->post_author, ]; $new_post_id = wp_insert_post($duplicate_post); if (is_wp_error($new_post_id)) { wp_send_json_error( [ 'title' => esc_html__('Failed', 'formipay'), 'message' => esc_html__( 'Something happened. Please try again.', 'formipay' ), 'icon' => 'error' ] ); } $meta_data = get_post_meta($post_id); foreach ($meta_data as $key => $values) { foreach ($values as $value) { update_post_meta($new_post_id, $key, maybe_unserialize($value)); } } $taxonomies = get_object_taxonomies($post->post_type); foreach ($taxonomies as $taxonomy) { $terms = wp_get_object_terms($post_id, $taxonomy, ['fields' => 'slugs']); wp_set_object_terms($new_post_id, $terms, $taxonomy); } wp_send_json_success( [ 'title' => esc_html__('Duplicated!', 'formipay'), 'message' => esc_html__( 'Product is successfully duplicated.', 'formipay' ), 'icon' => 'success' ] ); } public function get_product_variables() { $post_id = intval($_POST['post_id'] ?? 0); $data = get_post_meta($post_id, 'product_variables', true); $json = is_string($data) ? json_decode($data, true) : []; if(is_array($json)){ wp_send_json_success( $json ); } wp_send_json_error(); } public function save_product_depracated($post_id, $post) { // Verify nonce and permissions here if you have a nonce field (recommended) // Avoid autosave and revision saves if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return; if (wp_is_post_revision($post_id)) return; // Check user permissions if (!current_user_can('edit_post', $post_id)) return; if (isset($_POST['product_variables'])) { // Sanitize input (JSON string) $product_variables_json = wp_unslash($_POST['product_variables']); // Remove slashes added by WP $product_variables = json_decode($product_variables_json, true); if (json_last_error() === JSON_ERROR_NONE && is_array($product_variables)) { // Save the meta as JSON string or serialized array update_post_meta($post_id, 'product_variables', $product_variables_json); } else { // Invalid JSON, optionally delete meta or handle error delete_post_meta($post_id, 'product_variables'); } } } function save_product( $post_id ) { // 1. Verifikasi Nonce untuk keamanan if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ), 'update-post_' . $post_id ) ) { return; } // 2. Abaikan jika ini adalah autosave if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; } // 3. Periksa izin pengguna if ( ! current_user_can( 'edit_post', $post_id ) ) { return; } // 4. Periksa apakah data 'product_variables' dikirim if ( ! isset( $_POST['product_variables'] ) ) { // Jika tidak ada data, mungkin kita ingin menghapus meta yang lama delete_post_meta( $post_id, 'product_variables' ); return; } // 5. Ambil data, lakukan sanitasi dasar, dan simpan $variations_data_json = $_POST['product_variables']; // Sanitasi: wp_slash() penting untuk memastikan JSON string disimpan dengan benar, // terutama jika mengandung karakter kutip. $sanitized_variations_data = wp_unslash( $variations_data_json ); // Simpan data ke database. WordPress akan menangani serialisasi jika perlu. update_post_meta( $post_id, 'product_variables', $sanitized_variations_data ); } }