Index: src/wp-includes/formatting.php
===================================================================
--- src/wp-includes/formatting.php	(revision 35153)
+++ src/wp-includes/formatting.php	(working copy)
@@ -2009,10 +2009,7 @@
 }
 
 /**
- * Navigates through an array and removes slashes from the values.
- *
- * If an array is passed, the array_map() function causes a callback to pass the
- * value back to the function. The slashes from this value will removed.
+ * Navigates through an array, object, or scalar, and removes slashes from the values.
  *
  * @since 2.0.0
  *
@@ -2020,43 +2017,55 @@
  * @return mixed Stripped value.
  */
 function stripslashes_deep( $value ) {
-	if ( is_array($value) ) {
-		$value = array_map('stripslashes_deep', $value);
-	} elseif ( is_object($value) ) {
-		$vars = get_object_vars( $value );
-		foreach ($vars as $key=>$data) {
-			$value->{$key} = stripslashes_deep( $data );
-		}
-	} elseif ( is_string( $value ) ) {
-		$value = stripslashes($value);
-	}
-
-	return $value;
+	return map_deep( $value, 'stripslashes_from_strings_only' );
 }
 
 /**
- * Navigates through an array and encodes the values to be used in a URL.
+ * Callback function for `stripslashes_deep()` which strips slashes from strings.
+ *
+ * @since 4.4.0
  *
+ * @param mixed $value The array or string to be stripped.
+ * @return mixed $value The stripped value.
+ */
+function stripslashes_from_strings_only( $value ) {
+	return is_string( $value ) ? stripslashes( $value ) : $value;
+}
+
+/**
+ * Navigates through an array, object, or scalar, and encodes the values to be used in a URL.
  *
  * @since 2.2.0
  *
- * @param array|string $value The array or string to be encoded.
- * @return array|string $value The encoded array (or string from the callback).
+ * @param mixed $value The array or string to be encoded.
+ * @return mixed $value The encoded value.
  */
 function urlencode_deep( $value ) {
-	return is_array( $value ) ? array_map( 'urlencode_deep', $value ) : urlencode( $value );
+	return map_deep( $value, 'urlencode' );
 }
 
 /**
- * Navigates through an array and raw encodes the values to be used in a URL.
+ * Navigates through an array, object, or scalar, and raw-encodes the values to be used in a URL.
  *
  * @since 3.4.0
  *
- * @param array|string $value The array or string to be encoded.
- * @return array|string $value The encoded array (or string from the callback).
+ * @param mixed $value The array or string to be encoded.
+ * @return mixed $value The encoded value.
  */
 function rawurlencode_deep( $value ) {
-	return is_array( $value ) ? array_map( 'rawurlencode_deep', $value ) : rawurlencode( $value );
+	return map_deep( $value, 'rawurlencode' );
+}
+
+/**
+ * Navigates through an array, object, or scalar, and decodes URL-encoded values
+ *
+ * @since 4.4.0
+ *
+ * @param mixed $value The array or string to be decoded.
+ * @return mixed $value The decoded value.
+ */
+function urldecode_deep( $value ) {
+	return map_deep( $value, 'urldecode' );
 }
 
 /**
@@ -3863,6 +3872,28 @@
 }
 
 /**
+ * Maps a function to all non-iterable elements of an array or an object.
+ *
+ * This is similar to `array_walk_recursive()` but acts upon objects too.
+ *
+ * @since 4.4.0 
+ * 
+ * @param mixed    $value    The array, object, or scalar.
+ * @param callable $function The function to map onto $value.
+ * @return The value with the callback applied to all non-arrays and non-objects inside it.
+ */
+function map_deep( $value, $callback ) {
+	if ( is_array( $value ) || is_object( $value ) ) {
+		foreach ( $value as &$item ) {
+			$item = map_deep( $item, $callback );
+		}
+		return $value;
+	} else {
+		return call_user_func( $callback, $value );
+	}
+}
+
+/**
  * Parses a string into variables to be stored in an array.
  *
  * Uses {@link http://www.php.net/parse_str parse_str()} and stripslashes if
Index: tests/phpunit/tests/formatting/MapDeep.php
===================================================================
--- tests/phpunit/tests/formatting/MapDeep.php	(revision 0)
+++ tests/phpunit/tests/formatting/MapDeep.php	(working copy)
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * @group formatting
+ * @ticket 22300
+ */
+class Tests_Formatting_MapDeep extends WP_UnitTestCase {
+
+	public function test_map_deep_with_any_function_over_empty_array_should_return_empty_array() {
+		$this->assertEquals( array(), map_deep( array(), array( $this, 'append_baba' ) ) );
+	}
+
+	public function test_map_deep_should_map_each_element_of_array_one_level_deep() {
+		$this->assertEquals( array(
+			'ababa',
+			'xbaba',
+		), map_deep( array(
+			'a',
+			'x',
+		), array( $this, 'append_baba' ) ) );
+	}
+
+	public function test_map_deep_should_map_each_element_of_array_two_levels_deep() {
+		$this->assertEquals( array(
+			'ababa',
+			array(
+				'xbaba',
+			),
+		), map_deep( array(
+			'a',
+			array(
+				'x',
+			),
+		), array( $this, 'append_baba' ) ) );
+	}
+
+	public function test_map_deep_should_map_each_object_element_of_an_array() {
+		$this->assertEquals( array(
+			'var0' => 'ababa',
+			'var1' => (object) array(
+				'xbaba',
+			),
+		), map_deep( array(
+			'var0' => 'a',
+			'var1' => (object) array(
+				'x',
+			),
+		), array( $this, 'append_baba' ) ) );
+	}
+
+	public function test_map_deep_should_apply_the_function_to_a_string() {
+		$this->assertEquals( 'xbaba', map_deep( 'x', array( $this, 'append_baba' ) ) );
+	}
+
+	public function test_map_deep_should_apply_the_function_to_an_integer() {
+		$this->assertEquals( '5baba' , map_deep( 5, array( $this, 'append_baba' ) ) );
+	}
+
+	public function test_map_deep_should_map_each_property_of_an_object() {
+		$this->assertEquals( (object) array(
+			'var0' => 'ababa',
+			'var1' => 'xbaba',
+		), map_deep( (object) array(
+			'var0' => 'a',
+			'var1' => 'x',
+		), array( $this, 'append_baba' ) ) );
+	}
+
+	public function test_map_deep_should_map_each_array_property_of_an_object() {
+		$this->assertEquals( (object) array(
+			'var0' => 'ababa',
+			'var1' => array(
+				'xbaba',
+			),
+		), map_deep( (object) array(
+			'var0' => 'a',
+			'var1' => array(
+				'x',
+			),
+		), array( $this, 'append_baba' ) ) );
+	}
+
+	public function test_map_deep_should_map_each_object_property_of_an_object() {
+		$this->assertEquals( (object) array(
+			'var0' => 'ababa',
+			'var1' => (object) array(
+				'xbaba',
+			),
+		), map_deep( (object) array(
+			'var0' => 'a',
+			'var1' => (object) array(
+				'x',
+			),
+		), array( $this, 'append_baba' ) ) );
+	}
+
+	public function append_baba( $value ) {
+		return $value . 'baba';
+	}
+
+}
Index: tests/phpunit/tests/formatting/UrlencodeDeep.php
===================================================================
--- tests/phpunit/tests/formatting/UrlencodeDeep.php	(revision 0)
+++ tests/phpunit/tests/formatting/UrlencodeDeep.php	(working copy)
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @group formatting
+ * @ticket 22300
+ */
+class Tests_Formatting_UrlencodeDeep extends WP_UnitTestCase {
+
+	/**
+	 * Data Provider
+	 */
+	public function data_test_values() {
+		return array(
+			array( 'qwerty123456', 'qwerty123456' ),
+			array( '|!"£$%&/()=?', '%7C%21%22%C2%A3%24%25%26%2F%28%29%3D%3F' ),
+			array( '^é*ç°§;:_-.,', '%5E%C3%A9%2A%C3%A7%C2%B0%C2%A7%3B%3A_-.%2C' ),
+			array( 'abc123 @#[]€', 'abc123+%40%23%5B%5D%E2%82%AC' ),
+			array( 'abc123 @#[]€', urlencode( 'abc123 @#[]€' ) ),
+		);
+	}
+
+	/**
+	 * Validate the urlencode_deep function pair by pair
+	 *
+	 * @dataProvider data_test_values
+	 *
+	 * @param string $actual
+	 * @param string $expected
+	 */
+	public function test_urlencode_deep_should_encode_individual_value( $actual, $expected ) {
+		$this->assertEquals( $expected, urlencode_deep( $actual ) );
+	}
+
+	/**
+	 * Test the whole array as input
+	 */
+	public function test_urlencode_deep_should_encode_all_values_in_array() {
+		$data = $this->data_test_values();
+
+		$actual   = wp_list_pluck( $data, 0 );
+		$expected = wp_list_pluck( $data, 1 );
+
+		$this->assertEquals( $expected, urlencode_deep( $actual ) );
+	}
+
+}
