$method, 'timeout' => 20, 'headers' => array( 'Authorization' => 'Bearer ' . $key, 'Accept' => 'application/json', 'User-Agent' => 'Diretsa-WordPress/' . DIRETSA_VERSION . '; ' . home_url('/'), ), )); if (is_wp_error($response)) { /* translators: %s: the network error message. */ return new WP_Error('diretsa_unreachable', sprintf(__('Diretsa could not be reached: %s', 'diretsa'), $response->get_error_message())); } $code = (int) wp_remote_retrieve_response_code($response); $body = json_decode(wp_remote_retrieve_body($response), true); if ($code < 200 || $code >= 300) { /* translators: %d: HTTP status code. */ $message = is_array($body) && !empty($body['error']) ? $body['error'] : sprintf(__('Diretsa answered with HTTP %d.', 'diretsa'), $code); return new WP_Error('diretsa_http_' . $code, $message); } return is_array($body) ? $body : array(); } /** Fetch the site, its placements and tags, and keep them for the front end. */ function diretsa_refresh($key = null) { $data = diretsa_api('GET', '/wp/v1/site', $key); if (is_wp_error($data)) { return $data; } update_option('diretsa_site', $data, true); update_option('diretsa_site_fetched', time(), false); return $data; } /** The cached site data, or an empty array. */ function diretsa_site() { $data = get_option('diretsa_site', array()); return is_array($data) ? $data : array(); } /** One placement from the cache, by product id. */ function diretsa_placement($product_id) { $site = diretsa_site(); foreach ((isset($site['placements']) ? $site['placements'] : array()) as $p) { if (isset($p['product_id']) && $p['product_id'] === $product_id) { return $p; } } return null; } /* ---------------------------------------------------- Keep tags current */ register_activation_hook(__FILE__, function () { if (!wp_next_scheduled('diretsa_refresh_event')) { wp_schedule_event(time() + HOUR_IN_SECONDS, 'twicedaily', 'diretsa_refresh_event'); } }); register_deactivation_hook(__FILE__, function () { wp_clear_scheduled_hook('diretsa_refresh_event'); }); add_action('diretsa_refresh_event', function () { if (get_option('diretsa_key')) { diretsa_refresh(); } }); /* ---------------------------------------------------- Verification tag */ /** Until Diretsa has checked the site, put its verification tag in the page head. */ add_action('wp_head', function () { $site = diretsa_site(); if (empty($site['site']) || !empty($site['site']['verified']) || empty($site['site']['verification']['token'])) { return; } printf("\n", esc_attr($site['site']['verification']['token'])); }, 1); /* ------------------------------------------------------- Showing ads */ /** * Is this the address of Diretsa's ad server script? Only https addresses on * diretsa.com (or its subdomains) are loaded. */ function diretsa_is_ad_script_url($url) { $parts = wp_parse_url($url); if (empty($parts['scheme']) || 'https' !== $parts['scheme'] || empty($parts['host'])) { return false; } $host = strtolower($parts['host']); return 'diretsa.com' === $host || '.diretsa.com' === substr($host, -12); } /** * The ad slot for a placement: Diretsa's ad server fills each element * with the ad booked for that zone. The markup is built here from the zone * numbers Diretsa sends, and the ad server's script is loaded with * wp_enqueue_script(), so no HTML or script from the API is printed. */ function diretsa_render_ad($product_id) { $product_id = sanitize_text_field((string) $product_id); $p = $product_id ? diretsa_placement($product_id) : null; $zones = ($p && !empty($p['ad']) && is_array($p['ad'])) ? $p['ad'] : array(); $slots = ''; foreach ($zones as $zone) { $zone_id = isset($zone['zone_id']) ? absint($zone['zone_id']) : 0; $revive_id = isset($zone['revive_id']) ? preg_replace('/[^a-f0-9]/', '', strtolower((string) $zone['revive_id'])) : ''; $script = isset($zone['script_url']) ? (string) $zone['script_url'] : ''; if (!$zone_id || 32 !== strlen($revive_id) || !diretsa_is_ad_script_url($script)) { continue; } $slots .= sprintf('', $zone_id, esc_attr($revive_id)); if (!wp_script_is('diretsa-ads', 'enqueued')) { wp_enqueue_script('diretsa-ads', esc_url_raw($script), array(), null, array('in_footer' => true, 'strategy' => 'async')); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion -- the ad server's script, versioned by the ad server. } } if ('' === $slots) { return current_user_can('manage_options') /* translators: %s: the placement ID used in the shortcode or block. */ ? '' : ''; } $size = isset($p['size']) ? sanitize_html_class($p['size']) : ''; return '
' . $slots . '
'; } add_shortcode('diretsa_ad', function ($atts) { $atts = shortcode_atts(array('id' => ''), $atts, 'diretsa_ad'); return diretsa_render_ad($atts['id']); }); /** Block: "Diretsa ad". Rendered on the server so the tag always comes from the cache. */ add_action('init', function () { wp_register_script('diretsa-block', plugins_url('assets/block.js', __FILE__), array('wp-blocks', 'wp-element', 'wp-components', 'wp-block-editor', 'wp-i18n'), DIRETSA_VERSION, true); register_block_type('diretsa/ad', array( 'api_version' => 2, 'editor_script' => 'diretsa-block', 'attributes' => array('placement' => array('type' => 'string', 'default' => '')), 'render_callback' => function ($attributes) { return diretsa_render_ad(isset($attributes['placement']) ? $attributes['placement'] : ''); }, )); }); add_action('enqueue_block_editor_assets', function () { $site = diretsa_site(); $options = array(); foreach ((isset($site['placements']) ? $site['placements'] : array()) as $p) { if (!empty($p['ad'])) { $options[] = array('value' => $p['product_id'], 'label' => $p['name'] . ' (' . $p['size'] . ')'); } } wp_localize_script('diretsa-block', 'diretsaPlacements', $options); }); /** Classic widget: "Diretsa ad". */ class Diretsa_Ad_Widget extends WP_Widget { public function __construct() { parent::__construct('diretsa_ad', __('Diretsa ad', 'diretsa'), array('description' => __('Shows one of your Diretsa ad placements.', 'diretsa'))); } public function widget($args, $instance) { $html = diretsa_render_ad(isset($instance['placement']) ? $instance['placement'] : ''); if ($html !== '') { echo $args['before_widget'] . $html . $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- before/after_widget come from the theme; $html is built from escaped parts in diretsa_render_ad(). } } public function form($instance) { $current = isset($instance['placement']) ? $instance['placement'] : ''; $site = diretsa_site(); echo '

'; echo '

'; } public function update($new, $old) { return array('placement' => sanitize_text_field(isset($new['placement']) ? $new['placement'] : '')); } } add_action('widgets_init', function () { register_widget('Diretsa_Ad_Widget'); }); /* ------------------------------------------------------------- Admin */ add_action('admin_menu', function () { add_options_page(__('Diretsa', 'diretsa'), __('Diretsa', 'diretsa'), 'manage_options', 'diretsa', 'diretsa_settings_page'); }); add_filter('plugin_action_links_' . plugin_basename(__FILE__), function ($links) { array_unshift($links, '' . esc_html__('Settings', 'diretsa') . ''); return $links; }); /** Handle the settings page's buttons (connect, refresh, verify, disconnect). */ add_action('admin_post_diretsa', function () { if (!current_user_can('manage_options')) { wp_die(esc_html__('You are not allowed to do this.', 'diretsa')); } check_admin_referer('diretsa_action'); $action = isset($_POST['diretsa_action']) ? sanitize_key(wp_unslash($_POST['diretsa_action'])) : ''; $notice = ''; $type = 'success'; if ($action === 'connect') { $key = isset($_POST['diretsa_key']) ? trim(sanitize_text_field(wp_unslash($_POST['diretsa_key']))) : ''; if (strpos($key, 'dwp_') !== 0) { $notice = __('That is not a Diretsa connection key. It starts with dwp_ and is shown once when you create it in Media Control.', 'diretsa'); $type = 'error'; } else { $data = diretsa_refresh($key); if (is_wp_error($data)) { $notice = $data->get_error_message(); $type = 'error'; } else { update_option('diretsa_key', $key, false); /* translators: %s: the site's name in Diretsa. */ $notice = sprintf(__('Connected to %s.', 'diretsa'), $data['site']['name']); } } } elseif ($action === 'refresh') { $data = diretsa_refresh(); $notice = is_wp_error($data) ? $data->get_error_message() : __('Placements and ad tags updated.', 'diretsa'); $type = is_wp_error($data) ? 'error' : 'success'; } elseif ($action === 'verify') { $r = diretsa_api('POST', '/wp/v1/verify'); if (is_wp_error($r)) { $notice = $r->get_error_message(); $type = 'error'; } elseif (!empty($r['verified'])) { diretsa_refresh(); $notice = __('Your site is verified. You can now add placements in Media Control and they will appear here.', 'diretsa'); } else { $notice = __('Diretsa could not find the verification tag yet. If you use a caching plugin, clear its cache, then try again.', 'diretsa'); $type = 'warning'; } } elseif ($action === 'disconnect') { delete_option('diretsa_key'); delete_option('diretsa_site'); delete_option('diretsa_site_fetched'); delete_transient('diretsa_earnings'); $notice = __('Disconnected. Ads from Diretsa no longer appear on this site. Revoke the key in Media Control too.', 'diretsa'); } set_transient('diretsa_notice_' . get_current_user_id(), array('text' => $notice, 'type' => $type), 60); wp_safe_redirect(admin_url('options-general.php?page=diretsa')); exit; }); /** Earnings for the last 30 days, cached for an hour. */ function diretsa_earnings() { $cached = get_transient('diretsa_earnings'); if (is_array($cached)) { return $cached; } $data = diretsa_api('GET', '/wp/v1/earnings'); if (!is_wp_error($data)) { set_transient('diretsa_earnings', $data, HOUR_IN_SECONDS); } return $data; } function diretsa_rand($n) { return 'R' . number_format((float) $n, 2, '.', ' '); } function diretsa_earnings_box() { $e = diretsa_earnings(); if (is_wp_error($e)) { echo '

' . esc_html($e->get_error_message()) . '

'; return; } $s = $e['site']; echo ''; printf('', esc_html__('Earnings (last 30 days)', 'diretsa'), esc_html(diretsa_rand($s['earnings']))); printf('', esc_html__('Ready to pay', 'diretsa'), esc_html(diretsa_rand($s['earnings_available']))); printf('', esc_html__('Held (checks or dispute window)', 'diretsa'), esc_html(diretsa_rand($s['earnings_held']))); printf('', esc_html__('Impressions', 'diretsa'), esc_html(number_format_i18n((int) $s['impressions']))); printf('', esc_html__('Clicks', 'diretsa'), esc_html(number_format_i18n((int) $s['clicks']))); if (!empty($e['next_payout'])) { $np = $e['next_payout']; $line = !empty($np['not_payable_because']) /* translators: 1: payout date, 2: why it cannot be paid yet. */ ? sprintf(__('%1$s (not paid yet: %2$s)', 'diretsa'), $np['date'], $np['not_payable_because']) /* translators: 1: amount in rand, 2: payout date. */ : sprintf(__('%1$s on %2$s', 'diretsa'), diretsa_rand($np['amount']), $np['date']); printf('', esc_html__('Next payout (whole organisation)', 'diretsa'), esc_html($line)); } echo '
%s%s
%s%s
%s%s
%s%s
%s%s
%s%s
'; printf('

%s

', esc_html($e['note'])); } add_action('wp_dashboard_setup', function () { if (current_user_can('manage_options') && get_option('diretsa_key')) { wp_add_dashboard_widget('diretsa_earnings', __('Diretsa earnings', 'diretsa'), 'diretsa_earnings_box'); } }); function diretsa_button($action, $label, $class = 'button') { echo '
'; wp_nonce_field('diretsa_action'); echo ''; echo '
'; } function diretsa_settings_page() { if (!current_user_can('manage_options')) { return; } $notice = get_transient('diretsa_notice_' . get_current_user_id()); delete_transient('diretsa_notice_' . get_current_user_id()); $key = get_option('diretsa_key', ''); $data = diretsa_site(); $site = isset($data['site']) ? $data['site'] : null; echo '

' . esc_html__('Diretsa', 'diretsa') . '

'; if ($notice && $notice['text']) { printf('

%s

', esc_attr($notice['type']), esc_html($notice['text'])); } if (!$key || !$site) { echo '

' . esc_html__('Connect your site', 'diretsa') . '

    '; /* translators: %s: link to Diretsa Media Control. */ echo '
  1. ' . wp_kses_post(sprintf(__('Sign in to Diretsa Media Control. Add this site under My sites if it is not there yet.', 'diretsa'), 'https://diretsa.com/publisher/sites')) . '
  2. '; echo '
  3. ' . esc_html__('Open the site and choose Connect WordPress. Copy the connection key (it starts with dwp_).', 'diretsa') . '
  4. '; echo '
  5. ' . esc_html__('Paste it here and choose Connect.', 'diretsa') . '
'; echo '
'; wp_nonce_field('diretsa_action'); echo ''; echo '

'; echo ' '; echo '

'; return; } printf('

%s %s (%s) · %s %s

', esc_html__('Connected to', 'diretsa'), esc_html($site['name']), esc_html($site['domain']), esc_html__('key', 'diretsa'), esc_html(substr($key, 0, 10) . '…')); $host = wp_parse_url(home_url('/'), PHP_URL_HOST); if ($host && strtolower(preg_replace('/^www\./', '', $host)) !== strtolower(preg_replace('/^www\./', '', $site['domain']))) { printf('

%s

', esc_html(sprintf(/* translators: 1: this site's host name, 2: the domain the key was made for. */ __('This WordPress site is %1$s but the key is for %2$s. Ads and verification only work on the site the key was made for.', 'diretsa'), $host, $site['domain']))); } echo '

' . esc_html__('Verification', 'diretsa') . '

'; if (!empty($site['verified'])) { echo '

✓ ' . esc_html__('Verified: Diretsa has confirmed you own this site.', 'diretsa') . '

'; } else { echo '

' . esc_html__('The plugin has added Diretsa\'s verification tag to your home page. Choose Check verification to let Diretsa confirm it.', 'diretsa') . '

