Commit 7ca109ad18 for wordpress.org

commit 7ca109ad18aab3a0d49f033b1ea544022b838861
Author: westonruter <westonruter@git.wordpress.org>
Date:   Wed Oct 14 23:45:51 2026 +0000

    Code Quality: Correct nullable `WP_Http_Cookie` property types.

    A cookie created without a name, value, domain, expiration or host-only flag, or from incomplete data, leaves those properties `null`, and an unparsable expiration date is stored as `false`, but their documented types said otherwise. PHPStan therefore treated `isset()` checks on them as always true, so correcting the types retires the `booleanOr.alwaysFalse` baseline entirely along with several `isset.property` entries.

    The corrected types surfaced real errors in callers, which are fixed rather than baselined:
    * In `WP_Http::normalize_cookies()`, a `WP_Http_Cookie` value was passed to `WpOrg\Requests\Cookie` as is, which throws an `InvalidArgument` exception for anything but a string, failing the request. A cookie without a value or with a non-scalar value is now skipped, as `WP_Http_Cookie::getHeaderValue()` already does, and other scalar values are cast to strings.
    * `wp_remote_retrieve_cookie_value()` now returns an empty string instead of `null` for a cookie without a value.

    The handling of empty or missing cookie names is unchanged, as it is being addressed separately in #66305.

    Developed in https://github.com/WordPress/wordpress-develop/pull/14283.
    Follow-up to r38164, r45135, r57501, r63023.

    Props huzaifaalmesbah, westonruter.
    See #65817, #66305.

    Built from https://develop.svn.wordpress.org/trunk@64350


    git-svn-id: http://core.svn.wordpress.org/trunk@63500 1a063a9b-81f0-0310-95a4-ce76da25c4cd

diff --git a/wp-includes/class-wp-http-cookie.php b/wp-includes/class-wp-http-cookie.php
index 4546f58a1a..dbc63721c8 100644
--- a/wp-includes/class-wp-http-cookie.php
+++ b/wp-includes/class-wp-http-cookie.php
@@ -26,7 +26,7 @@ class WP_Http_Cookie {
 	 *
 	 * @since 2.8.0
 	 *
-	 * @var string
+	 * @var string|null
 	 */
 	public $name;

@@ -35,16 +35,18 @@ class WP_Http_Cookie {
 	 *
 	 * @since 2.8.0
 	 *
-	 * @var string
+	 * @var string|null
 	 */
 	public $value;

 	/**
-	 * When the cookie expires. Unix timestamp or formatted date.
+	 * When the cookie expires, as a Unix timestamp.
+	 *
+	 * False if the expiration date could not be parsed, or null if not provided.
 	 *
 	 * @since 2.8.0
 	 *
-	 * @var string|int|null
+	 * @var int|false|null
 	 */
 	public $expires;

@@ -62,7 +64,7 @@ class WP_Http_Cookie {
 	 *
 	 * @since 2.8.0
 	 *
-	 * @var string
+	 * @var string|null
 	 */
 	public $domain;

@@ -76,11 +78,13 @@ class WP_Http_Cookie {
 	public $port;

 	/**
-	 * host-only flag.
+	 * Host-only flag.
+	 *
+	 * Null if not provided.
 	 *
 	 * @since 5.2.0
 	 *
-	 * @var bool
+	 * @var bool|null
 	 */
 	public $host_only;

@@ -100,9 +104,9 @@ class WP_Http_Cookie {
 	 *     @type mixed           $value     Value. Should NOT already be urlencoded.
 	 *     @type string|int|null $expires   Optional. Unix timestamp or formatted date. Default null.
 	 *     @type string|null     $path      Optional. Path. Default '/'.
-	 *     @type string          $domain    Optional. Domain. Default host of parsed $requested_url.
+	 *     @type string|null     $domain    Optional. Domain. Default host of parsed $requested_url.
 	 *     @type int|string|null $port      Optional. Port or comma-separated list of ports. Default null.
-	 *     @type bool            $host_only Optional. host-only storage flag. Default true.
+	 *     @type bool|null       $host_only Optional. Host-only storage flag. Default null.
 	 * }
 	 * @param string       $requested_url The URL which the cookie was set on, used for default $domain
 	 *                                    and $port values.
@@ -262,9 +266,9 @@ class WP_Http_Cookie {
 	 * @return array {
 	 *     List of attributes.
 	 *
-	 *     @type string|int|null $expires When the cookie expires. Unix timestamp or formatted date.
-	 *     @type string          $path    Cookie URL path.
-	 *     @type string          $domain  Cookie domain.
+	 *     @type int|false|null $expires When the cookie expires, as a Unix timestamp.
+	 *     @type string         $path    Cookie URL path.
+	 *     @type string|null    $domain  Cookie domain.
 	 * }
 	 */
 	public function get_attributes() {
diff --git a/wp-includes/class-wp-http.php b/wp-includes/class-wp-http.php
index eab634e644..66cf907d0e 100644
--- a/wp-includes/class-wp-http.php
+++ b/wp-includes/class-wp-http.php
@@ -474,7 +474,9 @@ class WP_Http {
 	 *
 	 * @since 4.6.0
 	 *
-	 * @param array $cookies Array of cookies to send with the request.
+	 * @param array<int|string, WP_Http_Cookie|scalar> $cookies Array of cookies to send with the request,
+	 *                                                          as WP_Http_Cookie objects or name/value pairs.
+	 *                                                          Cookies without a scalar value are ignored.
 	 * @return WpOrg\Requests\Cookie\Jar Cookie holder object.
 	 */
 	public static function normalize_cookies( $cookies ) {
@@ -482,16 +484,28 @@ class WP_Http {

 		foreach ( $cookies as $name => $value ) {
 			if ( $value instanceof WP_Http_Cookie ) {
-				$attributes                 = array_filter(
+				$cookie_name  = (string) $value->name;
+				$cookie_value = $value->value;
+				$attributes   = array_filter(
 					$value->get_attributes(),
 					static function ( $attr ) {
 						return null !== $attr;
 					}
 				);
-				$cookie_jar[ $value->name ] = new WpOrg\Requests\Cookie( (string) $value->name, $value->value, $attributes, array( 'host-only' => $value->host_only ) );
-			} elseif ( is_scalar( $value ) ) {
-				$cookie_jar[ $name ] = new WpOrg\Requests\Cookie( (string) $name, (string) $value );
+				$flags        = array( 'host-only' => $value->host_only );
+			} else {
+				$cookie_name  = (string) $name;
+				$cookie_value = $value;
+				$attributes   = array();
+				$flags        = array();
 			}
+
+			// A cookie without a value is not sent by WP_Http_Cookie::getHeaderValue() either, and a non-scalar value cannot be represented.
+			if ( ! is_scalar( $cookie_value ) ) {
+				continue;
+			}
+
+			$cookie_jar[ $cookie_name ] = new WpOrg\Requests\Cookie( $cookie_name, (string) $cookie_value, $attributes, $flags );
 		}

 		return $cookie_jar;
diff --git a/wp-includes/http.php b/wp-includes/http.php
index 1a189a2613..34e1f452a7 100644
--- a/wp-includes/http.php
+++ b/wp-includes/http.php
@@ -381,7 +381,7 @@ function wp_remote_retrieve_cookie_value( $response, $name ) {
 		return '';
 	}

-	return $cookie->value;
+	return $cookie->value ?? '';
 }

 /**
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 1115c05bd3..e6b6a1d6e1 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '7.2-alpha-64349';
+$wp_version = '7.2-alpha-64350';

 /**
  * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.