feat: Affiliate program enrichment (Link Builder, Curated Collections, Smart Links)

This commit is contained in:
Dwindi Ramadhana
2026-06-03 14:04:17 +07:00
parent fd8eb38512
commit f8c733832e
22 changed files with 1348 additions and 10 deletions

View File

@@ -48,6 +48,33 @@ class AffiliateCustomerController
'callback' => [$this, 'update_payment_details'],
'permission_callback' => [$this, 'check_permission'],
]);
// Affiliate Collections
register_rest_route($this->namespace, '/account/affiliate/collections', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => [$this, 'get_collections'],
'permission_callback' => [$this, 'check_permission'],
],
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => [$this, 'create_collection'],
'permission_callback' => [$this, 'check_permission'],
]
]);
register_rest_route($this->namespace, '/account/affiliate/collections/(?P<id>\d+)', [
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => [$this, 'update_collection'],
'permission_callback' => [$this, 'check_permission'],
],
[
'methods' => WP_REST_Server::DELETABLE,
'callback' => [$this, 'delete_collection'],
'permission_callback' => [$this, 'check_permission'],
]
]);
}
public function check_permission()
@@ -89,6 +116,12 @@ class AffiliateCustomerController
$affiliate['commission_rate'] = $effective_rate;
$affiliate['total_earnings'] = $earnings->total_earnings ?: 0;
$affiliate['pending_earnings'] = $earnings->pending_earnings ?: 0;
if (class_exists('\WooNooW\Modules\Affiliate\AffiliateSettings')) {
$affiliate['collections_enabled'] = \WooNooW\Modules\Affiliate\AffiliateSettings::get_setting('woonoow_affiliate_enable_curated_collections', true);
} else {
$affiliate['collections_enabled'] = true;
}
return rest_ensure_response($affiliate);
}
@@ -318,4 +351,125 @@ class AffiliateCustomerController
return $sanitized;
}
// --- Collections ---
public function get_collections(WP_REST_Request $request)
{
if (class_exists('\WooNooW\Modules\Affiliate\AffiliateSettings') && !\WooNooW\Modules\Affiliate\AffiliateSettings::get_setting('woonoow_affiliate_enable_curated_collections', true)) {
return new \WP_Error('rest_forbidden', 'Curated collections are disabled.', ['status' => 403]);
}
global $wpdb;
$user_id = get_current_user_id();
$affiliate_table = $wpdb->prefix . 'woonoow_affiliates';
$collections_table = $wpdb->prefix . 'woonoow_affiliate_collections';
$affiliate = $wpdb->get_row($wpdb->prepare("SELECT id, referral_code FROM $affiliate_table WHERE user_id = %d", $user_id));
if (!$affiliate) {
return rest_ensure_response([]);
}
$collections = $wpdb->get_results($wpdb->prepare("SELECT * FROM $collections_table WHERE affiliate_id = %d ORDER BY created_at DESC", $affiliate->id), ARRAY_A);
foreach ($collections as &$collection) {
$collection['product_ids'] = $collection['product_ids'] ? json_decode($collection['product_ids'], true) : [];
$collection['link'] = site_url("/collection/{$collection['slug']}");
}
return rest_ensure_response($collections);
}
public function create_collection(WP_REST_Request $request)
{
global $wpdb;
$user_id = get_current_user_id();
$affiliate_table = $wpdb->prefix . 'woonoow_affiliates';
$collections_table = $wpdb->prefix . 'woonoow_affiliate_collections';
$affiliate = $wpdb->get_row($wpdb->prepare("SELECT id FROM $affiliate_table WHERE user_id = %d", $user_id));
if (!$affiliate) {
return new \WP_Error('not_found', 'Affiliate profile not found', ['status' => 404]);
}
$title = sanitize_text_field($request->get_param('title'));
$description = sanitize_textarea_field($request->get_param('description'));
$product_ids = $request->get_param('product_ids');
if (!is_array($product_ids)) $product_ids = [];
$product_ids = array_map('intval', $product_ids);
if (count($product_ids) > 20) {
return new \WP_Error('too_many_products', 'A collection can have a maximum of 20 products.', ['status' => 400]);
}
$slug = sanitize_title($title);
// Check unique slug for this affiliate
$existing = $wpdb->get_var($wpdb->prepare("SELECT id FROM $collections_table WHERE affiliate_id = %d AND slug = %s", $affiliate->id, $slug));
if ($existing) {
$slug .= '-' . wp_generate_password(4, false);
}
$data = [
'affiliate_id' => $affiliate->id,
'title' => $title,
'slug' => $slug,
'description' => $description,
'product_ids' => json_encode($product_ids)
];
$wpdb->insert($collections_table, $data);
$data['id'] = $wpdb->insert_id;
$data['product_ids'] = $product_ids;
return rest_ensure_response($data);
}
public function update_collection(WP_REST_Request $request)
{
global $wpdb;
$user_id = get_current_user_id();
$id = (int) $request->get_param('id');
$affiliate_table = $wpdb->prefix . 'woonoow_affiliates';
$collections_table = $wpdb->prefix . 'woonoow_affiliate_collections';
$affiliate = $wpdb->get_row($wpdb->prepare("SELECT id FROM $affiliate_table WHERE user_id = %d", $user_id));
if (!$affiliate) return new \WP_Error('unauthorized', 'Unauthorized', ['status' => 401]);
$collection = $wpdb->get_row($wpdb->prepare("SELECT id FROM $collections_table WHERE id = %d AND affiliate_id = %d", $id, $affiliate->id));
if (!$collection) return new \WP_Error('not_found', 'Collection not found', ['status' => 404]);
$title = sanitize_text_field($request->get_param('title'));
$description = sanitize_textarea_field($request->get_param('description'));
$product_ids = $request->get_param('product_ids');
if (!is_array($product_ids)) $product_ids = [];
$product_ids = array_map('intval', $product_ids);
if (count($product_ids) > 20) {
return new \WP_Error('too_many_products', 'A collection can have a maximum of 20 products.', ['status' => 400]);
}
$wpdb->update($collections_table, [
'title' => $title,
'description' => $description,
'product_ids' => json_encode($product_ids)
], ['id' => $id]);
return rest_ensure_response(['success' => true]);
}
public function delete_collection(WP_REST_Request $request)
{
global $wpdb;
$user_id = get_current_user_id();
$id = (int) $request->get_param('id');
$affiliate_table = $wpdb->prefix . 'woonoow_affiliates';
$collections_table = $wpdb->prefix . 'woonoow_affiliate_collections';
$affiliate = $wpdb->get_row($wpdb->prepare("SELECT id FROM $affiliate_table WHERE user_id = %d", $user_id));
if (!$affiliate) return new \WP_Error('unauthorized', 'Unauthorized', ['status' => 401]);
$wpdb->delete($collections_table, ['id' => $id, 'affiliate_id' => $affiliate->id]);
return rest_ensure_response(['success' => true]);
}
}