'ac_coupon_type', 'label' => __('Coupon Type', 'adscout'), 'options' => array( 'default' => __('Default', 'adscout'), 'adscout_influencer' => __('Adscout Influencer', 'adscout'), ), 'value' => $selected_coupon_type, )); } public static function save_custom_coupon_option($post_id) { if (isset($_POST['ac_coupon_type'])) { $coupon_type = sanitize_text_field(wp_unslash($_POST['ac_coupon_type'])); update_post_meta($post_id, 'ac_coupon_type', $coupon_type); } } public static function create_coupon_via_api_url() { register_rest_route(ADSCOUT_API_ENDPOINT_PREFIX, ADSCOUT_API_ENDPOINT_NAME, array( 'methods' => 'POST', 'callback' => array(__CLASS__, 'handle_coupon_request'), 'permission_callback' => array(__CLASS__, 'authenticate_coupon_via_api_request'), )); } public static function handle_coupon_request(WP_REST_Request $request) { if (!defined('WC_VERSION')) { return; } $coupon_data_raw = $request->get_json_params(); if (empty($coupon_data_raw)) { wp_send_json_error(array('message' => __('Invalid JSON data provided', 'adscout')), 400); } $required_fields = array( 'action', 'code', ); if (array_key_exists('action', $coupon_data_raw) and $coupon_data_raw['action'] !== 'read') { $required_fields = array( 'action', 'code', 'discount', ); } $coupon_data_raw_keys = array_keys($coupon_data_raw); $intersect = array_intersect($required_fields, $coupon_data_raw_keys); if (count($intersect) !== count($required_fields)) { wp_send_json_error( array('message' => __('Missing required parameters', 'adscout') . ': ' . implode(', ', array_diff($required_fields, $coupon_data_raw_keys))), 422 ); } $allowed_actions = array( 'create', 'read', 'update', 'delete', 'disable', ); if (!in_array($coupon_data_raw['action'], $allowed_actions)) { wp_send_json_error( array('message' => __('Unknown action', 'adscout')), 422 ); } if ($coupon_data_raw['action'] === 'create') { self::create_coupon($coupon_data_raw); } if ($coupon_data_raw['action'] === 'read') { self::read_coupon($coupon_data_raw); } if ($coupon_data_raw['action'] === 'update') { self::update_coupon($coupon_data_raw); } if ($coupon_data_raw['action'] === 'disable') { self::disable_coupon($coupon_data_raw); } if ($coupon_data_raw['action'] === 'delete') { self::delete_coupon($coupon_data_raw); } wp_send_json_error(array( 'message' => __('Something unexpected went wrong', 'adscout') . '.' ), 200); } public static function authenticate_coupon_via_api_request(WP_REST_Request $request): bool { $token = (new AdScout_Options())::all_options()['adscout_api_token']; $header = (string)$request->get_header('authorization'); return is_string($token) and $token !== '' and str_starts_with($header, 'Bearer ') and hash_equals($token, substr($header, 7)); } public static function create_coupon($coupon_data) { $errors = array(); if (!array_key_exists('code', $coupon_data)) { $errors[] = __('Missing required parameter \'code\'', 'adscout'); } if (!array_key_exists('discount', $coupon_data)) { $errors[] = __('Missing required parameter \'discount\'', 'adscout'); } if (!is_int($coupon_data['discount'])) { $errors[] = __('Parameter \'discount\' is not an integer', 'adscout'); } if ($coupon_data['discount'] < 0) { $errors[] = __('Parameter \'discount\' cannot have a value below 0', 'adscout'); } if ( array_key_exists('discount_type', $coupon_data) and $coupon_data['discount_type'] === 'percent' and ($coupon_data['discount'] > 100 or $coupon_data['discount'] < 0) ) { $errors[] = __('Percent discount must be between 0 and 100', 'adscout'); } if (array_key_exists('date_from', $coupon_data)) { $date_from = DateTime::createFromFormat('d-m-Y', $coupon_data['date_from']); $today = new DateTime(); $tomorrow = $today->modify('+1 day'); if ($date_from < $tomorrow) { $errors[] = __('The \'date_from\' must be at least one day in the future.', 'adscout'); } } if (array_key_exists('date_to', $coupon_data)) { $date_from = DateTime::createFromFormat('d-m-Y', $coupon_data['date_to']); $today = new DateTime(); $tomorrow = $today->modify('+1 day'); if ($date_from < $tomorrow) { $errors[] = __('The \'date_from\' must be at least one day in the future.', 'adscout'); } } if (wc_get_coupon_id_by_code($coupon_data['code'])) { $errors[] = __('Coupon exists. Try a new one', 'adscout'); } if (count($errors) > 0) { wp_send_json_error(array('errors' => $errors), 422); } $coupon = new WC_Coupon(); $coupon->set_code($coupon_data['code']); $coupon->set_discount_type($coupon_data['discount_type'] ?? 'percent'); $coupon->set_amount($coupon_data['discount']); if (array_key_exists('date_to', $coupon_data)) { $coupon->set_date_expires($coupon_data['date_to']); } if (array_key_exists('individual_use', $coupon_data)) { $coupon->set_individual_use(boolval($coupon_data['individual_use'])); } $coupon->set_description(__('AdScout influencer coupon', 'adscout')); $coupon->save(); if (array_key_exists('date_from', $coupon_data)) { $publish_date = DateTime::createFromFormat('d-m-Y', $coupon_data['date_from']); $updated_post = array( 'ID' => $coupon->get_id(), 'post_date' => $publish_date->format('Y-m-d 00:00:00'), 'post_date_gmt' => get_gmt_from_date($publish_date->format('Y-m-d 00:00:00')), 'edit_date' => true, 'post_status' => 'future' ); wp_update_post($updated_post); } add_post_meta($coupon->get_id(), 'ac_coupon_type', 'adscout_influencer'); add_post_meta($coupon->get_id(), 'ac_coupon_source', 'adscout_api'); return self::format_coupon_response($coupon->get_id(), 'create', array_key_exists('date_from', $coupon_data) ? $publish_date->format('DD-MM-YYYY HH:mm:ss') : null); } public static function read_coupon($coupon_data) { $coupon_id = self::get_coupon_id($coupon_data['code']); if (!$coupon_id) { wp_send_json_error(array('message' => __('Coupon not found', 'adscout')), 404); } return self::format_coupon_response($coupon_id, 'read'); } public static function update_coupon($coupon_data) { $coupon_id = self::get_coupon_id($coupon_data['code']); if (!$coupon_id) { // new WC_Coupon(null)->save() would silently create a new coupon wp_send_json_error(array('message' => __('Coupon not found', 'adscout')), 404); } $coupon = new WC_Coupon($coupon_id); $updates = false; if (array_key_exists('discount', $coupon_data)) { $coupon->set_amount($coupon_data['discount']); $updates = true; } if (array_key_exists('discount_type', $coupon_data)) { $coupon->set_discount_type($coupon_data['discount_type']); $updates = true; } if (array_key_exists('date_from', $coupon_data)) { $publish_date = DateTime::createFromFormat('d-m-Y', $coupon_data['date_from']); $updated_post = array( 'ID' => $coupon->get_id(), 'post_date' => $publish_date->format('Y-m-d 00:00:00'), 'post_date_gmt' => get_gmt_from_date($publish_date->format('Y-m-d 00:00:00')), 'edit_date' => true, 'post_status' => 'future' ); wp_update_post($updated_post); $updates = true; } if (array_key_exists('date_to', $coupon_data)) { $coupon->set_date_expires($coupon_data['date_to']); $updates = true; } if (array_key_exists('individual_use', $coupon_data)) { $coupon->set_individual_use(boolval($coupon_data['individual_use'])); $updates = true; } $coupon->save(); return self::format_coupon_response($coupon->get_id(), 'update', array_key_exists('date_from', $coupon_data) ? $publish_date->format('DD-MM-YYYY HH:mm:ss') : null); } public static function delete_coupon($coupon_data) { $coupon_id = self::get_coupon_id($coupon_data['code']); if (!$coupon_id) { wp_send_json_error(array('message' => __('Coupon not found', 'adscout')), 404); } $result = wp_delete_post($coupon_id, true); if (!$result) { /* translators: %s: The coupon code. */ wp_send_json_error(array('message' => sprintf(__('Failed to delete coupon \'%s\'', 'adscout'), $coupon_data['code'])), 500); } /* translators: %s: The coupon code. */ wp_send_json_success(array('message' => sprintf(__('Deleted coupon \'%s\'', 'adscout'), $coupon_data['code']))); } public static function disable_coupon($coupon_data) { $coupon_id = self::get_coupon_id($coupon_data['code']); if (!$coupon_id) { wp_send_json_error(array('message' => __('Coupon not found', 'adscout')), 404); } $post_update = array( 'ID' => $coupon_id, // ID of the post you want to update; gathered while fetching the coupon. 'post_status' => 'draft', // Setting the status to 'draft' ); $update = wp_update_post($post_update); if (is_wp_error($update)) { /* translators: %s: The coupon code. */ wp_send_json_error(array('message' => sprintf(__('Failed to set coupon \'%s\' status to \'draft\'', 'adscout'), $coupon_data['code'])), 500); } return self::format_coupon_response($coupon_id, 'disable', null); } /** * Apply a coupon via URL parameter 'aspc' if present. * * Checks if WooCommerce is active, creates a session if not already existent, and processes the coupon code if 'aspc' parameter is present in the URL. * * @return void */ public static function add_coupon_via_url() { if (!defined('WC_VERSION')) { return; } if (!WC()->session->has_session()) { WC()->session->set_customer_session_cookie(true); } global $wp; $current_url = home_url(add_query_arg(array(), $wp->request)); if (isset($_GET['aspc'])) { if (isset($_GET['aspc'])) { $coupon_code = sanitize_text_field(wp_unslash($_GET['aspc'])); WC()->cart->add_discount($coupon_code); } WC()->session->save_data(); WC()->cart->calculate_totals(); $query = $_GET; unset($query['aspc']); $url = $current_url; $queryString = http_build_query($query); if (!empty($queryString)) { $url .= '?' . $queryString; } wp_safe_redirect($url); } } public static function get_coupon_id($code) { global $wpdb; $cache_key = 'coupon_id_' . $code; $coupon_id = wp_cache_get($cache_key, 'adscout'); if (false === $coupon_id) { $coupon_id = $wpdb->get_var($wpdb->prepare(" SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type = 'shop_coupon' ", $code)); if ($coupon_id) { wp_cache_set($cache_key, $coupon_id, 'adscout'); } } return $coupon_id; } public static function format_coupon_response_data($coupon_id, $action, $current_status = null, $date_from = null) { $coupon = new WC_Coupon($coupon_id); if ($current_status === null) { $current_status = 'active'; } if ($date_from === null) { $date_from = $coupon->get_date_created(); } return array( 'action' => $action, 'current_status' => $current_status, 'code' => $coupon->get_code(), 'discount' => $coupon->get_amount(), 'discount_type' => $coupon->get_discount_type(), 'date_from' => $date_from->format('d-m-Y H:i'), 'date_to' => $coupon->get_date_expires() ? $coupon->get_date_expires()->format('d-m-Y H:i') : false, 'individual_use' => $coupon->get_individual_use(), ); } public static function format_coupon_response($coupon_id, $action, $current_status = null, $date_from = null) { wp_send_json_success(self::format_coupon_response_data($coupon_id, $action, $current_status = null, $date_from = null)); die(); } public static function shop_coupon_adscout_request($post_id, $post, $update) { if ($post->post_type != 'shop_coupon') { return; } if ( !get_post_meta($post_id, 'ac_coupon_type') or get_post_meta($post_id, 'ac_coupon_type') !== 'adscout_influencer' or ( isset($_POST['ac_coupon_type']) and $_POST['ac_coupon_type'] === 'adscout_influencer' ) ) { return; } (new AdScout_Request())::post('handle_coupon', wp_json_encode(self::format_coupon_response_data($post_id, $update ? 'update' : 'create', $current_status = null, $date_from = null))); } }