Index: src/wp-includes/ms-blogs.php
===================================================================
--- src/wp-includes/ms-blogs.php	(revision 40317)
+++ src/wp-includes/ms-blogs.php	(working copy)
@@ -531,6 +531,82 @@
 }
 
 /**
+ * Retrieves a site by given site data.
+ *
+ * @since 4.8.0
+ *
+ * @param int|string|array $field Name of a single field or an array of multiple fields to query against.
+ *                                The supported fields are 'id', 'slug', 'domain', 'path' and 'network_id'.
+ * @param mixed            $value Optional. If $field is the name of a field, this parameter must be
+ *                                provided for that field's value to query for. Otherwise it can be omitted.
+ *                                Default null.
+ * @return WP_Site|null The site object or null if not found.
+ */
+function get_site_by( $field, $value = null ) {
+	if ( 'id' === $field ) {
+		return get_site( $value );
+	}
+
+	$args = $field;
+	if ( ! is_array( $args ) ) {
+		$args = array( $field => $value );
+	}
+
+	if ( isset( $args['id'] ) ) {
+		if ( ! empty( $args['site__in'] ) ) {
+			$args['site__in'][] = $args['id'];
+		} else {
+			$args['site__in'] = array( $args['id'] );
+		}
+
+		unset( $args['id'] );
+	}
+
+	if ( isset( $args['slug'] ) ) {
+		$network = isset( $args['network_id'] ) ? get_network( $args['network_id'] ) : get_network();
+
+		if ( is_subdomain_install() ) {
+			$args['domain'] = trim( $args['slug'], '/' ) . '.' . preg_replace( '|^www\.|', '', $network->domain );
+			$args['path'] = $network->path;
+		} else {
+			$args['domain'] = $network->domain;
+			$args['path'] = $network->path . trim( $args['slug'], '/' ) . '/';
+		}
+
+		unset( $args['slug'] );
+	}
+
+	if ( ! isset( $args['site__in'] ) && ! isset( $args['domain'] ) ) {
+		return null;
+	}
+
+	if ( isset( $args['domain'] ) ) {
+		if ( ! isset( $args['path'] ) && ! is_subdomain_install() && empty( $args['site__in'] ) ) {
+			return null;
+		}
+
+		if ( substr( $args['domain'], 0, 4 ) == 'www.' ) {
+			$nowww = substr( $args['domain'], 4 );
+
+			$args['domain__in'] = array( $nowww, $args['domain'] );
+			unset( $args['domain'] );
+		}
+	}
+
+	$args['number'] = 1;
+	$args['fields'] = '';
+	$args['count']  = false;
+
+	$sites = get_sites( $args );
+
+	if ( empty( $sites ) ) {
+		return null;
+	}
+
+	return array_shift( $sites );
+}
+
+/**
  * Adds any sites from the given ids to the cache that do not already exist in cache.
  *
  * @since 4.6.0
Index: tests/phpunit/tests/multisite/getSiteBy.php
===================================================================
--- tests/phpunit/tests/multisite/getSiteBy.php	(revision 0)
+++ tests/phpunit/tests/multisite/getSiteBy.php	(working copy)
@@ -0,0 +1,211 @@
+<?php
+
+if ( is_multisite() ) :
+/**
+ * Test get_site_by() in multisite.
+ *
+ * @ticket 40180
+ * @group ms-site
+ * @group multisite
+ */
+class Tests_Multisite_Get_Site_By extends WP_UnitTestCase {
+	protected static $network_ids;
+	protected static $site_ids;
+
+	public static function wpSetUpBeforeClass( $factory ) {
+		self::$network_ids = array(
+			'wordpress.org/'         => array( 'domain' => 'wordpress.org',     'path' => '/' ),
+			'www.wordpress.net/'     => array( 'domain' => 'www.wordpress.net', 'path' => '/' ),
+		);
+
+		foreach ( self::$network_ids as &$id ) {
+			$id = $factory->network->create( $id );
+		}
+		unset( $id );
+
+		self::$site_ids = array(
+			'wordpress.org/'              => array( 'domain' => 'wordpress.org',     'path' => '/',     'site_id' => self::$network_ids['wordpress.org/'] ),
+			'foo.wordpress.org/'          => array( 'domain' => 'foo.wordpress.org', 'path' => '/',     'site_id' => self::$network_ids['wordpress.org/'] ),
+			'wordpress.org/foo/'          => array( 'domain' => 'wordpress.org',     'path' => '/foo/', 'site_id' => self::$network_ids['wordpress.org/'] ),
+			'www.wordpress.net/'          => array( 'domain' => 'www.wordpress.net', 'path' => '/',     'site_id' => self::$network_ids['www.wordpress.net/'] ),
+			'foo.wordpress.net/'          => array( 'domain' => 'foo.wordpress.net', 'path' => '/',     'site_id' => self::$network_ids['www.wordpress.net/'] ),
+			'www.wordpress.net/foo/'      => array( 'domain' => 'www.wordpress.net', 'path' => '/foo/', 'site_id' => self::$network_ids['www.wordpress.net/'] ),
+		);
+
+		foreach ( self::$site_ids as &$id ) {
+			$id = $factory->blog->create( $id );
+		}
+		unset( $id );
+	}
+
+	public static function wpTearDownAfterClass() {
+		global $wpdb;
+
+		foreach( self::$site_ids as $id ) {
+			wpmu_delete_blog( $id, true );
+		}
+
+		foreach( self::$network_ids as $id ) {
+			$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->sitemeta} WHERE site_id = %d", $id ) );
+			$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->site} WHERE id= %d", $id ) );
+		}
+
+		wp_update_network_site_counts();
+	}
+
+	public function test_get_site_by_id() {
+		$result = get_site_by( 'id', self::$site_ids['wordpress.org/'] );
+		$this->assertEquals( self::$site_ids['wordpress.org/'], $result->id );
+	}
+
+	public function test_get_site_by_id_in_array() {
+		$result = get_site_by( array( 'id' => self::$site_ids['wordpress.org/'] ) );
+		$this->assertEquals( self::$site_ids['wordpress.org/'], $result->id );
+	}
+
+	public function test_get_site_by_current_id() {
+		$result = get_site_by( 'id', null );
+		$this->assertEquals( get_current_blog_id(), $result->id );
+	}
+
+	public function test_get_site_by_name_subdomain() {
+		global $current_site;
+
+		if ( ! is_subdomain_install() ) {
+			$this->markTestSkipped( 'This test is only valid in a subdomain configuration.' );
+		}
+
+		$original_network = $current_site;
+		$current_site = get_network( self::$network_ids['wordpress.org/'] );
+
+		$result = get_site_by( 'slug', 'foo' );
+		$current_site = $original_network;
+
+		$this->assertEquals( self::$site_ids['foo.wordpress.org/'], $result->id );
+	}
+
+	public function test_get_site_by_name_with_www_subdomain() {
+		global $current_site;
+
+		if ( ! is_subdomain_install() ) {
+			$this->markTestSkipped( 'This test is only valid in a subdomain configuration.' );
+		}
+
+		$original_network = $current_site;
+		$current_site = get_network( self::$network_ids['www.wordpress.net/'] );
+
+		$result = get_site_by( 'slug', 'foo' );
+		$current_site = $original_network;
+
+		$this->assertEquals( self::$site_ids['foo.wordpress.net/'], $result->id );
+	}
+
+	public function test_get_site_by_name_and_network_subdomain() {
+		if ( ! is_subdomain_install() ) {
+			$this->markTestSkipped( 'This test is only valid in a subdomain configuration.' );
+		}
+
+		$result = get_site_by( array(
+			'slug'       => 'foo',
+			'network_id' => self::$network_ids['wordpress.org/'],
+		) );
+
+		$this->assertEquals( self::$site_ids['foo.wordpress.org/'], $result->id );
+	}
+
+	public function test_get_site_by_name_and_network_with_www_subdomain() {
+		if ( ! is_subdomain_install() ) {
+			$this->markTestSkipped( 'This test is only valid in a subdomain configuration.' );
+		}
+
+		$result = get_site_by( array(
+			'slug'       => 'foo',
+			'network_id' => self::$network_ids['www.wordpress.net/'],
+		) );
+
+		$this->assertEquals( self::$site_ids['foo.wordpress.net/'], $result->id );
+	}
+
+	public function test_get_site_by_name_subdirectory() {
+		global $current_site;
+
+		if ( is_subdomain_install() ) {
+			$this->markTestSkipped( 'This test is only valid in a subdirectory configuration.' );
+		}
+
+		$original_network = $current_site;
+		$current_site = get_network( self::$network_ids['wordpress.org/'] );
+
+		$result = get_site_by( 'slug', 'foo' );
+		$current_site = $original_network;
+
+		$this->assertEquals( self::$site_ids['wordpress.org/foo/'], $result->id );
+	}
+
+	public function test_get_site_by_name_with_www_subdirectory() {
+		global $current_site;
+
+		if ( is_subdomain_install() ) {
+			$this->markTestSkipped( 'This test is only valid in a subdirectory configuration.' );
+		}
+
+		$original_network = $current_site;
+		$current_site = get_network( self::$network_ids['www.wordpress.net/'] );
+
+		$result = get_site_by( 'slug', 'foo' );
+		$current_site = $original_network;
+
+		$this->assertEquals( self::$site_ids['www.wordpress.net/foo/'], $result->id );
+	}
+
+	public function test_get_site_by_name_and_network_subdirectory() {
+		if ( is_subdomain_install() ) {
+			$this->markTestSkipped( 'This test is only valid in a subdirectory configuration.' );
+		}
+
+		$result = get_site_by( array(
+			'slug'       => 'foo',
+			'network_id' => self::$network_ids['wordpress.org/'],
+		) );
+
+		$this->assertEquals( self::$site_ids['wordpress.org/foo/'], $result->id );
+	}
+
+	public function test_get_site_by_name_and_network_with_www_subdirectory() {
+		if ( is_subdomain_install() ) {
+			$this->markTestSkipped( 'This test is only valid in a subdirectory configuration.' );
+		}
+
+		$result = get_site_by( array(
+			'slug'       => 'foo',
+			'network_id' => self::$network_ids['www.wordpress.net/'],
+		) );
+
+		$this->assertEquals( self::$site_ids['www.wordpress.net/foo/'], $result->id );
+	}
+
+	public function test_get_site_by_domain_subdomain() {
+		if ( ! is_subdomain_install() ) {
+			$this->markTestSkipped( 'This test is only valid in a subdomain configuration.' );
+		}
+
+		$result = get_site_by( 'domain', 'wordpress.org' );
+		$this->assertEquals( self::$site_ids['wordpress.org/'], $result->id );
+	}
+
+	public function test_get_site_by_domain_subdirectory() {
+		if ( is_subdomain_install() ) {
+			$this->markTestSkipped( 'This test is only valid in a subdirectory configuration.' );
+		}
+
+		$result = get_site_by( 'domain', 'wordpress.org' );
+		$this->assertNull( $result );
+	}
+
+	public function test_get_site_by_path() {
+		$result = get_site_by( 'path', '/foo/' );
+		$this->assertNull( $result );
+	}
+}
+
+endif;

Property changes on: tests/phpunit/tests/multisite/getSiteBy.php
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
