509318396
­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
<?php
/**
 * Which request-level signals a server event may carry.
 *
 * A server event built for a WooCommerce order does not always run in the
 * customer's request. A status change in wp-admin runs in the administrator's;
 * a gateway webhook runs in the gateway's; cron runs in nobody's. Reading
 * client_ip_address, client_user_agent and the _fbp/_fbc cookies from the
 * current request there describes the wrong person — and when an administrator
 * once clicked the store's own ad, it hands Meta that click as the purchase's,
 * so a manual order is attributed to a campaign.
 *
 * WooCommerce stores the IP and user agent of the checkout request on the
 * order, so an order-bound event takes them from there. The cookies have their
 * own order-side copy (the pys_fb_cookie meta); what this file decides is
 * whether the *request's* cookies may stand in when the order has none.
 */

namespace PixelYourSite;

defined( 'ABSPATH' ) or die( 'Direct access not allowed' );

/**
 * True when the current request is a wp-admin page: the person behind it is
 * a site administrator, not the visitor an event describes.
 *
 * admin-ajax.php also answers true to is_admin(), but the front end calls it
 * for a visitor, so it is excluded. REST, cron and webhooks answer false; they
 * carry no cookies, and for order events the order's own IP takes precedence.
 *
 * @return bool
 */
function pys_is_admin_page_request() {
	return is_admin() && ! wp_doing_ajax();
}

/**
 * The IP and user agent for a server event, and whether the request's own
 * cookies may be read for it.
 *
 * The order wins when it has a value: it was captured when the order was
 * placed and describes that customer. The request stands in only when it is
 * the visitor's own. In wp-admin it is the administrator's, so nothing stands
 * in, and an order the administrator created has no checkout request behind
 * it at all — HPOS stores nothing, the legacy wc_create_order() path stores
 * the administrator's address — so its stored values are not used either.
 *
 * @param object|null $order         The WooCommerce order the event belongs to: a WC_Order,
 *                                   or anything with get_customer_ip_address(),
 *                                   get_customer_user_agent() and get_created_via().
 *                                   Null for an event without one.
 * @param string      $request_ip    Routable IP of the current request, '' when none.
 * @param string|null $request_ua    User agent of the current request, null when none.
 * @param bool        $admin_request The current request is a wp-admin page.
 * @return array{ip: string, user_agent: ?string, request_cookies: bool}
 *               'ip' is '' and 'user_agent' is null when the event should carry none.
 */
function pys_event_client_signals( $order, $request_ip, $request_ua, $admin_request ) {
	$ip = '';
	$ua = null;

	if ( $order && 'admin' !== (string) $order->get_created_via() ) {
		// Same bar as a header value: a private or malformed address occupies
		// the field Meta weighs most with something that cannot match.
		$ip = pys_normalize_ip( (string) $order->get_customer_ip_address() );
		if ( '' !== $ip && ! pys_is_public_ip( $ip ) ) {
			$ip = '';
		}

		$ua = (string) $order->get_customer_user_agent();
		$ua = '' !== $ua ? $ua : null;
	}

	if ( ! $admin_request ) {
		if ( '' === $ip ) {
			$ip = (string) $request_ip;
		}
		if ( null === $ua ) {
			$ua = $request_ua;
		}
	}

	return array(
		'ip'              => $ip,
		'user_agent'      => $ua,
		'request_cookies' => ! $admin_request,
	);
}
