WP_View_Config_Data::merge_propertiesprivateWP 7.1.0

Merges an incoming value into the current one, recursing by value shape.

This is the core of the merge algorithm and is applied at every nesting level: a scalar (or null) in $incoming replaces $current outright, an associative array merges key by key (recursing here for each key, with a null value deleting that key), and a list either replaces $current wholesale ($replace_lists) or merges into it by member identity. The $replace_lists flag is carried down through associative nesting so that, under replace(), every list reached along the way is swapped wholesale.

An array in $incoming only merges into a current value of the same shape. A non-empty mismatch — an associative array where a list lives, or a non-empty list where an associative value lives — is reported with _doing_it_wrong() and leaves the current value unchanged, so a malformed patch cannot silently destroy configuration. An empty array is shape-ambiguous and merges nothing, so it is a no-op: clearing a list is spelled replace() with an empty list, and resetting a key is spelled null.

Method of the class: WP_View_Config_Data{}

No Hooks.

Returns

mixed. The merged value.

Usage

// private - for code of main (parent) class only
$result = $this->merge_properties( $current, $incoming, $replace_lists );
$current(mixed) (required)
The current value.
$incoming(mixed) (required)
The incoming value.
$replace_lists(true|false) (required)
Whether a list in $incoming replaces the current list wholesale instead of merging into it by member identity.

Changelog

Since 7.1.0 Introduced.

WP_View_Config_Data::merge_properties() code WP 7.1

private function merge_properties( $current, $incoming, $replace_lists ) {
	// Scalar properties are merged as-is.
	if ( ! is_array( $incoming ) ) {
		return $incoming;
	}

	// Numerical indexed arrays are expected to be lists (sequential integer keys starting at 0).
	if ( array_is_list( $incoming ) ) {
		// A non-empty list only lands where a list (or nothing) lives, under
		// merge() and replace() alike. An empty array is shape-ambiguous and
		// exempt, so replace() with an empty list can still clear a list.
		if ( array() !== $incoming && is_array( $current ) && ! array_is_list( $current ) && array() !== $current ) {
			_doing_it_wrong(
				__METHOD__,
				esc_html__( 'A view configuration patch value must match the shape of the value it patches: a list merges into a list, and an associative array into an associative array.' ),
				'7.1.0'
			);
			return $current;
		}

		// replace() takes an incoming list as-is; merge() merges it by member identity.
		if ( $replace_lists ) {
			// As-is except for nulls: a list swapped in wholesale has no
			// existing leaf for a null to delete (the same rationale as
			// set()), so a null member is dropped rather than stored.
			return $this->strip_nulls( $incoming );
		}

		// An empty list has no members to merge, and an empty array is
		// shape-ambiguous, so merging one is a no-op rather than a reset.
		if ( array() === $incoming ) {
			return $current;
		}

		return $this->merge_list_by_identity(
			is_array( $current ) && array_is_list( $current ) ? $current : array(),
			$incoming
		);
	}

	// Consider any other array as associative (keys are strings).
	if ( is_array( $current ) && array_is_list( $current ) && array() !== $current ) {
		_doing_it_wrong(
			__METHOD__,
			esc_html__( 'A view configuration patch value must match the shape of the value it patches: a list merges into a list, and an associative array into an associative array.' ),
			'7.1.0'
		);
		return $current;
	}

	$result = is_array( $current ) && ! array_is_list( $current ) ? $current : array();
	foreach ( $incoming as $key => $value ) {
		// A null patch value deletes the property.
		if ( null === $value ) {
			unset( $result[ $key ] );
			continue;
		}

		$result[ $key ] = $this->merge_properties(
			array_key_exists( $key, $result ) ? $result[ $key ] : array(),
			$value,
			$replace_lists
		);
	}

	return $result;
}