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 '
';
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 '| ' . esc_html($h) . ' | ';
}
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 '' . esc_html($name) . ' ' . esc_html(isset($r['bizcode']) ? $r['bizcode'] : '') . ' | ';
echo '' . $this->model_pill(isset($r['model']) ? $r['model'] : '') . ' | '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built from esc_* in helper
echo '' . esc_html(number_format_i18n($conns)) . ' | ';
echo '' . esc_html(number_format_i18n((int) ($r['clicks'] ?? 0))) . ' | ';
echo '' . esc_html(number_format_i18n((int) ($r['sales'] ?? 0))) . ' | ';
echo '' . esc_html($this->money($r['revenue'] ?? 0)) . ' | ';
echo '' . esc_html($this->money($r['earned'] ?? 0)) . ' | ';
echo '' . esc_html($this->money($r['owed'] ?? 0)) . ' | ';
echo '
';
}
echo '
';
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 '
| ' . esc_html__('Source', 'adverships-affiliate') . ' | ' . esc_html__('Model', 'adverships-affiliate') . ' | ' . esc_html__('Funding', 'adverships-affiliate') . ' | ' . esc_html__('Amount', 'adverships-affiliate') . ' |
';
foreach ($breakdown as $b) {
$src = (isset($b['source_type']) ? ucfirst($b['source_type']) : '') . ' #' . (isset($b['source_id']) ? $b['source_id'] : '');
echo '';
echo '| ' . esc_html($src) . ' | ';
echo '' . $this->model_pill(isset($b['pay_type']) ? $b['pay_type'] : '') . ' | '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- esc in helper
echo '' . esc_html(isset($b['funding_type']) ? ucfirst($b['funding_type']) : '') . ' | ';
echo '' . esc_html($this->money($b['amount'] ?? 0)) . ' | ';
echo '
';
}
echo '
';
}
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 '';
}
private function cap() {
return current_user_can('manage_woocommerce') ? 'manage_woocommerce' : 'manage_options';
}
}