'; diretsa_button('verify', __('Check verification', 'diretsa'), 'button button-primary'); echo '

'; } echo '

' . esc_html__('Your placements', 'diretsa') . '

'; $placements = isset($data['placements']) ? $data['placements'] : array(); if (!$placements) { echo '

' . esc_html__('No placements yet. Add them for this site in Media Control (sizes and prices), then choose Refresh.', 'diretsa') . '

'; } else { echo '

' . esc_html__('Add a placement with the "Diretsa ad" block, the "Diretsa ad" widget, or its shortcode.', 'diretsa') . '

'; echo ''; foreach ($placements as $p) { $sale = !empty($p['on_sale']) ? __('Yes', 'diretsa') : (isset($p['not_on_sale_reason']) ? $p['not_on_sale_reason'] : __('No', 'diretsa')); printf('', esc_html($p['name']), esc_html($p['size']), esc_html($sale), esc_html($p['product_id'])); } echo '
' . esc_html__('Placement', 'diretsa') . '' . esc_html__('Size', 'diretsa') . '' . esc_html__('On sale', 'diretsa') . '' . esc_html__('Shortcode', 'diretsa') . '
%s%s%s[diretsa_ad id="%s"]
'; } echo '

'; diretsa_button('refresh', __('Refresh', 'diretsa')); printf('%s', esc_url($data['console_url'] . '/publisher/sites'), esc_html__('Open Media Control', 'diretsa')); echo '

'; if (!empty($site['verified'])) { echo '

' . esc_html__('Earnings', 'diretsa') . '

'; diretsa_earnings_box(); } echo '

' . esc_html__('Disconnect', 'diretsa') . '

' . esc_html__('Stops showing Diretsa ads and removes the key from this site.', 'diretsa') . '

'; diretsa_button('disconnect', __('Disconnect', 'diretsa'), 'button button-link-delete'); echo ''; }