cap())) { wp_die(esc_html__('You do not have permission to access this page.', 'adverships-affiliate')); } echo '

' . esc_html__('Adverships — Creators', 'adverships-affiliate') . '

'; if (!Adverships_Affiliate_Client::is_connected()) { $url = admin_url('admin.php?page=adverships-settings'); echo '

' . esc_html__('Connect your store to see your creator partners here.', 'adverships-affiliate') . '

'; echo '

' . esc_html__('Go to Settings', 'adverships-affiliate') . '

'; return; } // Drilldown if ?creator= is present (read-only GET, no state change → no nonce needed). // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only GET, no state change. $creator = isset($_GET['creator']) ? sanitize_text_field(wp_unslash($_GET['creator'])) : ''; if ($creator !== '') { $this->render_drilldown($creator); echo ''; return; } $res = Adverships_Affiliate_Client::post_signed('/api/wordpress/creators.php', array(), true); if (is_wp_error($res) || empty($res['data']['ok'])) { $this->render_error($res); echo ''; return; } // Pending partner requests banner — show before the roster so it's // visible even when there are no accepted partners yet. Adverships_Affiliate_Pending::render_banner(isset($res['data']['pending']) ? $res['data']['pending'] : array()); $rows = isset($res['data']['creators']) ? $res['data']['creators'] : array(); if (empty($rows)) { echo '

' . esc_html__('No creator partners yet.', 'adverships-affiliate') . '

'; return; } echo ''; foreach (array( __('Creator', 'adverships-affiliate'), __('Model', 'adverships-affiliate'), __('Connections', 'adverships-affiliate'), __('Clicks', 'adverships-affiliate'), __('Sales', 'adverships-affiliate'), __('Revenue', 'adverships-affiliate'), __('Earned', 'adverships-affiliate'), __('You owe', 'adverships-affiliate'), ) as $h) { echo ''; } echo ''; foreach ($rows as $r) { $name = !empty($r['display_name']) ? $r['display_name'] : (isset($r['creator']) ? $r['creator'] : ''); $link = add_query_arg(array('page' => 'adverships-creators', 'creator' => isset($r['creator']) ? $r['creator'] : ''), admin_url('admin.php')); $conns = (int) ($r['connections'] ?? 0) + (int) ($r['campaigns'] ?? 0); echo ''; echo ''; echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built from esc_* in helper echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; } echo '
' . esc_html($h) . '
' . esc_html($name) . '
' . esc_html(isset($r['bizcode']) ? $r['bizcode'] : '') . '
' . $this->model_pill(isset($r['model']) ? $r['model'] : '') . '' . esc_html(number_format_i18n($conns)) . '' . esc_html(number_format_i18n((int) ($r['clicks'] ?? 0))) . '' . esc_html(number_format_i18n((int) ($r['sales'] ?? 0))) . '' . esc_html($this->money($r['revenue'] ?? 0)) . '' . esc_html($this->money($r['earned'] ?? 0)) . '' . esc_html($this->money($r['owed'] ?? 0)) . '
'; echo ''; } private function render_drilldown($creator) { $res = Adverships_Affiliate_Client::post_signed('/api/wordpress/creators.php', array('creator' => $creator), true); $back = '

← ' . esc_html__('All creators', 'adverships-affiliate') . '

'; if (is_wp_error($res) || empty($res['data']['ok'])) { echo $back; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built from esc_* above $this->render_error($res); return; } $d = $res['data']; $name = !empty($d['display_name']) ? $d['display_name'] : $d['creator']; echo $back; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built from esc_* above echo '

' . esc_html($name) . '

'; echo '

' . sprintf( /* translators: 1: earned, 2: owed */ esc_html__('Earned: %1$s · You owe: %2$s', 'adverships-affiliate'), esc_html($this->money($d['earned'] ?? 0)), esc_html($this->money($d['owed'] ?? 0)) ) . '

'; $breakdown = isset($d['breakdown']) ? $d['breakdown'] : array(); echo '

' . esc_html__('By source', 'adverships-affiliate') . '

'; if (empty($breakdown)) { echo '

' . esc_html__('No earnings recorded yet.', 'adverships-affiliate') . '

'; } else { echo ''; foreach ($breakdown as $b) { $src = (isset($b['source_type']) ? ucfirst($b['source_type']) : '') . ' #' . (isset($b['source_id']) ? $b['source_id'] : ''); echo ''; echo ''; echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- esc in helper echo ''; echo ''; echo ''; } echo '
' . esc_html__('Source', 'adverships-affiliate') . '' . esc_html__('Model', 'adverships-affiliate') . '' . esc_html__('Funding', 'adverships-affiliate') . '' . esc_html__('Amount', 'adverships-affiliate') . '
' . esc_html($src) . '' . $this->model_pill(isset($b['pay_type']) ? $b['pay_type'] : '') . '' . esc_html(isset($b['funding_type']) ? ucfirst($b['funding_type']) : '') . '' . esc_html($this->money($b['amount'] ?? 0)) . '
'; } echo '
'; } // ---- helpers ---------------------------------------------------------- private function model_pill($model) { $model = $model === '' ? '—' : $model; $cls = 'adverships-pill adverships-pill--' . preg_replace('/[^a-z]/', '', strtolower($model)); return '' . esc_html(ucfirst($model)) . ''; } private function money($amount) { $amount = (float) $amount; if (function_exists('wc_price')) { return wp_strip_all_tags(wc_price($amount)); } return number_format_i18n($amount, 2); } private function render_error($res) { $msg = is_wp_error($res) ? $res->get_error_message() : (isset($res['data']['error']) ? $res['data']['error'] : __('Could not load data from Adverships.', 'adverships-affiliate')); echo '

' . esc_html($msg) . '

'; } private function cap() { return current_user_can('manage_woocommerce') ? 'manage_woocommerce' : 'manage_options'; } }