is_ads_txt_request() ) { return; } /** * Prevents the plugin from handling ads.txt (e.g. custom implementation). * * @param bool $skip Default false. */ if ( apply_filters( 'adfusion_ads_txt_skip', false ) ) { $this->send_not_found(); return; } if ( '1' !== get_option( 'adf_ads_txt_enabled', '1' ) ) { $this->send_not_found(); return; } $body = $this->build_body(); /** * Full ads.txt body (use only trusted sources; output is not HTML-escaped). * * @param string $body Plain text lines, may be empty to send 404. */ $body = apply_filters( 'adfusion_ads_txt_content', $body ); $body = is_string( $body ) ? trim( $body, "\n\r" ) : ''; if ( '' === $body ) { $this->send_not_found(); return; } if ( ! headers_sent() ) { nocache_headers(); header( 'Content-Type: text/plain; charset=utf-8' ); } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- text/plain, lines are validated. echo $body . "\n"; exit; } /** * Whether the current request path matches the site’s /ads.txt URL. * * @return bool */ private function is_ads_txt_request() { if ( ! isset( $_SERVER['REQUEST_URI'] ) || ! is_string( $_SERVER['REQUEST_URI'] ) ) { return false; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- only the path is compared to home /ads.txt; not stored. $raw = (string) wp_unslash( $_SERVER['REQUEST_URI'] ); $path = (string) wp_parse_url( $raw, PHP_URL_PATH ); if ( '' === $path ) { return false; } $path = untrailingslashit( $path ); $expected = (string) wp_parse_url( home_url( '/ads.txt' ), PHP_URL_PATH ); if ( '' === $expected ) { $expected = '/ads.txt'; } $expected = untrailingslashit( $expected ); return ( $path === $expected ); } /** * Build the default body from the saved AdSense publisher ID. * * @return string */ private function build_body() { $raw = get_option( 'adf_google_adsense_id' ); $pub = self::sanitize_publisher_id( is_scalar( $raw ) ? (string) $raw : '' ); if ( '' === $pub ) { return ''; } // IAB: domain, account id, relationship, certification authority id. return 'google.com, ' . $pub . ', DIRECT, ' . self::GOOGLE_TAG_ID; } /** * Normalize and validate an AdSense publisher id for ads.txt. * * @param string $id Value from settings. * @return string pub- + digits, or empty if invalid. */ public static function sanitize_publisher_id( $id ) { $s = is_string( $id ) ? trim( $id ) : ''; if ( '' === $s ) { return ''; } $s = preg_replace( '/\s+/', '', $s ); if ( ! is_string( $s ) || '' === $s ) { return ''; } // Google publisher IDs: pub- followed by 16 decimal digits. if ( 1 === preg_match( '/^pub-\d{16}$/i', $s ) ) { return strtolower( $s ); } return ''; } /** * 404 and stop (ads.txt missing or not configured). * * @return void */ private function send_not_found() { if ( ! headers_sent() ) { status_header( 404 ); nocache_headers(); header( 'Content-Type: text/plain; charset=utf-8' ); } exit; } } if ( ! is_admin() ) { new AdFusion_Ads_Txt(); }