diff --git a/composer.json b/composer.json index 95b12fce..dc279835 100644 --- a/composer.json +++ b/composer.json @@ -31,5 +31,10 @@ "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": true } + }, + "autoload": { + "psr-4": { + "DarkMatter\\": "includes/classes/" + } } } diff --git a/dark-matter.php b/dark-matter.php index b148add8..1180b54d 100644 --- a/dark-matter.php +++ b/dark-matter.php @@ -44,10 +44,22 @@ */ wp_cache_add_global_groups( 'dark-matter' ); -require_once DM_PATH . '/dark-matter/class-dm-pluginupdate.php'; +/** + * Include the PSR-4 autoloader. + */ +if ( file_exists( DM_PATH . 'vendor/autoload.php' ) ) { + require_once DM_PATH . 'vendor/autoload.php'; +} + +require_once DM_PATH . 'dark-matter/class-dm-pluginupdate.php'; new DM_PluginUpdate(); /** - * Domain Mapping module. + * Non-autoloader files. + */ +require_once DM_PATH . '/includes/utility/functions.php'; + +/** + * Let the magic - and bugs ... probably bugs! - begin. */ -require DM_PATH . '/domain-mapping/domain-mapping.php'; +\DarkMatter\DarkMatter::instance(); diff --git a/domain-mapping/classes/class-dm-ui.php b/domain-mapping/classes/class-dm-ui.php deleted file mode 100644 index 105dd26b..00000000 --- a/domain-mapping/classes/class-dm-ui.php +++ /dev/null @@ -1,124 +0,0 @@ -get_permission(), - 'domains', - array( - $this, - 'page', - ) - ); - - add_action( 'load-' . $hook_suffix, array( $this, 'enqueue' ) ); - } - - /** - * Enqueue assets for the Admin Page. - * - * @since 2.0.0 - * - * @return void - */ - public function enqueue() { - $min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' ); - - wp_register_script( - 'dark-matter-domains', - DM_PLUGIN_URL . 'domain-mapping/build/domain-mapping' . $min . '.js', - [ 'wp-i18n' ], - DM_VERSION, - true - ); - - wp_localize_script( - 'dark-matter-domains', - 'dmSettings', - array( - 'rest_root' => get_rest_url(), - 'nonce' => wp_create_nonce( 'wp_rest' ), - ) - ); - - wp_enqueue_script( 'dark-matter-domains' ); - - wp_enqueue_style( 'dark-matter-domains', DM_PLUGIN_URL . 'domain-mapping/build/domain-mapping-style' . $min . '.css', [], DM_VERSION ); - } - - /** - * Retrieve the capability that is required for using the admin page. - * - * @since 2.1.2 - * - * @return string Capability that must be met to use the Admin page. - */ - public function get_permission() { - /** - * Allows the override of the default permission for per site domain management. - * - * @since 2.1.2 - * - * @param string $capability Capability required to manage domains (upgrade_network / Super Admin). - * @param string $context The context the permission is checked. - */ - return apply_filters( 'dark_matter_domain_permission', 'upgrade_network', 'admin' ); - } - - /** - * Very basic HTML output for the - * - * @since 2.0.0 - * - * @return void - */ - public function page() { - if ( ! current_user_can( $this->get_permission() ) ) { - wp_die( esc_html__( 'You do not have permission to manage domains.', 'dark-matter' ) ); - } - ?> -
- cookie_domain_dm_set() && ( ! defined( 'DARKMATTER_SSO_TYPE' ) || 'disable' !== DARKMATTER_SSO_TYPE ) ) { - require_once DM_PATH . '/domain-mapping/sso/class-dm-sso-cookie.php'; -} - -require_once DM_PATH . '/domain-mapping/rest/class-dm-rest-domains-controller.php'; -require_once DM_PATH . '/domain-mapping/rest/class-dm-rest-restricted-controller.php'; - -if ( defined( 'WP_CLI' ) && WP_CLI ) { - require_once DM_PATH . '/domain-mapping/cli/class-darkmatter-domain-cli.php'; - require_once DM_PATH . '/domain-mapping/cli/class-darkmatter-dropin-cli.php'; - require_once DM_PATH . '/domain-mapping/cli/class-darkmatter-restrict-cli.php'; -} diff --git a/domain-mapping/inc/compat.php b/domain-mapping/inc/compat.php deleted file mode 100644 index b1d9174d..00000000 --- a/domain-mapping/inc/compat.php +++ /dev/null @@ -1,33 +0,0 @@ - over the unmapped domain. - */ - ! empty( $_GET['customize_changeset_uuid'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended - || - /** - * Do not redirect Previews - */ - ( ! empty( $_GET['preview'] ) || ! empty( $_GET['page_id'] ) || ! empty( $_GET['p'] ) ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended - ) { - return; -} - -/** - * Helper function which is used to determine if we need to perform a redirect - * to the primary domain whilst retaining the remaining URI structure. - * - * @since 2.0.0 - * - * @return void - */ -function darkmatter_maybe_redirect() { - /** - * Do not perform redirects if it is the main site. - */ - if ( is_main_site() ) { - return; - } - - $request_uri = ( empty( $_SERVER['REQUEST_URI'] ) ? '' : wp_strip_all_tags( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ); - - $request = ltrim( $request_uri, '/' ); - - /** - * Determine if the request is one we shouldn't handle for redirects. - */ - $filename = basename( $request ); - $filename = strtok( $filename, '?' ); - - $ajax_filenames = array( - 'admin-post.php' => true, - 'admin-ajax.php' => true, - ); - - /** - * Check to see if the current request is an Admin Post action or an AJAX action. These two requests in Dark Matter - * can be on either the admin domain or the primary domain. - */ - if ( ! empty( $filename ) && array_key_exists( $filename, $ajax_filenames ) ) { - return; - } - - $original_blog = get_site(); - - $http_host = ( empty( $_SERVER['HTTP_HOST'] ) ? '' : wp_strip_all_tags( wp_unslash( $_SERVER['HTTP_HOST'] ) ) ); - - $host = trim( $http_host, '/' ); - $primary = DarkMatter_Primary::instance()->get(); - - $is_admin = false; - - $admin_filenames = array( - 'wp-login.php' => true, - 'wp-register.php' => true, - ); - - if ( is_admin() || ( ! empty( $filename ) && array_key_exists( $filename, $admin_filenames ) ) ) { - $is_admin = true; - } - - /** - * Dark Matter will disengage if the website is no longer public or is archived or deleted. - */ - if ( (int) $original_blog->public < 0 || '0' !== $original_blog->archived || '0' !== $original_blog->deleted ) { - return; - } - - /** - * If Allow Logins is enabled, then the `wp-login.php` request is to be made - * available on both the primary mapped domain and admin domain. - */ - if ( ! apply_filters( 'darkmatter_allow_logins', false ) && $is_admin && $host === $original_blog->domain ) { - return; - } - - /** - * If there is no primary domain, there is nothing to do. Also make sure the - * domain is active. - */ - if ( ! $primary || ! $original_blog || ! $primary->active || absint( $original_blog->public ) < 1 ) { - return; - } - - if ( $is_admin && $host !== $original_blog->domain ) { - $is_ssl_admin = ( defined( 'FORCE_SSL_ADMIN' ) && FORCE_SSL_ADMIN ); - - $url = 'http' . ( $is_ssl_admin ? 's' : '' ) . '://' . $original_blog->domain . $original_blog->path . $request; - } elseif ( $host !== $primary->domain || is_ssl() !== $primary->is_https ) { - $url = 'http' . ( $primary->is_https ? 's' : '' ) . '://' . $primary->domain . '/' . $request; - - /** - * Make sure the Path - if this is a sub-folder Network - is removed from - * the URL. For sub-domain Networks, the path will be a single forward slash - * (/). - */ - if ( '/' !== $original_blog->path ) { - $path = '/' . trim( $original_blog->path, '/' ) . '/'; - $url = str_ireplace( $path, '/', $url ); - } - } - - /** - * If the URL is empty, then there is no redirect to perform. - */ - if ( empty( $url ) ) { - return; - } - - header( 'X-Redirect-By: Dark-Matter' ); - header( 'Location:' . $url, true, 301 ); - - die; -} - -/** - * We use `muplugins_loaded` action (introduced in WordPress 2.8.0) rather than - * the "ms_loaded" (introduced in WordPress 4.6.0). - * - * A hook on `muplugins_loaded` is used to ensure that WordPress has loaded the - * Blog / Site globals. This is specifically useful when some one goes to the - * Admin domain URL - http://my.sites.com/two/ - which is to redirect to the - * primary domain - http://example.com. - */ -add_action( 'muplugins_loaded', 'darkmatter_maybe_redirect', 20 ); diff --git a/domain-mapping/inc/sunrise.php b/domain-mapping/inc/sunrise.php deleted file mode 100644 index c54f1beb..00000000 --- a/domain-mapping/inc/sunrise.php +++ /dev/null @@ -1,107 +0,0 @@ -get( $fqdn ); - -if ( $dm_domain && $dm_domain->active ) { - /** - * Prepare all the global variables. This is require irrespective of whether - * it is a primary or secondary domain. - */ - global $current_blog, $original_blog; - $current_blog = get_site( $dm_domain->blog_id ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited - - global $current_site; - $current_site = WP_Network::get_instance( $current_blog->site_id ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited - - // @codingStandardsIgnoreStart - global $blog_id; - $blog_id = $current_blog->blog_id; - global $site_id; - $site_id = $current_blog->site_id; - // @codingStandardsIgnoreEnd - - /** - * Dark Matter will disengage if the website is no longer public or is - * archived or deleted. - */ - if ( (int) $current_blog->public < 0 || '0' !== $current_blog->archived || '0' !== $current_blog->deleted ) { - return; - } - - /** - * If the primary domain, then update the WP_Site properties to match the - * mapped domain and not the admin domain. - */ - if ( $dm_domain->is_primary ) { - $original_blog = clone $current_blog; - - $current_blog->domain = $dm_domain->domain; - $current_blog->path = '/'; - - /** - * Load and prepare the WordPress Network. - */ - global $current_site; // phpcs:ignore WordPressVIPMinimum.Variables.VariableAnalysis.VariableRedeclaration - $current_site = WP_Network::get_instance( $current_blog->site_id ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited - - if ( ! defined( 'COOKIE_DOMAIN' ) ) { - define( 'COOKIE_DOMAIN', $dm_domain->domain ); - } - - define( 'DOMAIN_MAPPING', true ); - - if ( empty( $current_site->blog_id ) ) { - $current_site->blog_id = get_main_site_id( $current_site->id ); - } - - /** - * Set the other necessary globals to ensure WordPress functions correctly. - */ - // @codingStandardsIgnoreStart - global $blog_id; - $blog_id = $current_blog->blog_id; - global $site_id; - $site_id = $current_blog->site_id; - // @codingStandardsIgnoreEnd - } -} - -/** - * Determine if we should perform a redirect. - */ -require_once $dirname . '/inc/redirect.php'; diff --git a/domain-mapping/sso/class-dm-sso-cookie.php b/domain-mapping/sso/class-dm-sso-cookie.php deleted file mode 100644 index a23e76f3..00000000 --- a/domain-mapping/sso/class-dm-sso-cookie.php +++ /dev/null @@ -1,377 +0,0 @@ -is_admin_domain() ) { - add_action( 'wp_head', array( $this, 'head_script' ) ); - add_action( 'plugins_loaded', array( $this, 'validate_token' ) ); - } - } - - /** - * Creates a nonce that isn't linked to a user, like the APIs in WordPress Core, but functions in a similar fashion. - * - * @since 2.0.4 - * - * @param string $action Value which creates the unique nonce. - * @return string Nonce token for use. - */ - private function create_shared_nonce( $action = '' ) { - $i = wp_nonce_tick(); - return substr( wp_hash( $i . '|' . $action, 'nonce' ), -12, 10 ); - } - - /** - * Verify a shared nonce. - * - * @since 2.0.4 - * - * @see create_shared_nonce() - * - * @param string $nonce Nonce that was used and requires verification. - * @param string $action Value which provides the nonce uniqueness. - * @return bool|int An integer if the nonce check passed, 1 for 0-12 hours ago and 2 for 12-24 hours ago. False otherwise. - */ - private function verify_shared_nonce( $nonce = '', $action = '' ) { - if ( empty( $nonce ) ) { - return false; - } - - $i = wp_nonce_tick(); - - /** - * Nonce generated 0-12 hours ago - */ - $expected = substr( wp_hash( $i . '|' . $action, 'nonce' ), -12, 10 ); - if ( hash_equals( $expected, $nonce ) ) { - return 1; - } - - /** - * Nonce generated 12-24 hours ago - */ - $expected = substr( wp_hash( ( $i - 1 ) . '|' . $action, 'nonce' ), -12, 10 ); - if ( hash_equals( $expected, $nonce ) ) { - return 2; - } - - /** - * Invalid. - */ - return false; - } - - /** - * Determines if the current request is on the Admin Domain. - * - * @since 2.0.0 - * - * @return bool True if current request is on the admin domain. False otherwise. - */ - private function is_admin_domain() { - $network = get_network(); - - $http_host = ( empty( $_SERVER['HTTP_HOST'] ) ? '' : wp_strip_all_tags( wp_unslash( $_SERVER['HTTP_HOST'] ) ) ); - - if ( ! empty( $network ) && false === stripos( $network->domain, $http_host ) ) { - return false; - } - - return true; - } - - /** - * Create the JavaScript output include for logging a user in to the admin - * when on the Mapped domain. This is ultimately what makes the Admin Bar - * appear. - * - * @since 2.0.0 - * - * @return void - */ - public function login_token() { - header( 'Content-Type: text/javascript' ); - - $this->nocache_headers(); - - /** - * Ensure that the JavaScript is never empty. - */ - echo '// dm_sso' . PHP_EOL; - - if ( is_user_logged_in() ) { - $referer = ( empty( $_SERVER['HTTP_REFERER'] ) ? '' : wp_strip_all_tags( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) ); - - $action = sprintf( - 'darkmatter-sso|%1$s|%2$s', - $referer, - md5( empty( $_SERVER['HTTP_USER_AGENT'] ) ? '' : wp_strip_all_tags( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) ) - ); - - /** - * Construct an authentication token which is passed back along with an - * action flag to tell the front end to - */ - $url = add_query_arg( - array( - '__dm_action' => 'authorise', - 'auth' => wp_generate_auth_cookie( get_current_user_id(), time() + ( 2 * MINUTE_IN_SECONDS ) ), - 'nonce' => $this->create_shared_nonce( $action ), - ), - $referer - ); - - printf( 'window.location.replace( "%1$s" );', esc_url_raw( $url ) ); - } - - die(); - } - - /** - * Create the JavaScript output for handling the logout functionality. - * Without this, users can end up in a state where they are logged out of - * the Admin domain but remain perpetually logged in to the Mapped domains. - * - * @since 2.0.0 - * - * @return void - */ - public function logout_token() { - header( 'Content-Type: text/javascript' ); - - $this->nocache_headers(); - - /** - * Ensure that the JavaScript is never empty. - */ - echo '// dm_sso' . PHP_EOL; - - if ( false === is_user_logged_in() ) { - $referer = ( empty( $_SERVER['HTTP_REFERER'] ) ? '' : wp_strip_all_tags( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) ); - - $url = add_query_arg( - array( - '__dm_action' => 'logout', - ), - $referer - ); - printf( 'window.location.replace( "%1$s" );', esc_url_raw( $url ) ); - } - - die(); - } - - /** - * Adds the - $header_value ) { - header( "{$header_name}: {$header_value}" ); - } - } - - /** - * Handle the validation of the login token and logging in of a user. Also - * handle the logout if that action is provided. - * - * @since 2.0.0 - * - * @return void - */ - public function validate_token() { - $dm_action = ( empty( $_GET['__dm_action'] ) ? '' : wp_strip_all_tags( wp_unslash( $_GET['__dm_action'] ) ) ); - - /** - * Ensure that URLs with the __dm_action query string are not cached by browsers. - */ - if ( ! empty( $dm_action ) ) { - $this->nocache_headers(); - } - - /** - * If the validation token is provided on the admin domain, rather than the primary / mapped domain, then just - * ignore it and end processing. - */ - if ( $this->is_admin_domain() ) { - return; - } - - /** - * First check to see if the authorise action is provided in the URL. - */ - if ( 'authorise' === $dm_action ) { - /** - * Validate the token provided in the URL. - */ - $user_id = wp_validate_auth_cookie( wp_strip_all_tags( wp_unslash( $_GET['auth'] ) ), 'auth' ); - $nonce = wp_strip_all_tags( wp_unslash( $_GET['nonce'] ) ); - - $action = sprintf( - 'darkmatter-sso|%1$s|%2$s', - ( empty( $_SERVER['HTTP_REFERER'] ) ? '' : wp_strip_all_tags( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) ), - md5( empty( $_SERVER['HTTP_USER_AGENT'] ) ? '' : wp_strip_all_tags( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) ) - ); - - /** - * Check if the validate token worked and we have a User ID. It will - * display an error message or login the User if all works out well. - */ - if ( false === $user_id || ! $this->verify_shared_nonce( $nonce, $action ) ) { - wp_die( 'Oops! Something went wrong with logging in.' ); - } else { - /** - * Create the Login session cookie and redirect the user to the - * current page with the URL querystrings for Domain Mapping SSO - * removed. - */ - wp_set_auth_cookie( $user_id ); - - // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect - wp_redirect( esc_url( remove_query_arg( array( '__dm_action', 'auth', 'nonce' ) ) ), 302, 'Dark-Matter' ); - die(); - } - } elseif ( 'logout' === $dm_action ) { - wp_logout(); - - // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect - wp_redirect( esc_url( remove_query_arg( array( '__dm_action' ) ) ), 302, 'Dark-Matter' ); - - die(); - } - } - - /** - * Return the Singleton Instance of the class. - * - * @since 2.0.0 - * - * @return DM_SSO_Cookie - */ - public static function instance() { - static $instance = false; - - if ( ! $instance ) { - $instance = new self(); - } - - return $instance; - } -} - -DM_SSO_Cookie::instance(); diff --git a/includes/classes/DarkMatter.php b/includes/classes/DarkMatter.php new file mode 100644 index 00000000..813c7036 --- /dev/null +++ b/includes/classes/DarkMatter.php @@ -0,0 +1,190 @@ +register_domainmapping(); + + /** + * SSO is a web-based process and not needed in the CLI. + */ + if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) { + $this->register_sso(); + } + } + + /** + * Register a set of classes used by the Dark Matter plugin. + * + * @since 3.0.0 + * + * @param array $classes String of class names / namespaces to be instantiated. + * @return array Array of the resultant objects. + */ + private function class_register( $classes = [] ) { + if ( empty( $classes ) ) { + return []; + } + + + $objs = []; + foreach ( $classes as $class ) { + $obj = new $class(); + + if ( $obj instanceof Registerable ) { + $obj->register(); + } + + if ( $obj instanceof \WP_CLI_Command ) { + $obj::define(); + } + + if ( $obj instanceof \WP_REST_Controller ) { + $obj->register_routes(); + } + } + + return $objs; + } + + /** + * Register the classes for Domain Mapping. + * + * @since 3.0.0 + * + * @return void + */ + public function register_domainmapping() { + /** + * Domain type constants. + */ + define( 'DM_DOMAIN_TYPE_MAIN', 1 ); + define( 'DM_DOMAIN_TYPE_MEDIA', 2 ); + + /** + * Basic compatibility/configuration for bbPress and WooCommerce. + */ + if ( + /** + * Detect if WooCommerce is installed. + */ + class_exists( 'WooCommerce' ) + || + /** + * Detect if bbPress is installed. + */ + class_exists( 'bbPress' ) + ) { + add_filter( 'darkmatter_allow_logins', '__return_true' ); + } + + $domainmapping_classes = [ + DomainMapping\Installer::class, + DomainMapping\Processor\Mapping::class, + DomainMapping\Processor\Media::class, + ]; + + if ( + ( ! defined( 'DARKMATTER_HIDE_UI' ) || ! DARKMATTER_HIDE_UI ) + && ! is_main_site() + ) { + $domainmapping_classes[] = DomainMapping\Admin\DomainSettings::class; + } + + $domainmapping_classes[] = DomainMapping\Admin\HealthChecks::class; + + if ( defined( 'WPSEO_VERSION' ) ) { + $domainmapping_classes = DomainMapping\Support\Yoast::class; + } + + $this->class_register( $domainmapping_classes ); + + if ( defined( 'WP_CLI' ) && WP_CLI ) { + $this->class_register( + [ + DomainMapping\CLI\Domains::class, + DomainMapping\CLI\Dropin::class, + DomainMapping\CLI\Restricted::class, + ] + ); + } + } + + /** + * Register REST routes. This is separate due to the need to be fired on the `rest_api_init` hook. + * + * @since 3.0.0 + * + * @return void + */ + public function register_rest() { + $this->class_register( + [ + DomainMapping\REST\Domains::class, + DomainMapping\REST\Restricted::class, + ] + ); + } + + /** + * Single Sign-On functionality. + * + * @return void + */ + public function register_sso() { + $this->class_register( + [ + Admin::class, + Authorise::class, + Authenticate::class, + ] + ); + } + + /** + * Return the Singleton Instance of the class. + * + * @since 3.0.0 + * + * @return DarkMatter + */ + public static function instance() { + static $instance = false; + + if ( ! $instance ) { + $instance = new self(); + } + + return $instance; + } +} diff --git a/includes/classes/DomainMapping/Admin/DomainSettings.php b/includes/classes/DomainMapping/Admin/DomainSettings.php new file mode 100644 index 00000000..f6f91b14 --- /dev/null +++ b/includes/classes/DomainMapping/Admin/DomainSettings.php @@ -0,0 +1,87 @@ +slug = 'domains'; + $this->menu_title = __( 'Domains', 'dark-matter' ); + $this->page_title = __( 'Domain Mappings', 'dark-matter' ); + + /** + * Allows the override of the default permission for per site domain management. + * + * @since 2.1.2 + * + * @param string $capability Capability required to manage domains (upgrade_network / Super Admin). + * @param string $context The context the permission is checked. + */ + $this->permission = apply_filters( 'dark_matter_domain_permission', 'upgrade_network', 'admin' ); + } + + /** + * Enqueue assets for the Admin Page. + * + * @since 3.0.0 + * + * @return void + */ + public function enqueue() { + $min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' ); + + wp_register_script( + 'dark-matter-domains', + DM_PLUGIN_URL . 'domain-mapping/build/domain-mapping' . $min . '.js', + [ 'wp-i18n' ], + DM_VERSION, + true + ); + + wp_localize_script( + 'dark-matter-domains', + 'dmSettings', + [ + 'rest_root' => get_rest_url(), + 'nonce' => wp_create_nonce( 'wp_rest' ), + ] + ); + + wp_enqueue_script( 'dark-matter-domains' ); + + wp_enqueue_style( 'dark-matter-domains', DM_PLUGIN_URL . 'domain-mapping/build/domain-mapping-style' . $min . '.css', [], DM_VERSION ); + } + + /** + * Output the HTML container for the React app. + * + * @since 3.0.0 + * + * @return void + */ + public function render() { + ?> +
+ __( 'Dark Matter single-sign on (bringing the admin bar to the public-facing side) is enabled.', 'dark-matter' ), 'status' => 'good', - 'badge' => array( + 'badge' => [ 'label' => __( 'Domain Mapping', 'dark-matter' ), 'color' => 'green', - ), + ], 'description' => sprintf( '

%s

', __( 'Dark Matter single-sign on is enabled and can load the admin bar when WordPress users are visiting the public-facing side of your site.', 'dark-matter' ) @@ -155,10 +160,10 @@ public function test_dropin() { $result = [ 'label' => __( 'Sunrise dropin is enabled and up-to-date.', 'dark-matter' ), 'status' => 'good', - 'badge' => array( + 'badge' => [ 'label' => __( 'Domain Mapping', 'dark-matter' ), 'color' => 'green', - ), + ], 'description' => sprintf( '

%s

', __( 'Sunrise is the name of the dropin file which maps custom domains to your WordPress sites.', 'dark-matter' ) @@ -219,16 +224,15 @@ public function test_primary_domain_set() { $result = [ 'label' => __( 'You have a primary domain.', 'dark-matter' ), 'status' => 'good', - 'badge' => array( + 'badge' => [ 'label' => __( 'Domain Mapping', 'dark-matter' ), 'color' => 'green', - ), - 'description' => '', + ], 'actions' => '', 'test' => 'darkmatter_domain_mapping_primary_domain_set', ]; - $primary = DarkMatter_Primary::instance()->get(); + $primary = Primary::instance()->get(); if ( empty( $primary ) ) { $result['label'] = __( 'You have not a set a primary domain.', 'dark-matter' ); @@ -273,10 +277,10 @@ public function test_ssl() { $result = [ 'label' => __( 'Your SSL configuration is compatible with Dark Matter.', 'dark-matter' ), 'status' => 'good', - 'badge' => array( + 'badge' => [ 'label' => __( 'Domain Mapping', 'dark-matter' ), 'color' => 'green', - ), + ], 'description' => sprintf( '

%s

', __( 'Your admin area is secured by HTTPS and compatible with domain mapping.', 'dark-matter' ) @@ -308,22 +312,4 @@ public function test_ssl() { return $result; } - - /** - * Return the Singleton Instance of the class. - * - * @since 2.1.0 - * - * @return DM_HealthChecks - */ - public static function instance() { - static $instance = false; - - if ( ! $instance ) { - $instance = new self(); - } - - return $instance; - } } -DM_HealthChecks::instance(); diff --git a/domain-mapping/cli/class-darkmatter-domain-cli.php b/includes/classes/DomainMapping/CLI/Domains.php similarity index 92% rename from domain-mapping/cli/class-darkmatter-domain-cli.php rename to includes/classes/DomainMapping/CLI/Domains.php index 0fffc3bc..7ee4926e 100644 --- a/domain-mapping/cli/class-darkmatter-domain-cli.php +++ b/includes/classes/DomainMapping/CLI/Domains.php @@ -1,21 +1,28 @@ add( $fqdn, $opts['primary'], $opts['https'], $opts['force'], ! $opts['disable'], $type ); if ( is_wp_error( $result ) ) { @@ -121,6 +128,15 @@ private function check_type_opt( $type = '' ) { return DM_DOMAIN_TYPE_MAIN; } + /** + * Include this CLI amongst the others. + * + * @return void + */ + public static function define() { + WP_CLI::add_command( 'darkmatter domain', self::class ); + } + /** * List a domain for the current Site. If the the URL is omitted and the * command is run on the root Site, it will list all domains available for @@ -166,12 +182,12 @@ public function list( $args, $assoc_args ) { ] ); - if ( ! in_array( $opts['format'], array( 'table', 'json', 'csv', 'yaml', 'count' ) ) ) { + if ( ! in_array( $opts['format'], [ 'table', 'json', 'csv', 'yaml', 'count' ] ) ) { $opts['format'] = 'table'; } if ( $opts['primary'] ) { - $db = DarkMatter_Primary::instance(); + $db = Manager\Primary::instance(); $domains = $db->get_all(); } else { /** @@ -184,7 +200,7 @@ public function list( $args, $assoc_args ) { $site_id = null; } - $db = DarkMatter_Domains::instance(); + $db = Manager\Domain::instance(); $domains = $db->get_domains( $site_id ); } @@ -196,13 +212,13 @@ function ( $domain ) { $no_val = __( 'No', 'dark-matter' ); $yes_val = __( 'Yes', 'dark-matter' ); - $columns = array( + $columns = [ 'F.Q.D.N.' => $domain->domain, 'Primary' => ( $domain->is_primary ? $yes_val : $no_val ), 'Protocol' => ( $domain->is_https ? 'HTTPS' : 'HTTP' ), 'Active' => ( $domain->active ? $yes_val : $no_val ), 'Type' => ( DM_DOMAIN_TYPE_MEDIA === $domain->type ? 'Media' : 'Main' ), - ); + ]; /** * If the query is the root Site and we are displaying all domains, @@ -288,7 +304,7 @@ public function remove( $args, $assoc_args ) { ] ); - $db = DarkMatter_Domains::instance(); + $db = Manager\Domain::instance(); /** * Remove the domain. @@ -371,7 +387,7 @@ public function set( $args, $assoc_args ) { $fqdn = $args[0]; - $db = DarkMatter_Domains::instance(); + $db = Manager\Domain::instance(); $domain_before = $db->get( $fqdn ); $opts = wp_parse_args( @@ -462,4 +478,3 @@ public function set( $args, $assoc_args ) { WP_CLI::success( $fqdn . __( ': successfully updated.', 'dark-matter' ) ); } } -WP_CLI::add_command( 'darkmatter domain', 'DarkMatter_Domain_CLI' ); diff --git a/domain-mapping/cli/class-darkmatter-dropin-cli.php b/includes/classes/DomainMapping/CLI/Dropin.php similarity index 81% rename from domain-mapping/cli/class-darkmatter-dropin-cli.php rename to includes/classes/DomainMapping/CLI/Dropin.php index 546bedd9..beb629fb 100644 --- a/domain-mapping/cli/class-darkmatter-dropin-cli.php +++ b/includes/classes/DomainMapping/CLI/Dropin.php @@ -1,23 +1,26 @@ is_dropin_latest() ) { WP_CLI::success( __( 'Current Sunrise dropin matches the Sunrise within Dark Matter plugin.', 'dark-matter' ) ); return; @@ -40,6 +42,15 @@ public function check() { WP_CLI::error( __( 'Sunrise dropin does not match the Sunrise within Dark Matter plugin. Consider using the "update" command to correct this issue.', 'dark-matter' ) ); } + /** + * Include this CLI amongst the others. + * + * @return void + */ + public static function define() { + WP_CLI::add_command( 'darkmatter dropin', self::class ); + } + /** * Upgrade the Sunrise dropin plugin to the latest version within the Dark * Matter plugin. @@ -66,7 +77,7 @@ public function check() { */ public function update( $args, $assoc_args ) { $destination = WP_CONTENT_DIR . '/sunrise.php'; - $source = DM_PATH . '/domain-mapping/sunrise.php'; + $source = DM_PATH . '/includes/dropins/sunrise.php'; $opts = wp_parse_args( $assoc_args, @@ -100,4 +111,3 @@ public function update( $args, $assoc_args ) { } } } -WP_CLI::add_command( 'darkmatter dropin', 'DarkMatter_Dropin_CLI' ); diff --git a/domain-mapping/cli/class-darkmatter-restrict-cli.php b/includes/classes/DomainMapping/CLI/Restricted.php similarity index 81% rename from domain-mapping/cli/class-darkmatter-restrict-cli.php rename to includes/classes/DomainMapping/CLI/Restricted.php index ed2171fc..6d893409 100644 --- a/domain-mapping/cli/class-darkmatter-restrict-cli.php +++ b/includes/classes/DomainMapping/CLI/Restricted.php @@ -1,21 +1,26 @@ add( $fqdn ); if ( is_wp_error( $result ) ) { @@ -51,6 +56,15 @@ public function add( $args, $assoc_args ) { WP_CLI::success( $fqdn . __( ': is now restricted.', 'dark-matter' ) ); } + /** + * Include this CLI amongst the others. + * + * @return void + */ + public static function define() { + WP_CLI::add_command( 'darkmatter restrict', self::class ); + } + /** * Retrieve a list of all Restricted domains for the Network. * @@ -90,11 +104,11 @@ public function list( $args, $assoc_args ) { ] ); - if ( ! in_array( $opts['format'], array( 'ids', 'table', 'json', 'csv', 'yaml', 'count' ) ) ) { + if ( ! in_array( $opts['format'], [ 'ids', 'table', 'json', 'csv', 'yaml', 'count' ] ) ) { $opts['format'] = 'table'; } - $db = DarkMatter_Restrict::instance(); + $db = Manager\Restricted::instance(); $restricted = $db->get(); @@ -146,7 +160,7 @@ public function remove( $args, $assoc_args ) { $fqdn = $args[0]; - $restricted = DarkMatter_Restrict::instance(); + $restricted = Manager\Restricted::instance(); $result = $restricted->delete( $fqdn ); if ( is_wp_error( $result ) ) { @@ -156,4 +170,3 @@ public function remove( $args, $assoc_args ) { WP_CLI::success( $fqdn . __( ': is no longer restricted.', 'dark-matter' ) ); } } -WP_CLI::add_command( 'darkmatter restrict', 'DarkMatter_Restrict_CLI' ); diff --git a/domain-mapping/classes/class-dm-domain.php b/includes/classes/DomainMapping/Data/Domain.php similarity index 86% rename from domain-mapping/classes/class-dm-domain.php rename to includes/classes/DomainMapping/Data/Domain.php index 4986174b..d7109ea9 100644 --- a/domain-mapping/classes/class-dm-domain.php +++ b/includes/classes/DomainMapping/Data/Domain.php @@ -1,19 +1,22 @@ $value ) { diff --git a/includes/classes/DomainMapping/Helper.php b/includes/classes/DomainMapping/Helper.php new file mode 100644 index 00000000..4781260b --- /dev/null +++ b/includes/classes/DomainMapping/Helper.php @@ -0,0 +1,193 @@ +get_request_filename() : $filename; + + $admin_filenames = [ + 'wp-login.php' => true, + 'wp-register.php' => true, + ]; + + if ( is_admin() || ( ! empty( $filename ) && array_key_exists( $filename, $admin_filenames ) ) ) { + return true; + } + + return false; + } + + /** + * Checks the supply blog/site to ensure it is public. + * + * @since 3.0.0 + * + * @param \WP_Site $blog Blog to check. + * @return bool True if public. False otherwise. + */ + public function is_public( $blog ) { + /** + * Make sure we have the right kind of object. + */ + if ( ! $blog instanceof \WP_Site ) { + return false; + } + + return ( + /** + * Check the current blog is public and be compatible with plugins such as Restricted Site Access. + */ + 0 < (int) $blog->public + /** + * Check the current blog has not been archived. + */ + && 0 === (int) $blog->archived + /** + * Check the current blog has not been "soft" deleted. + */ + && 0 === (int) $blog->deleted + ); + } + + /** + * Map the primary domain on the passed in value if it contains the unmapped URL and the Site has a primary domain. + * + * @since 3.0.0 + * + * @param mixed $value Potentially a value containing the site's unmapped URL. + * @param integer $blog_id Site (Blog) ID for the URL which is being mapped. + * @return string If unmapped URL is found, then returns the primary URL. Untouched otherwise. + */ + public function map( $value = '', $blog_id = 0 ) { + /** + * Ensure that we are working with a string. + */ + if ( ! is_string( $value ) ) { + return $value; + } + + /** + * Retrieve the current blog. + */ + $blog = get_site( absint( $blog_id ) ); + $primary = Primary::instance()->get( $blog->blog_id ); + + $unmapped = untrailingslashit( $blog->domain . $blog->path ); + + /** + * If there is no primary domain or the unmapped version cannot be found + * then we return the value as-is. + */ + if ( empty( $primary ) || false === stripos( $value, $unmapped ) ) { + return $value; + } + + $domain = 'http' . ( $primary->is_https ? 's' : '' ) . '://' . $primary->domain; + + return preg_replace( "#https?://{$unmapped}#", $domain, $value ); + } + + /** + * Converts a URL from a mapped domain to the admin domain. This will only convert a URL which is the primary + * domain. + * + * @since 3.0.0 + * + * @param mixed $value Potentially a value containing the site's unmapped URL. + * @return mixed If unmapped URL is found, then returns the primary URL. Untouched otherwise. + */ + public function unmap( $value = '' ) { + /** + * Ensure that we are working with a string. + */ + if ( ! is_string( $value ) ) { + return $value; + } + + /** + * Retrieve the current blog. + */ + $blog = get_site(); + $primary = Primary::instance()->get(); + + /** + * If there is no primary domain or the primary domain cannot be found + * then we return the value as-is. + */ + if ( empty( $primary ) || false === stripos( $value, $primary->domain ) ) { + return $value; + } + + $unmapped = 'http' . ( $primary->is_https ? 's' : '' ) . '://' . untrailingslashit( $blog->domain . $blog->path ); + + return preg_replace( "#https?://{$primary->domain}#", $unmapped, $value ); + } + + /** + * Return the Singleton Instance of the class. + * + * @return Helper + */ + public static function instance() { + static $instance = false; + + if ( ! $instance ) { + $instance = new self(); + } + + return $instance; + } +} diff --git a/domain-mapping/classes/class-dm-database.php b/includes/classes/DomainMapping/Installer.php similarity index 79% rename from domain-mapping/classes/class-dm-database.php rename to includes/classes/DomainMapping/Installer.php index 752bbd60..944820e3 100644 --- a/domain-mapping/classes/class-dm-database.php +++ b/includes/classes/DomainMapping/Installer.php @@ -1,26 +1,29 @@ wpdb = $wpdb; - if ( defined( 'DM_NETWORK_MEDIA' ) && ! empty( DM_NETWORK_MEDIA ) ) { - $this->network_media = DM_NETWORK_MEDIA; + if ( defined( '\DM_NETWORK_MEDIA' ) && ! empty( \DM_NETWORK_MEDIA ) ) { + $this->network_media = \DM_NETWORK_MEDIA; } } @@ -70,11 +75,11 @@ public function __construct() { * @since 2.0.0 * * @param string $fqdn Fully qualified domain name. - * @return WP_Error|boolean True on pass. WP_Error on failure. + * @return \WP_Error|boolean True on pass. WP_Error on failure. */ private function _basic_check( $fqdn = '' ) { if ( empty( $fqdn ) ) { - return new WP_Error( 'empty', __( 'Please include a fully qualified domain name to be added.', 'dark-matter' ) ); + return new \WP_Error( 'empty', __( 'Please include a fully qualified domain name to be added.', 'dark-matter' ) ); } /** @@ -90,7 +95,7 @@ private function _basic_check( $fqdn = '' ) { } if ( ! empty( $domain_parts['path'] ) || ! empty( $domain_parts['port'] ) || ! empty( $domain_parts['query'] ) ) { - return new WP_Error( 'unsure', __( 'The domain provided contains path, port, or query string information. Please removed this before continuing.', 'dark-matter' ) ); + return new \WP_Error( 'unsure', __( 'The domain provided contains path, port, or query string information. Please removed this before continuing.', 'dark-matter' ) ); } $fqdn = $domain_parts['host']; @@ -99,20 +104,20 @@ private function _basic_check( $fqdn = '' ) { * Check to ensure we have a valid domain to work with. */ if ( ! filter_var( $fqdn, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME ) ) { - return new WP_Error( 'domain', __( 'The domain is not valid.', 'dark-matter' ) ); + return new \WP_Error( 'domain', __( 'The domain is not valid.', 'dark-matter' ) ); } if ( defined( 'DOMAIN_CURRENT_SITE' ) && DOMAIN_CURRENT_SITE === $fqdn ) { - return new WP_Error( 'wp-config', __( 'You cannot configure the WordPress Network primary domain.', 'dark-matter' ) ); + return new \WP_Error( 'wp-config', __( 'You cannot configure the WordPress Network primary domain.', 'dark-matter' ) ); } if ( is_main_site() ) { - return new WP_Error( 'root', __( 'Domains cannot be mapped to the main / root Site.', 'dark-matter' ) ); + return new \WP_Error( 'root', __( 'Domains cannot be mapped to the main / root Site.', 'dark-matter' ) ); } - $reserve = DarkMatter_Restrict::instance(); + $reserve = \DarkMatter\DomainMapping\Manager\Restricted::instance(); if ( $reserve->is_exist( $fqdn ) ) { - return new WP_Error( 'reserved', __( 'This domain has been reserved.', 'dark-matter' ) ); + return new \WP_Error( 'reserved', __( 'This domain has been reserved.', 'dark-matter' ) ); } /** @@ -153,7 +158,7 @@ private function _clear_caches( $fqdn = '' ) { * @param boolean $force Whether the update should be forced. * @param boolean $active Default is active. Set to false if you wish to add a domain but not make it active. * @param integer $type Domain type. Defaults to `1`, which is "main". - * @return DM_Domain|WP_Error DM_Domain on success. WP_Error on failure. + * @return Data\Domain|\WP_Error Domain on success. WP_Error on failure. */ public function add( $fqdn = '', $is_primary = false, $is_https = false, $force = true, $active = true, $type = DM_DOMAIN_TYPE_MAIN ) { $fqdn = $this->_basic_check( $fqdn ); @@ -166,10 +171,10 @@ public function add( $fqdn = '', $is_primary = false, $is_https = false, $force * Check that the FQDN is not already stored in the database. */ if ( $this->is_exist( $fqdn ) ) { - return new WP_Error( 'exists', __( 'This domain is already assigned to a Site.', 'dark-matter' ) ); + return new \WP_Error( 'exists', __( 'This domain is already assigned to a Site.', 'dark-matter' ) ); } - $dm_primary = DarkMatter_Primary::instance(); + $dm_primary = Primary::instance(); if ( $is_primary ) { $primary_domain = $dm_primary->get(); @@ -179,7 +184,7 @@ public function add( $fqdn = '', $is_primary = false, $is_https = false, $force */ if ( ! empty( $primary_domain ) ) { if ( ! $force ) { - return new WP_Error( 'primary', __( 'You cannot add this domain as the primary domain without using the force flag.', 'dark-matter' ) ); + return new \WP_Error( 'primary', __( 'You cannot add this domain as the primary domain without using the force flag.', 'dark-matter' ) ); } } } @@ -188,29 +193,29 @@ public function add( $fqdn = '', $is_primary = false, $is_https = false, $force * Check the type is valid. */ if ( DM_DOMAIN_TYPE_MAIN !== $type && DM_DOMAIN_TYPE_MEDIA !== $type ) { - return new WP_Error( 'type', __( 'The type for the new domain is not supported.', 'dark-matter' ) ); + return new \WP_Error( 'type', __( 'The type for the new domain is not supported.', 'dark-matter' ) ); } - $_domain = array( + $_domain = [ 'active' => ( ! $active ? false : true ), 'blog_id' => get_current_blog_id(), 'domain' => $fqdn, 'is_primary' => ( ! $is_primary ? false : true ), 'is_https' => ( ! $is_https ? false : true ), 'type' => ( ! empty( $type ) ? $type : DM_DOMAIN_TYPE_MAIN ), - ); + ]; $result = $this->wpdb->insert( $this->dm_table, $_domain, - array( + [ '%d', '%d', '%s', '%d', '%d', '%d', - ) + ] ); if ( $result ) { @@ -235,7 +240,7 @@ public function add( $fqdn = '', $is_primary = false, $is_https = false, $force $this->primary_set( $fqdn, get_current_blog_id() ); } - $dm_domain = new DM_Domain( (object) $_domain ); + $dm_domain = new Data\Domain( (object) $_domain ); $this->update_last_changed(); @@ -247,14 +252,14 @@ public function add( $fqdn = '', $is_primary = false, $is_https = false, $force * * @since 2.0.0 * - * @param DM_Domain $dm_domain Domain object of the newly added Domain. + * @param Data\Domain $dm_domain Domain object of the newly added Domain. */ do_action( 'darkmatter_domain_add', $dm_domain ); return $dm_domain; } - return new WP_Error( 'unknown', __( 'Sorry, the domain could not be added. An unknown error occurred.', 'dark-matter' ) ); + return new \WP_Error( 'unknown', __( 'Sorry, the domain could not be added. An unknown error occurred.', 'dark-matter' ) ); } /** @@ -322,7 +327,7 @@ public function clear_cache_for_domain_type( $type = DM_DOMAIN_TYPE_MAIN, $site_ * * @param string $fqdn FQDN to be deleted. * @param boolean $force Force the FQDN to be deleted, even if it is the primary domain. - * @return WP_Error|boolean True on success. False otherwise. + * @return \WP_Error|boolean True on success. False otherwise. */ public function delete( $fqdn = '', $force = true ) { $fqdn = $this->_basic_check( $fqdn ); @@ -335,7 +340,7 @@ public function delete( $fqdn = '', $force = true ) { * Cannot delete what does not exist. */ if ( ! $this->is_exist( $fqdn ) ) { - return new WP_Error( 'exists', __( 'The domain cannot be found.', 'dark-matter' ) ); + return new \WP_Error( 'exists', __( 'The domain cannot be found.', 'dark-matter' ) ); } /** @@ -344,7 +349,7 @@ public function delete( $fqdn = '', $force = true ) { $_domain = $this->get( $fqdn ); if ( ! $_domain || get_current_blog_id() !== $_domain->blog_id ) { - return new WP_Error( 'not found', __( 'The domain cannot be found.', 'dark-matter' ) ); + return new \WP_Error( 'not found', __( 'The domain cannot be found.', 'dark-matter' ) ); } /** @@ -355,7 +360,7 @@ public function delete( $fqdn = '', $force = true ) { if ( $force ) { $this->primary_unset( $_domain->domain, $_domain->blog_id ); } else { - return new WP_Error( 'primary', __( 'This domain is the primary domain for this Site. Please provide the force flag to delete.', 'dark-matter' ) ); + return new \WP_Error( 'primary', __( 'This domain is the primary domain for this Site. Please provide the force flag to delete.', 'dark-matter' ) ); } } @@ -381,14 +386,14 @@ public function delete( $fqdn = '', $force = true ) { * * @since 2.0.0 * - * @param DM_Domain $_domain Domain object that was deleted. + * @param Data\Domain $_domain Domain object that was deleted. */ do_action( 'darkmatter_domain_delete', $_domain ); return true; } - return new WP_Error( 'unknown', __( 'Sorry, the domain could not be deleted. An unknown error occurred.', 'dark-matter' ) ); + return new \WP_Error( 'unknown', __( 'Sorry, the domain could not be deleted. An unknown error occurred.', 'dark-matter' ) ); } @@ -398,7 +403,7 @@ public function delete( $fqdn = '', $force = true ) { * @since 2.0.0 * * @param string $fqdn FQDN to search for. - * @return DM_Domain|boolean Domain object. False on failure or not found. + * @return Data\Domain|boolean Domain object. False on failure or not found. */ public function find( $fqdn = '' ) { if ( empty( $fqdn ) ) { @@ -414,7 +419,7 @@ public function find( $fqdn = '' ) { * @since 2.0.0 * * @param string $fqdn FQDN to search for. - * @return DM_Domain|boolean Domain object. False otherwise. + * @return Data\Domain|boolean Domain object. False otherwise. */ public function get( $fqdn = '' ) { if ( empty( $fqdn ) ) { @@ -478,7 +483,7 @@ public function get( $fqdn = '' ) { /** * Return the DM_Domain object version. */ - return new DM_Domain( (object) $_domain ); + return new Data\Domain( (object) $_domain ); } /** @@ -515,7 +520,7 @@ public function get_domains_by_type( $type = DM_DOMAIN_TYPE_MEDIA, $site_id = 0, * Convert the domains into DM_Domain objects. */ foreach ( $this->network_media as $i => $media_domain ) { - $media_domains[ $i ] = new DM_Domain( + $media_domains[ $i ] = new Data\Domain( (object) [ 'active' => true, 'blog_id' => get_current_blog_id(), @@ -576,7 +581,7 @@ public function get_domains_by_type( $type = DM_DOMAIN_TYPE_MEDIA, $site_id = 0, /** * Retrieve the domain details, probably from cache, and get an array of `DM_Domain` objects. */ - $domains = array(); + $domains = []; foreach ( $_domains as $_domain ) { $domains[] = $this->get( $_domain ); @@ -615,7 +620,7 @@ public function get_domains( $site_id = 0 ) { /** * Retrieve the domain details from the cache. If the cache is */ - $domains = array(); + $domains = []; foreach ( $_domains as $_domain ) { $domains[] = $this->get( $_domain ); @@ -671,7 +676,7 @@ public function is_reserved( $fqdn = '' ) { * @return void */ private function primary_set( $domain = '', $blog_id = 0 ) { - $current_primary = DarkMatter_Primary::instance()->get( $blog_id ); + $current_primary = \DarkMatter\DomainMapping\Manager\Primary::instance()->get( $blog_id ); if ( ! empty( $current_primary ) && $domain !== $current_primary->domain ) { $this->update( $current_primary->domain, false, null, true, $current_primary->active ); @@ -748,7 +753,7 @@ public function reserve( $fqdn = '' ) { * @param boolean $force Whether the update should be forced. * @param boolean $active Default is active. Set to false if you wish to add a domain but not make it active. * @param integer $type Domain type. Defaults to `null`, do not change current value. Accepts `1` for main and `2` for Media. - * @return DM_Domain|WP_Error DM_Domain on success. WP_Error on failure. + * @return Data\Domain|\WP_Error DM_Domain on success. WP_Error on failure. */ public function update( $fqdn = '', $is_primary = null, $is_https = null, $force = true, $active = true, $type = null ) { $fqdn = $this->_basic_check( $fqdn ); @@ -760,16 +765,16 @@ public function update( $fqdn = '', $is_primary = null, $is_https = null, $force $domain_before = $this->get( $fqdn ); if ( ! $domain_before ) { - return new WP_Error( 'not found', __( 'Cannot find the domain to update.', 'dark-matter' ) ); + return new \WP_Error( 'not found', __( 'Cannot find the domain to update.', 'dark-matter' ) ); } - $dm_primary = DarkMatter_Primary::instance(); + $dm_primary = \DarkMatter\DomainMapping\Manager\Primary::instance(); - $_domain = array( + $_domain = [ 'active' => ( ! $active ? false : true ), 'blog_id' => $domain_before->blog_id, 'domain' => $fqdn, - ); + ]; /** * Determine if there is an attempt to update the "is primary" field. @@ -779,7 +784,7 @@ public function update( $fqdn = '', $is_primary = null, $is_https = null, $force * Any update to the "is primary" requires the force flag. */ if ( ! $force ) { - return new WP_Error( 'primary', __( 'You cannot update the primary flag without setting the force parameter to true', 'dark-matter' ) ); + return new \WP_Error( 'primary', __( 'You cannot update the primary flag without setting the force parameter to true', 'dark-matter' ) ); } $_domain['is_primary'] = $is_primary; @@ -796,16 +801,16 @@ public function update( $fqdn = '', $is_primary = null, $is_https = null, $force if ( DM_DOMAIN_TYPE_MAIN === $type || DM_DOMAIN_TYPE_MEDIA === $type ) { $_domain['type'] = $type; } else { - return new WP_Error( 'type', __( 'The type for the new domain is not supported.', 'dark-matter' ) ); + return new \WP_Error( 'type', __( 'The type for the new domain is not supported.', 'dark-matter' ) ); } } $result = $this->wpdb->update( $this->dm_table, $_domain, - array( + [ 'id' => $domain_before->id, - ) + ] ); if ( $result ) { @@ -841,7 +846,7 @@ public function update( $fqdn = '', $is_primary = null, $is_https = null, $force $this->primary_unset( $domain_before->domain, $domain_before->blog_id ); } - $domain_after = new DM_Domain( (object) $_domain ); + $domain_after = new Data\Domain( (object) $_domain ); $this->update_last_changed(); @@ -850,15 +855,15 @@ public function update( $fqdn = '', $is_primary = null, $is_https = null, $force * * @since 2.0.0 * - * @param DM_Domain $domain_after Domain object after the changes have been applied successfully. - * @param DM_Domain $domain_before Domain object before. + * @param Data\Domain $domain_after Domain object after the changes have been applied successfully. + * @param Data\Domain $domain_before Domain object before. */ do_action( 'darkmatter_domain_updated', $domain_after, $domain_before ); return $domain_after; } - return new WP_Error( 'unknown', __( 'Sorry, the domain could not be updated. An unknown error occurred.', 'dark-matter' ) ); + return new \WP_Error( 'unknown', __( 'Sorry, the domain could not be updated. An unknown error occurred.', 'dark-matter' ) ); } /** @@ -877,7 +882,7 @@ private function update_last_changed() { * * @since 2.0.0 * - * @return DarkMatter_Domains + * @return Domain */ public static function instance() { static $instance = false; diff --git a/domain-mapping/api/class-darkmatter-primary.php b/includes/classes/DomainMapping/Manager/Primary.php similarity index 85% rename from domain-mapping/api/class-darkmatter-primary.php rename to includes/classes/DomainMapping/Manager/Primary.php index 7379ba6d..90d75f1e 100644 --- a/domain-mapping/api/class-darkmatter-primary.php +++ b/includes/classes/DomainMapping/Manager/Primary.php @@ -1,21 +1,26 @@ get( $primary_domain ); return $_domain; @@ -118,7 +123,7 @@ public function get( $site_id = 0 ) { * * @since 2.0.0 * - * @return array Array of DM_Domain objects of the Primary domains for each Site in the Network. + * @return array Array of Domain objects of the Primary domains for each Site in the Network. */ public function get_all() { global $wpdb; @@ -130,7 +135,7 @@ public function get_all() { return array(); } - $db = DarkMatter_Domains::instance(); + $db = Domain::instance(); /** * Retrieve the DM_Domain objects for each of the primary domains. @@ -154,13 +159,13 @@ public function get_all() { * @return boolean True on success, false otherwise. */ public function set( $site_id = 0, $domain = '' ) { - $new_primary_domain = DarkMatter_Domains::instance()->get( $domain ); + $new_primary_domain = Domain::instance()->get( $domain ); if ( $new_primary_domain->blog_id !== $site_id ) { return false; } - $result = DarkMatter_Domains::instance()->update( + $result = Domain::instance()->update( $new_primary_domain->domain, true, $new_primary_domain->is_https, @@ -188,13 +193,13 @@ public function set( $site_id = 0, $domain = '' ) { * @return boolean True on success. False otherwise. */ public function unset( $site_id = 0, $domain = '', $db = false ) { - $new_primary_domain = DarkMatter_Domains::instance()->get( $domain ); + $new_primary_domain = Domain::instance()->get( $domain ); if ( $new_primary_domain->blog_id !== $site_id ) { return false; } - $result = DarkMatter_Domains::instance()->update( + $result = Domain::instance()->update( $new_primary_domain->domain, false, $new_primary_domain->is_https, @@ -226,7 +231,7 @@ private function update_last_changed() { * * @since 2.0.0 * - * @return DarkMatter_Primary + * @return Primary */ public static function instance() { static $instance = false; diff --git a/domain-mapping/api/class-darkmatter-restrict.php b/includes/classes/DomainMapping/Manager/Restricted.php similarity index 72% rename from domain-mapping/api/class-darkmatter-restrict.php rename to includes/classes/DomainMapping/Manager/Restricted.php index 5b8ee87e..9b0408a1 100644 --- a/domain-mapping/api/class-darkmatter-restrict.php +++ b/includes/classes/DomainMapping/Manager/Restricted.php @@ -1,19 +1,22 @@ is_exist( $fqdn ) ) { - return new WP_Error( 'used', __( 'This domain is in use.', 'dark-matter' ) ); + return new \WP_Error( 'used', __( 'This domain is in use.', 'dark-matter' ) ); } return $fqdn; @@ -82,7 +85,7 @@ private function _basic_checks( $fqdn ) { * @since 2.0.0 * * @param string $fqdn Domain to be added to the reserve list. - * @return WP_Error|boolean True on success, WP_Error otherwise. + * @return \WP_Error|boolean True on success, WP_Error otherwise. */ public function add( $fqdn = '' ) { $fqdn = $this->_basic_checks( $fqdn ); @@ -92,7 +95,7 @@ public function add( $fqdn = '' ) { } if ( $this->is_exist( $fqdn ) ) { - return new WP_Error( 'exists', __( 'The Domain is already Restricted.', 'dark-matter' ) ); + return new \WP_Error( 'exists', __( 'The Domain is already Restricted.', 'dark-matter' ) ); } /** @@ -100,8 +103,8 @@ public function add( $fqdn = '' ) { */ global $wpdb; - // phpcs:ignore - $result = $wpdb->insert( + // phpcs:ignore + $result = $wpdb->insert( $this->restrict_table, array( 'domain' => $fqdn, @@ -110,7 +113,7 @@ public function add( $fqdn = '' ) { ); if ( ! $result ) { - return new WP_Error( 'unknown', __( 'An unknown error has occurred. The domain has not been removed from the Restrict list.', 'dark-matter' ) ); + return new \WP_Error( 'unknown', __( 'An unknown error has occurred. The domain has not been removed from the Restrict list.', 'dark-matter' ) ); } $this->refresh_cache(); @@ -133,7 +136,7 @@ public function add( $fqdn = '' ) { * @since 2.0.0 * * @param string $fqdn Domain to be deleted to the restrict list. - * @return WP_Error|boolean True on success, WP_Error otherwise. + * @return \WP_Error|boolean True on success, WP_Error otherwise. */ public function delete( $fqdn = '' ) { $fqdn = $this->_basic_checks( $fqdn ); @@ -143,7 +146,7 @@ public function delete( $fqdn = '' ) { } if ( ! $this->is_exist( $fqdn ) ) { - return new WP_Error( 'missing', __( 'The Domain is not found in the Restrict list.', 'dark-matter' ) ); + return new \WP_Error( 'missing', __( 'The Domain is not found in the Restrict list.', 'dark-matter' ) ); } /** @@ -151,8 +154,8 @@ public function delete( $fqdn = '' ) { */ global $wpdb; - // phpcs:ignore - $result = $wpdb->delete( + // phpcs:ignore + $result = $wpdb->delete( $this->restrict_table, array( 'domain' => $fqdn, @@ -161,7 +164,7 @@ public function delete( $fqdn = '' ) { ); if ( ! $result ) { - return new WP_Error( 'unknown', __( 'An unknown error has occurred. The domain has not been removed from the Restrict list.', 'dark-matter' ) ); + return new \WP_Error( 'unknown', __( 'An unknown error has occurred. The domain has not been removed from the Restrict list.', 'dark-matter' ) ); } $this->refresh_cache(); @@ -211,8 +214,8 @@ public function get() { */ global $wpdb; - // phpcs:ignore - $restricted_domains = $wpdb->get_col( "SELECT domain FROM {$this->restrict_table} ORDER BY domain" ); + // phpcs:ignore + $restricted_domains = $wpdb->get_col( "SELECT domain FROM {$this->restrict_table} ORDER BY domain" ); if ( empty( $restricted_domains ) ) { $restricted_domains = array(); @@ -263,7 +266,7 @@ public function refresh_cache() { * * @since 2.0.0 * - * @return DarkMatter_Restrict + * @return Restricted */ public static function instance() { static $instance = false; diff --git a/domain-mapping/classes/class-dm-url.php b/includes/classes/DomainMapping/Processor/Mapping.php similarity index 77% rename from domain-mapping/classes/class-dm-url.php rename to includes/classes/DomainMapping/Processor/Mapping.php index 7d714fda..8f2c89b5 100644 --- a/domain-mapping/classes/class-dm-url.php +++ b/includes/classes/DomainMapping/Processor/Mapping.php @@ -1,19 +1,27 @@ is_request_mapped = ( defined( 'DOMAIN_MAPPING' ) && DOMAIN_MAPPING ); + public function register() { + self::$is_request_mapped = ( defined( 'DOMAIN_MAPPING' ) && DOMAIN_MAPPING ); /** * In some circumstances, we always want to process the logic regardless of request type, circumstances, * conditions, etc. (like ensuring saved post data is unmapped properly). */ - add_filter( 'http_request_host_is_external', array( $this, 'is_external' ), 10, 2 ); - add_filter( 'wp_insert_post_data', array( $this, 'insert_post' ), -10, 1 ); + add_filter( 'http_request_host_is_external', [ $this, 'is_external' ], 10, 2 ); + add_filter( 'wp_insert_post_data', [ $this, 'insert_post' ], -10, 1 ); /** * Ensure we do not map on the login and register pages. @@ -45,7 +53,7 @@ public function __construct() { 'wp-login.php' => true, 'wp-register.php' => true, ]; - $filename = $this->get_request_filename(); + $filename = Helper::instance()->get_request_filename(); if ( ! empty( $filename ) && array_key_exists( $filename, $admin_filenames ) ) { /** * Ensure the "Go to [site name]" and Privacy Policy links still go to the mapped domain. @@ -85,8 +93,7 @@ public function __construct() { * archived or deleted. */ $blog = get_site(); - - if ( (int) $blog->public < 0 || '0' !== $blog->archived || '0' !== $blog->deleted ) { + if ( ! Helper::instance()->is_public( $blog ) ) { return; } @@ -97,13 +104,13 @@ public function __construct() { * the unmapped and mapped domain - like REST API and XMLRPC - will not * be properly detected for the rewrite rules. */ - add_action( 'muplugins_loaded', array( $this, 'prepare' ), -10 ); + add_action( 'muplugins_loaded', [ $this, 'prepare' ], -10 ); /** * Jetpack compatibility. This filter ensures that Jetpack gets the * correct domain for the home URL. */ - add_action( 'jetpack_sync_home_url', array( $this, 'map' ), 10, 1 ); + add_action( 'jetpack_sync_home_url', [ $this, 'map' ], 10, 1 ); } /** @@ -131,10 +138,10 @@ public function adminurl( $url = '', $path = '', $blog_id = 0 ) { return $url; } - $valid_paths = array( + $valid_paths = [ 'admin-ajax.php' => true, 'admin-post.php' => true, - ); + ]; if ( array_key_exists( $filename, $valid_paths ) ) { return $this->map( $url, $blog_id ); @@ -143,22 +150,6 @@ public function adminurl( $url = '', $path = '', $blog_id = 0 ) { return $url; } - /** - * Get the filename, if it has one, from the current request. - * - * @return string - */ - public function get_request_filename() { - $request_uri = ( empty( $_SERVER['REQUEST_URI'] ) ? '' : wp_unslash( wp_strip_all_tags( $_SERVER['REQUEST_URI'] ) ) ); - $request = ltrim( $request_uri, '/' ); - - /** - * Get the filename and remove any query strings. - */ - $filename = basename( $request ); - return strtok( $filename, '?' ); - } - /** * Checks to ensure that "mapped" domains are considered internal to WordPress and not external. * @@ -181,7 +172,7 @@ public function is_external( $external = false, $host = '' ) { * Attempt to find the domain in Dark Matter. If the domain is found, then tell WordPress it is an internal * domain. */ - $db = DarkMatter_Domains::instance(); + $db = Domain::instance(); $domain = $db->find( $host ); if ( is_a( $domain, 'DM_Domain' ) ) { @@ -226,8 +217,8 @@ private function is_mapped() { * the context can be mapped (i.e. it has an active primary domain) and if so, we say the request is mapped. */ global $switched; - if ( $switched && $this->is_request_mapped ) { - $primary = DarkMatter_Primary::instance()->get(); + if ( $switched && self::$is_request_mapped ) { + $primary = Primary::instance()->get(); /** * If there is no primary or if it is inactive, then the site is not mapped. @@ -239,7 +230,7 @@ private function is_mapped() { return true; } - return $this->is_request_mapped; + return self::$is_request_mapped; } /** @@ -253,32 +244,7 @@ private function is_mapped() { * @return string If unmapped URL is found, then returns the primary URL. Untouched otherwise. */ public function map( $value = '', $blog_id = 0 ) { - /** - * Ensure that we are working with a string. - */ - if ( ! is_string( $value ) ) { - return $value; - } - - /** - * Retrieve the current blog. - */ - $blog = get_site( absint( $blog_id ) ); - $primary = DarkMatter_Primary::instance()->get( $blog->blog_id ); - - $unmapped = untrailingslashit( $blog->domain . $blog->path ); - - /** - * If there is no primary domain or the unmapped version cannot be found - * then we return the value as-is. - */ - if ( empty( $primary ) || false === stripos( $value, $unmapped ) ) { - return $value; - } - - $domain = 'http' . ( $primary->is_https ? 's' : '' ) . '://' . $primary->domain; - - return preg_replace( "#https?://{$unmapped}#", $domain, $value ); + return Helper::instance()->map( $value, $blog_id ); } /** @@ -301,14 +267,14 @@ public function prepare() { * manipulating `post_content`, usually on the "normal" priority (10). For domain mapping, we want to ensure we * catch every thing after WordPress core and any plugins, so we run later in the process to achieve that. */ - add_filter( 'the_content', array( $this, 'map' ), 5, 1 ); + add_filter( 'the_content', [ $this, 'map' ], 5, 1 ); /** * Please note: the `$this->map()` method will check for unmapped URLs before committing to an regex replace. So * most of the time, this will go "nothing to do here". And the rest of time, catch any edge cases that produce * unmapped URLs. */ - add_filter( 'the_content', array( $this, 'map' ), 50, 1 ); + add_filter( 'the_content', [ $this, 'map' ], 50, 1 ); /** * We only wish to affect `the_content` for Previews and nothing else. @@ -334,7 +300,7 @@ public function prepare() { * action is always called here and not just when the request is called (as in previous versions of Dark * Matter). */ - add_action( 'rest_api_init', array( $this, 'prepare_rest' ) ); + add_action( 'rest_api_init', [ $this, 'prepare_rest' ] ); /** * We have to stop here for the REST API as the later filters and hooks can cause the REST API endpoints to 404 @@ -345,7 +311,7 @@ public function prepare() { } if ( is_admin() ) { - add_action( 'init', array( $this, 'prepare_admin' ) ); + add_action( 'init', [ $this, 'prepare_admin' ] ); return; } @@ -353,16 +319,16 @@ public function prepare() { * Every thing here is designed to ensure all URLs throughout WordPress * is consistent. This is the public serving / theme powered code. */ - add_filter( 'admin_url', array( $this, 'adminurl' ), -10, 3 ); - add_filter( 'home_url', array( $this, 'siteurl' ), -10, 4 ); - add_filter( 'site_url', array( $this, 'siteurl' ), -10, 4 ); - add_filter( 'content_url', array( $this, 'map' ), -10, 1 ); - add_filter( 'get_shortlink', array( $this, 'map' ), -10, 4 ); + add_filter( 'admin_url', [ $this, 'adminurl' ], -10, 3 ); + add_filter( 'home_url', [ $this, 'siteurl' ], -10, 4 ); + add_filter( 'site_url', [ $this, 'siteurl' ], -10, 4 ); + add_filter( 'content_url', [ $this, 'map' ], -10, 1 ); + add_filter( 'get_shortlink', [ $this, 'map' ], -10, 4 ); - add_filter( 'script_loader_tag', array( $this, 'map' ), -10, 4 ); - add_filter( 'style_loader_tag', array( $this, 'map' ), -10, 4 ); + add_filter( 'script_loader_tag', [ $this, 'map' ], -10, 4 ); + add_filter( 'style_loader_tag', [ $this, 'map' ], -10, 4 ); - add_filter( 'upload_dir', array( $this, 'upload' ), 10, 1 ); + add_filter( 'upload_dir', [ $this, 'upload' ], 10, 1 ); } /** @@ -375,7 +341,7 @@ public function prepare() { * @return void */ public function prepare_admin() { - add_filter( 'home_url', array( $this, 'siteurl' ), -10, 4 ); + add_filter( 'home_url', [ $this, 'siteurl' ], -10, 4 ); /** * The Preview link in the metabox of Post Publish cannot be handled by the home_url hook. This is because it @@ -384,13 +350,13 @@ public function prepare_admin() { * @link https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/meta-boxes.php#L57 Preview Metabox call to get Preview URL. * @link https://github.com/WordPress/WordPress/blob/5.2.2/wp-includes/link-template.php#L1311-L1312 Query string parameter "preview=true" being added to the URL. */ - add_filter( 'preview_post_link', array( $this, 'unmap' ), 10, 1 ); + add_filter( 'preview_post_link', [ $this, 'unmap' ], 10, 1 ); /** * To prepare the Classic Editor, we need to attach to a very late hook to ensure that `get_current_screen()` is * available and returns something useful. */ - add_action( 'edit_form_top', array( $this, 'prepare_classic_editor' ) ); + add_action( 'edit_form_top', [ $this, 'prepare_classic_editor' ] ); } /** @@ -401,7 +367,7 @@ public function prepare_classic_editor() { $screen = get_current_screen(); if ( is_a( $screen, 'WP_Screen' ) && 'post' === $screen->base && 'edit' === $screen->parent_base ) { - add_filter( 'the_editor_content', array( $this, 'map' ), 10, 1 ); + add_filter( 'the_editor_content', [ $this, 'map' ], 10, 1 ); } } @@ -413,9 +379,9 @@ public function prepare_classic_editor() { * @return void */ public function prepare_rest() { - add_filter( 'home_url', array( $this, 'siteurl' ), -10, 4 ); + add_filter( 'home_url', [ $this, 'siteurl' ], -10, 4 ); - add_filter( 'preview_post_link', array( $this, 'unmap' ), 10, 1 ); + add_filter( 'preview_post_link', [ $this, 'unmap' ], 10, 1 ); /** * Loop all post types with REST endpoints to fix the mapping for content.raw property. @@ -423,7 +389,7 @@ public function prepare_rest() { $rest_post_types = get_post_types( [ 'show_in_rest' => true ] ); foreach ( $rest_post_types as $post_type ) { - add_filter( "rest_prepare_{$post_type}", array( $this, 'prepare_rest_post_item' ), 10, 1 ); + add_filter( "rest_prepare_{$post_type}", [ $this, 'prepare_rest_post_item' ], 10, 1 ); } } @@ -431,8 +397,8 @@ public function prepare_rest() { * Ensures the "raw" version of the content, typically used by Gutenberg through it's middleware pre-load / JS * hydrate process, gets handled the same as content (which runs through the `the_content` hook). * - * @param WP_REST_Response $item Individual post / item in the response that is being processed. - * @return WP_REST_Response Post / item with the content.raw, if present, mapped. + * @param \WP_REST_Response $item Individual post / item in the response that is being processed. + * @return \WP_REST_Response Post / item with the content.raw, if present, mapped. */ public function prepare_rest_post_item( $item = null ) { if ( isset( $item->data['content']['raw'] ) ) { @@ -463,10 +429,10 @@ public function siteurl( $url = '', $path = '', $scheme = null, $blog_id = 0 ) { return $url; } - $valid_schemes = array( + $valid_schemes = [ 'http' => true, 'https' => true, - ); + ]; if ( ! is_admin() ) { $valid_schemes['json'] = true; @@ -527,30 +493,7 @@ public function siteurl( $url = '', $path = '', $scheme = null, $blog_id = 0 ) { * @return mixed If unmapped URL is found, then returns the primary URL. Untouched otherwise. */ public function unmap( $value = '' ) { - /** - * Ensure that we are working with a string. - */ - if ( ! is_string( $value ) ) { - return $value; - } - - /** - * Retrieve the current blog. - */ - $blog = get_site(); - $primary = DarkMatter_Primary::instance()->get(); - - /** - * If there is no primary domain or the primary domain cannot be found - * then we return the value as-is. - */ - if ( empty( $primary ) || false === stripos( $value, $primary->domain ) ) { - return $value; - } - - $unmapped = 'http' . ( $primary->is_https ? 's' : '' ) . '://' . untrailingslashit( $blog->domain . $blog->path ); - - return preg_replace( "#https?://{$primary->domain}#", $unmapped, $value ); + return Helper::instance()->unmap( $value ); } /** @@ -572,22 +515,4 @@ public function upload( $uploads ) { return $uploads; } - - /** - * Return the Singleton Instance of the class. - * - * @since 2.0.0 - * - * @return DM_URL - */ - public static function instance() { - static $instance = false; - - if ( ! $instance ) { - $instance = new self(); - } - - return $instance; - } } -DM_URL::instance(); diff --git a/domain-mapping/classes/class-dm-media.php b/includes/classes/DomainMapping/Processor/Media.php similarity index 88% rename from domain-mapping/classes/class-dm-media.php rename to includes/classes/DomainMapping/Processor/Media.php index 706b9bc5..2ae652d4 100644 --- a/domain-mapping/classes/class-dm-media.php +++ b/includes/classes/DomainMapping/Processor/Media.php @@ -1,20 +1,25 @@ get( $site_id ); + $primary = Primary::instance()->get( $site_id ); if ( ! empty( $primary ) ) { $main_domains[] = $primary->domain; } @@ -295,10 +300,10 @@ public function prepare_rest() { /** * Loop all post types with REST endpoints to fix the mapping for content.raw property. */ - $rest_post_types = get_post_types( array( 'show_in_rest' => true ) ); + $rest_post_types = get_post_types( [ 'show_in_rest' => true ] ); foreach ( $rest_post_types as $post_type ) { - add_filter( "rest_prepare_{$post_type}", array( $this, 'prepare_rest_post_item' ), 10, 1 ); + add_filter( "rest_prepare_{$post_type}", [ $this, 'prepare_rest_post_item' ], 10, 1 ); } } @@ -306,8 +311,8 @@ public function prepare_rest() { * Ensures the "raw" version of the content, typically used by Gutenberg through it's middleware pre-load / JS * hydrate process, gets handled the same as content (which runs through the `the_content` hook). * - * @param WP_REST_Response $item Individual post / item in the response that is being processed. - * @return WP_REST_Response Post / item with the content.raw, if present, mapped. + * @param \WP_REST_Response $item Individual post / item in the response that is being processed. + * @return \WP_REST_Response Post / item with the content.raw, if present, mapped. * * @since 2.2.0 */ @@ -344,7 +349,7 @@ private function prime_site( $site_id = 0 ) { /** * Ensure we have media domains to use. */ - $media_domains = DarkMatter_Domains::instance()->get_domains_by_type( DM_DOMAIN_TYPE_MEDIA, $site_id ); + $media_domains = Domain::instance()->get_domains_by_type( DM_DOMAIN_TYPE_MEDIA, $site_id ); if ( empty( $media_domains ) ) { $this->sites[ $site_id ] = false; return; @@ -421,22 +426,4 @@ public function unmap( $value = '' ) { $value ); } - - /** - * Return the Singleton Instance of the class. - * - * @return DM_Media - * - * @since 2.2.0 - */ - public static function instance() { - static $instance = false; - - if ( ! $instance ) { - $instance = new self(); - } - - return $instance; - } } -DM_Media::instance(); diff --git a/includes/classes/DomainMapping/Processor/Redirect.php b/includes/classes/DomainMapping/Processor/Redirect.php new file mode 100644 index 00000000..3e4bd85f --- /dev/null +++ b/includes/classes/DomainMapping/Processor/Redirect.php @@ -0,0 +1,204 @@ + over the unmapped domain. + */ + ! empty( $_GET['customize_changeset_uuid'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended + || + /** + * Do not redirect Previews + */ + ( ! empty( $_GET['preview'] ) || ! empty( $_GET['page_id'] ) || ! empty( $_GET['p'] ) ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended + ); + } + + /** + * Check to see if the current request is an Admin Post action or an AJAX action. These two requests in Dark Matter + * can be on either the admin domain or the primary domain. + * + * @since 3.0.0 + * + * @param string $filename Filename. + * @return bool True if request is AJAX, false otherwise. + */ + private function is_ajax( $filename = '' ) { + $ajax_filenames = [ + 'admin-post.php' => true, + 'admin-ajax.php' => true, + ]; + + + if ( ! empty( $filename ) && array_key_exists( $filename, $ajax_filenames ) ) { + return true; + } + + return false; + } + + /** + * Performs various checks and, if required, performs the redirect. + * + * @since 3.0.0 + * + * @return void + */ + public function maybe_redirect() { + /** + * Do not perform redirects if it is the main site or the site is _not_ public. + * + * Note: this is here inside the caller on `muplugins_loaded` as earlier is before the function is available for + * use. + */ + $original_blog = get_site(); + if ( is_main_site() || ! Helper::instance()->is_public( $original_blog ) ) { + return; + } + + $filename = Helper::instance()->get_request_filename(); + if ( $this->is_ajax( $filename ) ) { + return; + } + + $is_admin = Helper::instance()->is_admin( $filename ); + $host = Helper::instance()->get_request_fqdn(); + + /** + * Check if logins are allowed on mapped domains, as we shouldn't redirect here if it is allowed. + */ + if ( ! apply_filters( 'darkmatter_allow_logins', false ) && $is_admin && $host === $original_blog->domain ) { + return; + } + + /** + * Check we have a primary domain that we can, maybe, redirect to. + */ + $primary = Primary::instance()->get(); + if ( ! $primary || ! $primary->active ) { + return; + } + + /** + * Get the request so we can use it to build up the redirect URL. + */ + $request_uri = ( empty( $_SERVER['REQUEST_URI'] ) ? '' : filter_var( $_SERVER['REQUEST_URI'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW ) ); + $request = ltrim( $request_uri, '/' ); + + /** + * Final set of checks. Make sure we redirect were appropriate here, both for the admin side/admin domain and + * the public side/primary domain. + */ + if ( $is_admin && $host !== $original_blog->domain ) { + $is_ssl_admin = ( defined( 'FORCE_SSL_ADMIN' ) && FORCE_SSL_ADMIN ); + + $url = 'http' . ( $is_ssl_admin ? 's' : '' ) . '://' . $original_blog->domain . $original_blog->path . $request; + } elseif ( $host !== $primary->domain || is_ssl() !== $primary->is_https ) { + $url = 'http' . ( $primary->is_https ? 's' : '' ) . '://' . $primary->domain . '/' . $request; + + /** + * Make sure the Path - if this is a sub-folder Network - is removed from the URL. For subdomain Networks, + * the path will be a single forward slash (/). + */ + if ( '/' !== $original_blog->path ) { + $path = '/' . trim( $original_blog->path, '/' ) . '/'; + $url = str_ireplace( $path, '/', $url ); + } + } + + /** + * If the URL is empty, then there is no redirect to perform. + */ + if ( empty( $url ) ) { + return; + } + + header( 'X-Redirect-By: Dark-Matter-Plugin' ); + header( 'Location:' . $url, true, 301 ); + + die; + } + + /** + * Register hooks for this class. + * + * @since 3.0.0 + * + * @return void + */ + public function register() { + if ( $this->can_redirect() ) { + /** + * We use `muplugins_loaded` action (introduced in WordPress 2.8.0) rather than the "ms_loaded" (introduced + * in WordPress 4.6.0). + * + * A hook on `muplugins_loaded` is used to ensure that WordPress has loaded the Blog/Site globals. This is + * specifically useful when someone goes to the Admin domain URL - http://my.sites.com/two/ - which is to + * redirect to the primary domain - http://example.com. + */ + add_action( 'muplugins_loaded', [ $this, 'maybe_redirect' ], 20 ); + } + } +} diff --git a/domain-mapping/rest/class-dm-rest-domains-controller.php b/includes/classes/DomainMapping/REST/Domains.php similarity index 70% rename from domain-mapping/rest/class-dm-rest-domains-controller.php rename to includes/classes/DomainMapping/REST/Domains.php index cdfcef5c..e3122385 100644 --- a/domain-mapping/rest/class-dm-rest-domains-controller.php +++ b/includes/classes/DomainMapping/REST/Domains.php @@ -1,17 +1,25 @@ prepare_item_for_database( $request ); @@ -62,7 +70,7 @@ public function create_item( $request ) { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. + * @param \WP_REST_Request $request Current request. * @return boolean True if the current user is a Super Admin. False otherwise. */ public function create_item_permissions_check( $request ) { @@ -75,11 +83,11 @@ public function create_item_permissions_check( $request ) { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. - * @return WP_REST_Response|mixed WP_REST_Response on success. WP_Error on failure. + * @param \WP_REST_Request $request Current request. + * @return \WP_REST_Response|mixed WP_REST_Response on success. WP_Error on failure. */ public function delete_item( $request ) { - $db = DarkMatter_Domains::instance(); + $db = Manager\Domain::instance(); $result = $db->delete( $request['domain'], $request['force'] ); @@ -109,7 +117,7 @@ public function delete_item( $request ) { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. + * @param \WP_REST_Request $request Current request. * @return boolean True if the current user is a Super Admin. False otherwise. */ public function delete_item_permissions_check( $request ) { @@ -122,11 +130,11 @@ public function delete_item_permissions_check( $request ) { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. - * @return WP_REST_Response|mixed WP_REST_Response on success. WP_Error on failure. + * @param \WP_REST_Request $request Current request. + * @return \WP_REST_Response|mixed WP_REST_Response on success. WP_Error on failure. */ public function get_item( $request ) { - $db = DarkMatter_Domains::instance(); + $db = Manager\Domain::instance(); $result = $db->get( $request['domain'] ); @@ -158,136 +166,136 @@ public function get_item_schema() { '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'Domain', 'type' => 'object', - 'properties' => array( - 'id' => array( - 'context' => array( 'view', 'edit' ), + 'properties' => [ + 'id' => [ + 'context' => [ 'view', 'edit' ], 'description' => __( 'Unique identifier for the object.', 'dark-matter' ), 'readonly' => true, 'type' => 'integer', - ), - 'domain' => array( - 'context' => array( 'view', 'edit' ), + ], + 'domain' => [ + 'context' => [ 'view', 'edit' ], 'default' => '', 'description' => __( 'Domain name.', 'dark-matter' ), 'required' => true, 'type' => 'string', - ), - 'is_primary' => array( - 'context' => array( 'view', 'edit' ), + ], + 'is_primary' => [ + 'context' => [ 'view', 'edit' ], 'default' => null, 'description' => __( 'Domain is the primary domain for the Site.', 'dark-matter' ), 'required' => false, 'type' => 'boolean', - ), - 'is_active' => array( - 'context' => array( 'view', 'edit' ), + ], + 'is_active' => [ + 'context' => [ 'view', 'edit' ], 'default' => null, 'description' => __( 'Domain is currently being used.', 'dark-matter' ), 'required' => false, 'type' => 'boolean', - ), - 'is_https' => array( - 'context' => array( 'view', 'edit' ), + ], + 'is_https' => [ + 'context' => [ 'view', 'edit' ], 'default' => null, 'description' => __( 'Domain is to be available on the HTTPS protocol.', 'dark-matter' ), 'required' => false, 'type' => 'boolean', - ), - 'type' => array( - 'context' => array( 'view', 'edit' ), + ], + 'type' => [ + 'context' => [ 'view', 'edit' ], 'default' => null, 'description' => __( 'Type of domain.', 'dark-matter' ), 'required' => false, 'type' => 'integer', - ), - 'site' => array( + ], + 'site' => [ 'description' => __( 'Site ID the domain is assigned against.', 'dark-matter' ), 'type' => 'object', - 'context' => array( 'view', 'edit' ), + 'context' => [ 'view', 'edit' ], 'readonly' => true, - 'properties' => array( - 'blog_id' => array( - 'context' => array( 'view', 'edit' ), + 'properties' => [ + 'blog_id' => [ + 'context' => [ 'view', 'edit' ], 'description' => __( 'Site ID.', 'dark-matter' ), 'readonly' => true, 'required' => false, 'type' => 'integer', - ), - 'site_id' => array( - 'context' => array( 'view', 'edit' ), + ], + 'site_id' => [ + 'context' => [ 'view', 'edit' ], 'description' => __( 'The ID of the site\'s parent network.', 'dark-matter' ), 'readonly' => true, 'required' => false, 'type' => 'integer', - ), - 'domain' => array( - 'context' => array( 'view', 'edit' ), + ], + 'domain' => [ + 'context' => [ 'view', 'edit' ], 'description' => __( 'Domain of the site.', 'dark-matter' ), 'readonly' => true, 'required' => false, 'type' => 'string', - ), - 'path' => array( - 'context' => array( 'view', 'edit' ), + ], + 'path' => [ + 'context' => [ 'view', 'edit' ], 'description' => __( 'Path of the site.', 'dark-matter' ), 'readonly' => true, 'required' => false, 'type' => 'string', - ), - 'registered' => array( - 'context' => array( 'view', 'edit' ), + ], + 'registered' => [ + 'context' => [ 'view', 'edit' ], 'description' => __( 'The date on which the site was created or registered.', 'dark-matter' ), 'format' => 'date-time', 'readonly' => true, 'required' => false, 'type' => 'string', - ), - 'last_updated' => array( - 'context' => array( 'view', 'edit' ), + ], + 'last_updated' => [ + 'context' => [ 'view', 'edit' ], 'description' => __( 'The date and time on which site settings were last updated.', 'dark-matter' ), 'format' => 'date-time', 'readonly' => true, 'required' => false, 'type' => 'string', - ), - 'public' => array( - 'context' => array( 'view', 'edit' ), + ], + 'public' => [ + 'context' => [ 'view', 'edit' ], 'description' => __( 'Whether the site should be treated as public.', 'dark-matter' ), 'readonly' => true, 'required' => false, 'type' => 'integer', - ), - 'archived' => array( - 'context' => array( 'view', 'edit' ), + ], + 'archived' => [ + 'context' => [ 'view', 'edit' ], 'description' => __( 'Whether the site should be treated as archived.', 'dark-matter' ), 'readonly' => true, 'required' => false, 'type' => 'boolean', - ), - 'mature' => array( - 'context' => array( 'view', 'edit' ), + ], + 'mature' => [ + 'context' => [ 'view', 'edit' ], 'description' => __( 'Whether the site should be treated as mature.', 'dark-matter' ), 'readonly' => true, 'required' => false, 'type' => 'boolean', - ), - 'spam' => array( - 'context' => array( 'view', 'edit' ), + ], + 'spam' => [ + 'context' => [ 'view', 'edit' ], 'description' => __( 'Whether the site should be treated as spam.', 'dark-matter' ), 'readonly' => true, 'required' => false, 'type' => 'boolean', - ), - 'deleted' => array( - 'context' => array( 'view', 'edit' ), + ], + 'deleted' => [ + 'context' => [ 'view', 'edit' ], 'description' => __( 'Whether the site should be treated as deleted.', 'dark-matter' ), 'readonly' => true, 'required' => false, 'type' => 'boolean', - ), - ), - ), - ), + ], + ], + ], + ], ); return $schema; @@ -298,8 +306,8 @@ public function get_item_schema() { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. - * @return WP_REST_Response|mixed WP_REST_Response on success. WP_Error on failure. + * @param \WP_REST_Request $request Current request. + * @return \WP_REST_Response|mixed WP_REST_Response on success. WP_Error on failure. */ public function get_items( $request ) { $site_id = null; @@ -316,9 +324,9 @@ public function get_items( $request ) { $site_id = get_current_blog_id(); } - $db = DarkMatter_Domains::instance(); + $db = Manager\Domain::instance(); - $response = array(); + $response = []; $result = $db->get_domains( $site_id ); @@ -345,7 +353,7 @@ public function get_items( $request ) { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. + * @param \WP_REST_Request $request Current request. * @return boolean True if the current user is a Super Admin. False otherwise. */ public function get_items_permissions_check( $request ) { @@ -358,17 +366,17 @@ public function get_items_permissions_check( $request ) { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. + * @param \WP_REST_Request $request Current request. * @return array Data provided by the call to the endpoint. */ protected function prepare_item_for_database( $request ) { - $item = array( + $item = [ 'domain' => '', 'is_primary' => null, 'is_https' => null, 'is_active' => null, 'type' => null, - ); + ]; $method = $request->get_method(); @@ -379,15 +387,15 @@ protected function prepare_item_for_database( $request ) { $value = $request[ $key ]; } - if ( WP_REST_Server::CREATABLE === $method && null === $value && 'is_primary' === $key ) { + if ( \WP_REST_Server::CREATABLE === $method && null === $value && 'is_primary' === $key ) { $value = false; } - if ( WP_REST_Server::CREATABLE === $method && null === $value && 'is_https' === $key ) { + if ( \WP_REST_Server::CREATABLE === $method && null === $value && 'is_https' === $key ) { $value = false; } - if ( WP_REST_Server::CREATABLE === $method && null === $value && 'is_active' === $key ) { + if ( \WP_REST_Server::CREATABLE === $method && null === $value && 'is_active' === $key ) { $value = true; } @@ -402,14 +410,14 @@ protected function prepare_item_for_database( $request ) { * * @since 2.0.0 * - * @param DM_Domain $item Domain object to be prepared for response. - * @param WP_REST_Request $request Current request. + * @param Data\Domain $item Domain object to be prepared for response. + * @param \WP_REST_Request $request Current request. * @return array Prepared item for REST response. */ public function prepare_item_for_response( $item, $request ) { $fields = $this->get_fields_for_response( $request ); - $data = array(); + $data = []; if ( in_array( 'id', $fields, true ) ) { $data['id'] = $item->id; @@ -479,81 +487,81 @@ public function register_routes() { register_rest_route( $this->namespace, $this->rest_base, - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - ) + [ + 'methods' => \WP_REST_Server::CREATABLE, + 'callback' => [ $this, 'create_item' ], + 'permission_callback' => [ $this, 'create_item_permissions_check' ], + 'args' => $this->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE ), + ] ); register_rest_route( $this->namespace, $this->rest_base . '/(?P.+)', - array( - 'args' => array( - 'domain' => array( + [ + 'args' => [ + 'domain' => [ 'description' => __( 'Site ID to retrieve a list of Domains.', 'dark-matter' ), 'required' => true, 'type' => 'string', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'schema' => array( $this, 'get_item_schema' ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( + ], + ], + [ + 'methods' => \WP_REST_Server::READABLE, + 'callback' => [ $this, 'get_item' ], + 'permission_callback' => [ $this, 'get_items_permissions_check' ], + 'schema' => [ $this, 'get_item_schema' ], + ], + [ + 'methods' => \WP_REST_Server::DELETABLE, + 'callback' => [ $this, 'delete_item' ], + 'permission_callback' => [ $this, 'delete_item_permissions_check' ], + 'args' => [ + 'force' => [ 'default' => false, 'description' => __( 'Force Dark Matter to remove the domain. This is required if you wish to remove a Primary domain from a Site.', 'dark-matter' ), 'type' => 'boolean', - ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - ), - ) + ], + ], + ], + [ + 'methods' => \WP_REST_Server::EDITABLE, + 'callback' => [ $this, 'update_item' ], + 'permission_callback' => [ $this, 'update_item_permissions_check' ], + 'args' => $this->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE ), + ], + ] ); register_rest_route( $this->namespace, $this->rest_base_plural, - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'schema' => array( $this, 'get_item_schema' ), - ) + [ + 'methods' => \WP_REST_Server::READABLE, + 'callback' => [ $this, 'get_items' ], + 'permission_callback' => [ $this, 'get_items_permissions_check' ], + 'schema' => [ $this, 'get_item_schema' ], + ] ); register_rest_route( $this->namespace, $this->rest_base_plural . '/(?P[\d]+)', - array( - 'args' => array( - 'site_id' => array( + [ + 'args' => [ + 'site_id' => [ 'description' => __( 'Site ID to retrieve a list of Domains.', 'dark-matter' ), 'required' => true, 'type' => 'integer', - ), - ), - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'schema' => array( $this, 'get_item_schema' ), - ), - ) + ], + ], + [ + 'methods' => \WP_REST_Server::READABLE, + 'callback' => [ $this, 'get_items' ], + 'permission_callback' => [ $this, 'get_items_permissions_check' ], + 'schema' => [ $this, 'get_item_schema' ], + ], + ] ); } @@ -562,11 +570,11 @@ public function register_routes() { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. - * @return WP_REST_Response|mixed WP_REST_Response on success. WP_Error on failure. + * @param \WP_REST_Request $request Current request. + * @return \WP_REST_Response|mixed WP_REST_Response on success. WP_Error on failure. */ public function update_item( $request ) { - $db = DarkMatter_Domains::instance(); + $db = Manager\Domain::instance(); $item = $this->prepare_item_for_database( $request ); @@ -601,7 +609,7 @@ public function update_item( $request ) { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. + * @param \WP_REST_Request $request Current request. * @return boolean True if the current user is a Super Admin. False otherwise. */ public function update_item_permissions_check( $request ) { @@ -609,16 +617,3 @@ public function update_item_permissions_check( $request ) { return current_user_can( apply_filters( 'dark_matter_domain_permission', 'upgrade_network', 'rest-update' ) ); } } - -/** - * Setup the REST Controller for Domains for use. - * - * @since 2.0.0 - * - * @return void - */ -function dark_matter_domains_rest() { - $controller = new DM_REST_Domains_Controller(); - $controller->register_routes(); -} -add_action( 'rest_api_init', 'dark_matter_domains_rest' ); diff --git a/domain-mapping/rest/class-dm-rest-restricted-controller.php b/includes/classes/DomainMapping/REST/Restricted.php similarity index 66% rename from domain-mapping/rest/class-dm-rest-restricted-controller.php rename to includes/classes/DomainMapping/REST/Restricted.php index 6d53e812..0d94ed1b 100644 --- a/domain-mapping/rest/class-dm-rest-restricted-controller.php +++ b/includes/classes/DomainMapping/REST/Restricted.php @@ -1,17 +1,24 @@ $domain, - ) + ] ); $response->set_status( '201' ); @@ -61,7 +68,7 @@ public function create_item( $request ) { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. + * @param \WP_REST_Request $request Current request. * @return boolean True if the current user is a Super Admin. False otherwise. */ public function create_item_permissions_check( $request ) { @@ -81,11 +88,11 @@ public function create_item_permissions_check( $request ) { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. - * @return WP_REST_Response|mixed WP_REST_Response on success. WP_Error on failure. + * @param \WP_REST_Request $request Current request. + * @return \WP_REST_Response|mixed WP_REST_Response on success. WP_Error on failure. */ public function delete_item( $request ) { - $db = DarkMatter_Restrict::instance(); + $db = Manager\Restricted::instance(); $domain = ( isset( $request['domain'] ) ? $request['domain'] : '' ); @@ -100,10 +107,10 @@ public function delete_item( $request ) { } return rest_ensure_response( - array( + [ 'deleted' => true, 'domain' => $domain, - ) + ] ); } @@ -112,7 +119,7 @@ public function delete_item( $request ) { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. + * @param \WP_REST_Request $request Current request. * @return boolean True if the current user is a Super Admin. False otherwise. */ public function delete_item_permissions_check( $request ) { @@ -125,11 +132,11 @@ public function delete_item_permissions_check( $request ) { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. - * @return WP_REST_Response|mixed WP_REST_Response on success. WP_Error on failure. + * @param \WP_REST_Request $request Current request. + * @return \WP_REST_Response|mixed WP_REST_Response on success. WP_Error on failure. */ public function get_items( $request ) { - $db = DarkMatter_Restrict::instance(); + $db = Manager\Restricted::instance(); return rest_ensure_response( $db->get() ); } @@ -140,7 +147,7 @@ public function get_items( $request ) { * * @since 2.0.0 * - * @param WP_REST_Request $request Current request. + * @param \WP_REST_Request $request Current request. * @return boolean True if the current user is a Super Admin. False otherwise. */ public function get_items_permissions_check( $request ) { @@ -160,9 +167,9 @@ public function register_routes() { $this->namespace, $this->rest_base, [ - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), + 'methods' => \WP_REST_Server::CREATABLE, + 'callback' => [ $this, 'create_item' ], + 'permission_callback' => [ $this, 'create_item_permissions_check' ], ] ); @@ -170,9 +177,9 @@ public function register_routes() { $this->namespace, $this->rest_base, [ - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), + 'methods' => \WP_REST_Server::DELETABLE, + 'callback' => [ $this, 'delete_item' ], + 'permission_callback' => [ $this, 'delete_item_permissions_check' ], ] ); @@ -180,23 +187,10 @@ public function register_routes() { $this->namespace, $this->rest_base, [ - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), + 'methods' => \WP_REST_Server::READABLE, + 'callback' => [ $this, 'get_items' ], + 'permission_callback' => [ $this, 'get_items_permissions_check' ], ] ); } } - -/** - * Setup the REST Controller for Domains for use. - * - * @since 2.0.0 - * - * @return void - */ -function dark_matter_restricted_rest() { - $controller = new DM_REST_Restricted_Controller(); - $controller->register_routes(); -} -add_action( 'rest_api_init', 'dark_matter_restricted_rest' ); diff --git a/includes/classes/DomainMapping/Sunrise.php b/includes/classes/DomainMapping/Sunrise.php new file mode 100644 index 00000000..41876ee1 --- /dev/null +++ b/includes/classes/DomainMapping/Sunrise.php @@ -0,0 +1,143 @@ +init(); + + /** + * Find the domain based on the request. + */ + $domain = $this->get_domain(); + if ( $domain && $domain->active && $this->set_globals( $domain ) && $domain->is_primary ) { + $this->update_globals( $domain ); + } + + /** + * Hook up the redirect logic. + */ + $redirect = new Redirect(); + $redirect->register(); + } + + /** + * Get the domain from the requested FQDN. + * + * @since 3.0.0 + * + * @return bool|Data\Domain + */ + private function get_domain() { + $fqdn = Helper::instance()->get_request_fqdn(); + return Manager\Domain::instance()->get( $fqdn ); + } + + /** + * Set up various globals and constants which are used, either by Dark Matter itself or by other plugins and/or + * WordPress Core. + * + * @since 3.0.0 + * + * @return void + */ + private function init() { + /** + * Ensure `dark-matter` cache group is available globally. + */ + wp_cache_add_global_groups( 'dark-matter' ); + + /** + * Define the `SUNRISE_LOADED`. Dark Matter Plugin does not make use of this but other plugins do in certain + * circumstances (i.e. Jetpack). So we define it for compatibility. + */ + if ( false === defined( 'SUNRISE_LOADED' ) ) { + define( 'SUNRISE_LOADED', true ); + } + + /** + * Use to detect misconfiguration where the cookie domain is set. + */ + define( 'DARKMATTER_COOKIE_SET', ! defined( 'COOKIE_DOMAIN' ) ); + } + + /** + * Sets up a few global variables which are used through WordPress Core. Will do some basic detection to ensure the + * website should be served on the mapped domain. + * + * @since 3.0.0 + * + * @param Data\Domain $domain Domain data. + * @return bool True to proceed, false to disengage. + */ + private function set_globals( $domain ) { + global $blog_id, $current_blog, $current_site, $site_id; + + /** + * Set the current Blog (WP_Site) and current Site (WP_Network). + */ + $current_blog = get_site( $domain->blog_id ); + $blog_id = $current_blog->blog_id; + $current_site = \WP_Network::get_instance( $current_blog->site_id ); + $site_id = $current_blog->site_id; + + return Helper::instance()->is_public( $current_blog ); + } + + /** + * Prepare WordPress globals to use the primary domain data instead. + * + * @since 3.0.0 + * + * @param Data\Domain $primary Primary Domain data. + * @return void + */ + private function update_globals( $primary ) { + /** + * Store the current WP_Site object in another global, so it is available for comparison and reference. + */ + global $current_blog, $original_blog; + $original_blog = clone $current_blog; + + /** + * Update the domain and path to match the primary. + */ + $current_blog->domain = $primary->domain; + $current_blog->path = '/'; + + /** + * Update the cookie domain to be the primary domain. + */ + if ( ! defined( 'COOKIE_DOMAIN' ) ) { + define( 'COOKIE_DOMAIN', $primary->domain ); + } + + /** + * Set the constant to state the current request has been mapped. + */ + define( 'DOMAIN_MAPPING', true ); + } +} diff --git a/domain-mapping/classes/third-party/class-dm-yoast.php b/includes/classes/DomainMapping/Support/Yoast.php similarity index 69% rename from domain-mapping/classes/third-party/class-dm-yoast.php rename to includes/classes/DomainMapping/Support/Yoast.php index a6acdf21..e5a0bca4 100644 --- a/domain-mapping/classes/third-party/class-dm-yoast.php +++ b/includes/classes/DomainMapping/Support/Yoast.php @@ -2,32 +2,32 @@ /** * Compatibility adjustments for supporting Yoast SEO. * - * @package DarkMatter + * @since 2.1.3 + * + * @package DarkMatterPlugin\DomainMapping */ +namespace DarkMatter\DomainMapping\Support; + +use DarkMatter\DomainMapping\Helper; +use DarkMatter\Interfaces\Registerable; + /** - * Class DM_Yoast + * Class Yoast + * + * Previously called `DM_Yoast`. * * @since 2.1.3 */ -class DM_Yoast { - /** - * DM_Yoast constructor. - */ - public function __construct() { - if ( defined( 'WPSEO_VERSION' ) ) { - return; - } - - add_filter( 'wpseo_should_save_indexable', [ $this, 'fix_indexable_permalinks' ], 10, 2 ); - } - +class Yoast implements Registerable { /** * Correct indexables permalinks to be unmapped prior to save to the database. This works with versions 15.1+ of * Yoast SEO. Version 15.1 - which contains the `wpseo_should_save_indexable` was released on 14th October 2020. * * @link https://github.com/Yoast/wordpress-seo/blob/15.1/src/builders/indexable-builder.php#L296 * + * @since 2.1.3 + * * @param boolean $intend_to_save Whether the indexable is to be saved or not. * @param \Yoast\WP\SEO\Models\Indexable $indexable The indexable to be saved. * @return boolean The default value of "intend to save". @@ -37,15 +37,18 @@ public function fix_indexable_permalinks( $intend_to_save, $indexable ) { * If saving to the database, then make sure the permalink is unmapped. */ if ( $intend_to_save ) { - $dm_url = DM_URL::instance(); - $indexable->permalink = $dm_url->unmap( $indexable->permalink ); + $indexable->permalink = Helper::instance()->unmap( $indexable->permalink ); } return $intend_to_save; } -} -/** - * Only instantiate this class if Yoast SEO is in use. - */ -new DM_Yoast(); + /** + * Register hooks for this class. + * + * @return void + */ + public function register() { + add_filter( 'wpseo_should_save_indexable', [ $this, 'fix_indexable_permalinks' ], 10, 2 ); + } +} diff --git a/includes/classes/Interfaces/Registerable.php b/includes/classes/Interfaces/Registerable.php new file mode 100644 index 00000000..21bb137e --- /dev/null +++ b/includes/classes/Interfaces/Registerable.php @@ -0,0 +1,22 @@ +add_node( + [ + 'id' => 'dark-matter-plugin-signin', + 'href' => $check_url, + 'parent' => 'site-name', + 'title' => __( 'Log into Site', 'dark-matter-plugin' ), + ] + ); + + return $admin_bar; + } + + /** + * Handle actions and filters for the SSO admin. + * + * @return void + */ + public function register() { + add_action( 'admin_bar_menu', [ $this, 'admin_bar' ], 40 ); + } +} diff --git a/includes/classes/SSO/Authenticate.php b/includes/classes/SSO/Authenticate.php new file mode 100644 index 00000000..c8169bf7 --- /dev/null +++ b/includes/classes/SSO/Authenticate.php @@ -0,0 +1,208 @@ +token_api = new Token( 'dmp_login_token', 'dark-matter-plugin-logintoken' ); + } + + /** + * Retrieve the URL data. + * + * @return array|false|null + */ + private function get_data() { + return filter_var_array( + $_GET, + [ + 'action' => [ + 'filter' => FILTER_CALLBACK, + 'options' => 'sanitize_text_field', + ], + 'nonce' => [ + 'filter' => FILTER_CALLBACK, + 'options' => 'sanitize_text_field', + ], + 'token' => [ + 'filter' => FILTER_CALLBACK, + 'options' => 'sanitize_text_field', + ], + 'key' => [ + 'filter' => FILTER_CALLBACK, + 'options' => 'sanitize_key', + ], + ] + ); + } + + /** + * Prepare a redirect to the mapped domain which can be used for authentication and log on. + * + * @param string $token_id Token ID. + * @param array $token_data Data from the Token that completed the authorisation. + * @return void + */ + public function prepare( $token_id, $token_data ) { + if ( ! is_user_logged_in() ) { + return; + } + + $user_id = get_current_user_id(); + $nonce = wp_create_nonce( sprintf( 'dmp_login_check_%s', $user_id ) ); + + /** + * Generate a random key. + */ + $key = wp_hash( $user_id . wp_rand() . microtime(), 'dmp_authenticate' ); + + $data = [ + 'key' => $key, + 'nonce' => $nonce, + 'user_id' => $user_id, + ]; + + /** + * Hashed the key and store it. This will be used to cross-reference later. + */ + $hashed_key = wp_hash( wp_json_encode( $data ), 'dmp_authenticate' ); + $data['key'] = $hashed_key; + + /** + * Now add the session token. As this data is a bit more sensitive, we only want to store this in the within the + * Cache API/Token logic but not include it in the one-way hash for the URL. + */ + $data['session_token'] = wp_get_session_token(); + + // Create a new token with User ID in the data. + $token_id = $this->token_api->create( $user_id, '', $data ); + + $url = add_query_arg( + [ + 'action' => 'dmp_auth_do', + 'token' => $token_id, + 'nonce' => $nonce, + 'key' => $key, + 't' => time(), // Cache buster + ], + home_url( '/' ) + ); + + // Redirect to the mapped domain to log them in. + wp_safe_redirect( $url, 302, 'DarkMatterPlugin' ); + die; + } + + /** + * Handle actions and filters for SSO Authenticate. + * + * @return void + */ + public function register() { + add_action( 'darkmatterplugin.sso.authorised', [ $this, 'prepare' ], 10, 2 ); + + // Add action to log in the user. + add_action( 'template_redirect', [ $this, 'signin' ] ); // TODO: Should probably be a custom action from DMP when a mapped request has been determined. + } + + /** + * Perform sign-in request. + * + * @return void + */ + public function signin() { + $data = $this->get_data(); + + if ( 'dmp_auth_do' !== $data['action'] ) { + return; + } + + /** + * Check to see if the token exists. + */ + $token_data = $this->token_api->get( $data['token'], 'token' ); + if ( empty( $token_data['nonce'] ) && empty( $token_data['user_id'] ) ) { + return; + } + + /** + * Check the nonce matches. + */ + if ( $data['nonce'] !== $token_data['nonce'] ) { + return; + } + + /** + * Check the key hash and make sure it is valid. + */ + $unverified_key = wp_hash( + wp_json_encode( + [ + 'key' => $data['key'], + 'nonce' => $data['nonce'], + 'user_id' => $token_data['user_id'], + ] + ), + 'dmp_authenticate' + ); + + $hashes_match = $unverified_key && hash_equals( $token_data['key'], $unverified_key ); + if ( ! $hashes_match ) { + return; + } + + wp_set_auth_cookie( $token_data['user_id'], false, '', $token_data['session_token'] ); + wp_set_current_user( $token_data['user_id'] ); + + /** + * `wp_verify_nonce()` works with `$_COOKIE` to retrieve the auth cookies and despite being set above, the auth + * cookies are not available in this manner. This means the retrieving the current WP User and get the session + * token does not work, meaning the nonce always fails. + * + * The below allows us to perform the check with the need for `$_COOKIE` being updated. + */ + $verify_nonce = verify_nonce( + $token_data['nonce'], + sprintf( 'dmp_login_check_%s', $token_data['user_id'] ), + $token_data['user_id'], + $token_data['session_token'] + ); + + /** + * With the person signed in, perform an actual verification on the nonce. If it fails, then immediately clear + * the auth cookies. + */ + if ( ! $verify_nonce ) { + /** + * Sadly the `wp_verify_nonce()` does not provide a way to supply the relevant data without the auth cookies + * being set. However, this weird "create" and "destroy" immediately approach to cookies. + */ + wp_clear_auth_cookie(); + return; + } + + wp_safe_redirect( home_url( '/' ), 302, 'DarkMatterPlugin' ); + die; + } +} diff --git a/includes/classes/SSO/Authorise.php b/includes/classes/SSO/Authorise.php new file mode 100644 index 00000000..dbc8fc51 --- /dev/null +++ b/includes/classes/SSO/Authorise.php @@ -0,0 +1,266 @@ +token_api = new Token( 'dmp_auth_token', 'dark-matter-plugin-authtokens', true ); + } + + /** + * Ensure the admin request is valid. + * + * @return bool True to proceed. False otherwise. + */ + private function is_valid_admin() { + /** + * If they are not logged in, then we ignore it. + */ + if ( ! is_user_logged_in() ) { + return false; + } + + /** + * Make sure we are an admin request and that it is + */ + if ( wp_doing_ajax() || ! is_admin() ) { + return false; + } + + return true; + } + + /** + * Helper method to get the check URL for logging in a person to the primary domain. + * + * @return string + */ + public static function get_check_url() { + $user_id = get_current_user_id(); + $token_api = new Token( 'dmp_auth_token', 'dark-matter-plugin-authtokens', true ); + + $token_id = $token_api->get( $user_id ); + if ( empty( $token_id ) ) { + return ''; + } + + $token_data = $token_api->get( $token_id, 'token' ); + if ( empty( $token_data['nonce'] ) && empty( $token_data['user_id'] ) ) { + return ''; + } + + return add_query_arg( + [ + 'action' => 'dmp_auth_check', + 'token' => $token_id, + 'nonce' => $token_data['nonce'], + ], + home_url( '/' ) + ); + } + + /** + * Get the URL data. + * + * @return void + */ + private function get_data() { + $this->data = filter_var_array( + $_GET, + [ + 'action' => [ + 'filter' => FILTER_CALLBACK, + 'options' => 'sanitize_text_field', + ], + 'nonce' => [ + 'filter' => FILTER_CALLBACK, + 'options' => 'sanitize_text_field', + ], + 'token' => [ + 'filter' => FILTER_CALLBACK, + 'options' => 'sanitize_text_field', + ], + ] + ); + } + + /** + * Handle the authorise request. + * + * @return void + */ + public function handle() { + if ( is_user_logged_in() ) { + return; + } + + /** + * Check to see if the token exists. + */ + $token_data = $this->token_api->get( $this->data['token'], 'token' ); + if ( empty( $token_data['nonce'] ) && empty( $token_data['user_id'] ) ) { + return; + } + + /** + * Check the nonce matches. + */ + if ( $this->data['nonce'] !== $token_data['nonce'] ) { + return; + } + + $url = admin_url(); + $url = add_query_arg( + [ + 'action' => 'dmp_auth_verify', + 'token' => $this->data['token'], + 'nonce' => $this->data['nonce'], + ], + $url + ); + + wp_safe_redirect( $url, 302, 'Dark-Matter-Plugin' ); + die; + } + + /** + * Initiate the Authorise process by creating a token. + * + * @return void + */ + public function initiate() { + if ( ! $this->is_valid_admin() ) { + return; + } + + $user_id = get_current_user_id(); + + /** + * Check to see if a Token already exists. + */ + $token = $this->token_api->get( $user_id ); + if ( ! empty( $token ) ) { + return; + } + + $data = [ + 'user_id' => $user_id, + 'nonce' => wp_create_nonce( sprintf( 'dmp_auth_check_%s', $user_id ) ), + ]; + + $this->token_api->create( $user_id, '', $data ); + } + + /** + * Handle actions and filters for this SSO Authorise. + * + * @return void + */ + public function register() { + if ( wp_doing_ajax() ) { + return; + } + + $this->get_data(); + + if ( empty( $this->data['action'] ) ) { + add_action( 'init', [ $this, 'initiate' ], 11 ); + } + + /** + * Check if the current request has data and has the action. + */ + if ( ! empty( $this->data ) && 'dmp_auth_check' === $this->data['action'] ) { + add_action( 'template_redirect', [ $this, 'handle' ] ); // TODO: Should probably be a custom action from DMP when a mapped request has been determined. + } + + /** + * Verification must only occur on the admin domain (unmapped). + */ + if ( + ! empty( $this->data ) + && ( is_admin() ) + && 'dmp_auth_verify' === $this->data['action'] ) { + add_action( 'init', [ $this, 'verify' ], 11 ); + } + } + + /** + * Verify a request provided by the handle method. + * + * @return void + */ + public function verify() { + if ( ! $this->is_valid_admin() ) { + return; + } + + $user_id = get_current_user_id(); + + $token_id = $this->token_api->get( $user_id ); + if ( empty( $token_id ) || $this->data['token'] !== $token_id ) { + return; + } + + $token_data = $this->token_api->get( $token_id, 'token' ); + if ( empty( $token_data ) ) { + return; + } + + /** + * Make sure the Token we are verifying is for the same user as us. + */ + if ( $token_data['user_id'] !== $user_id ) { + return; + } + + /** + * Verify the nonce properly now. + * + * As this is processed on the admin domain, the person's session is up and running, which will mean the nonce + * verify is meaningful. + */ + if ( ! wp_verify_nonce( $token_data['nonce'], sprintf( 'dmp_auth_check_%s', $user_id ) ) ) { + return; + } + + $this->token_api->delete( $user_id, $token_id ); + + /** + * Action that is fired when the SSO is authorised with a crafted URL from the front-end. + * + * @since 3.0.0 + * + * @param string $token_id Token ID. + * @param array $token_data Data from the Token that completed the authorisation. + */ + do_action( 'darkmatterplugin.sso.authorised', $token_id, $token_data ); + } +} diff --git a/includes/classes/SSO/Token.php b/includes/classes/SSO/Token.php new file mode 100644 index 00000000..a5a798da --- /dev/null +++ b/includes/classes/SSO/Token.php @@ -0,0 +1,139 @@ +prefix = $prefix ?? 'dmp_token_'; + + if ( ! empty( $cache_group ) ) { + $this->cache_group = $cache_group; + } + + if ( $cache_global ) { + wp_cache_add_global_groups( $this->cache_group ); + } + } + + /** + * Create a token. + * + * @param int $user_id User ID. + * @param string $token_id Token ID. If blank, will auto-generate. + * @param array $data Array of data to store with the token. + * @return false|string Token ID on success. False otherwise. + */ + public function create( $user_id, $token_id = '', $data = [] ) { + if ( ! is_integer( $user_id ) ) { + return false; + } + + /** + * No Token ID, then generate one. + */ + if ( empty( $token_id ) ) { + $token_id = wp_generate_password( 20, false ); + } + + /** + * Create an entry so that Token can be found by looking up a WP User ID. + */ + wp_cache_set( sprintf( '%1$sfor_%2$s', $this->prefix, $user_id ), $token_id, $this->cache_group, HOUR_IN_SECONDS ); + + /** + * Create the actual token entry with the appropriate data. + */ + wp_cache_set( sprintf( '%1$s%2$s', $this->prefix, $token_id ), $data, $this->cache_group, HOUR_IN_SECONDS ); + + return $token_id; + } + + /** + * Delete a token. + * + * @param int $user_id User ID. + * @param string $token_id Token ID. + * @return bool True on success. False otherwise. + */ + public function delete( $user_id, $token_id ) { + if ( is_integer( $user_id ) && ! empty( $token_id ) ) { + wp_cache_delete( sprintf( '%1$sfor_%2$s', $this->prefix, $user_id ), $this->cache_group ); + wp_cache_delete( sprintf( '%1$s%2$s', $this->prefix, $token_id ), $this->cache_group ); + + return true; + } + + return false; + } + + /** + * Retrieve a token by Token ID or User ID. + * + * @param string $id ID to retrieve token. + * @param string $type ID type; "token" or "user". + * @return false|string|array Data from the Token, either as an array or string. Can return false if cache entry has + * been deleted. + */ + public function get( $id, $type = 'user' ) { + $prefix = [ + 'token' => $this->prefix, + 'user' => sprintf( '%1$sfor_', $this->prefix ), + ]; + + if ( ! array_key_exists( $type, $prefix ) ) { + return []; + } + + $key = sprintf( '%1$s%2$s', $prefix[ $type ], $id ); + + return wp_cache_get( $key, $this->cache_group ); + } + + /** + * Update a token. + * + * Note: this will extend the length of time the token will remain. + * + * @param int $token_id Token ID. + * @param array $data Data. + * @return bool True on success. False otherwise. + */ + public function set( $token_id, $data = [] ) { + if ( empty( $token_id ) ) { + return false; + } + + wp_cache_set( sprintf( '%1$s%2$s', $this->prefix, $token_id ), $data, $this->cache_group, HOUR_IN_SECONDS ); + + return true; + } +} diff --git a/includes/classes/UI/AbstractAdminPage.php b/includes/classes/UI/AbstractAdminPage.php new file mode 100644 index 00000000..7e46988f --- /dev/null +++ b/includes/classes/UI/AbstractAdminPage.php @@ -0,0 +1,125 @@ +parent_slug, + $this->page_title, + $this->menu_title, + $this->permission, + $this->slug, + [ $this, 'page' ] + ); + + add_action( 'load-' . $hook_suffix, [ $this, 'enqueue' ] ); + } + + /** + * Used for enqueuing custom scripts and styles. + * + * @since 3.0.0 + * + * @return void + */ + abstract public function enqueue(); + + /** + * Handle the rendering of the page. + * + * @return void + */ + public function page() { + if ( ! current_user_can( $this->permission ) ) { + wp_die( esc_html__( 'You do not have permission to manage domains.', 'dark-matter' ) ); + } + + $this->render(); + } + + /** + * Produce the HTML output of the admin page. + * + * @since 3.0.0 + * + * @return void + */ + abstract public function render(); + + /** + * Register hooks for this class. + * + * @since 3.0.0 + * + * @return void + */ + public function register() { + add_action( 'admin_menu', [ $this, 'admin_menu' ] ); + } +} diff --git a/domain-mapping/sunrise.php b/includes/dropins/sunrise.php similarity index 64% rename from domain-mapping/sunrise.php rename to includes/dropins/sunrise.php index 64cefb5b..fb478f46 100644 --- a/domain-mapping/sunrise.php +++ b/includes/dropins/sunrise.php @@ -14,8 +14,13 @@ * @package DarkMatter */ -$sunrise_path = ( dirname( __FILE__ ) . '/plugins/dark-matter/domain-mapping/inc/sunrise.php' ); +$dirname = ( dirname( __FILE__ ) . '/plugins/dark-matter/' ); -if ( is_readable( $sunrise_path ) ) { - require_once $sunrise_path; +/** + * Include the PSR-4 autoloader. + */ +if ( file_exists( $dirname . 'vendor/autoload.php' ) ) { + require_once $dirname . 'vendor/autoload.php'; } + +new \DarkMatter\DomainMapping\Sunrise(); diff --git a/includes/utility/functions.php b/includes/utility/functions.php new file mode 100644 index 00000000..f90f36c8 --- /dev/null +++ b/includes/utility/functions.php @@ -0,0 +1,56 @@ +add( $domain ); + \DarkMatter\DomainMapping\Manager\Domain::instance()->add( $domain ); global $wpdb; $data = $wpdb->get_row( @@ -71,12 +71,12 @@ public function test_add_add_again() { /** * Add the domain. */ - DarkMatter_Domains::instance()->add( $domain ); + \DarkMatter\DomainMapping\Manager\Domain::instance()->add( $domain ); /** * Attempt to add the domain again. */ - $error = DarkMatter_Domains::instance()->add( $domain ); + $error = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( $domain ); $this->assertWPError( $error ); $this->assertSame( $error->get_error_code(), 'exists' ); @@ -93,12 +93,12 @@ public function test_delete_domain() { /** * Add the domain. */ - DarkMatter_Domains::instance()->add( $domain ); + \DarkMatter\DomainMapping\Manager\Domain::instance()->add( $domain ); /** * Attempt to add the domain again. */ - $return = DarkMatter_Domains::instance()->delete( $domain ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->delete( $domain ); $this->assertTrue( $return ); @@ -125,12 +125,12 @@ public function test_find_domain() { /** * Add the domain. */ - DarkMatter_Domains::instance()->add( $domain ); + \DarkMatter\DomainMapping\Manager\Domain::instance()->add( $domain ); /** * Attempt to add the domain again. */ - $return = DarkMatter_Domains::instance()->find( $domain ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->find( $domain ); $this->assertNotFalse( $return ); $this->assertEquals( $return->domain, $domain ); @@ -147,12 +147,12 @@ public function test_update_domain() { /** * Add the domain. */ - DarkMatter_Domains::instance()->add( $domain ); + \DarkMatter\DomainMapping\Manager\Domain::instance()->add( $domain ); /** * Make sure the update did not return a WP_Error. */ - $return = DarkMatter_Domains::instance()->update( $domain, true, true ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->update( $domain, true, true ); $this->assertNotWPError( $return ); /** @@ -178,12 +178,12 @@ public function test_update_domain() { */ public function test_validation_international_domains() { /** Chinese - Unicode - Invalid */ - $return = DarkMatter_Domains::instance()->add( 'www.例如.中国' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( 'www.例如.中国' ); $this->assertWPError( $return, 'Chinese - Unicode - Invalid' ); $this->assertSame( $return->get_error_code(), 'domain' ); /** Chinese - ASCII - Valid */ - $return = DarkMatter_Domains::instance()->add( 'www.xn--fsqu6v.xn--fiqs8s' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( 'www.xn--fsqu6v.xn--fiqs8s' ); $this->assertNotWPError( $return, 'Chinese - ASCII - Valid' ); } @@ -194,37 +194,37 @@ public function test_validation_international_domains() { */ public function test_validation_invalid_domains() { /** Empty */ - $return = DarkMatter_Domains::instance()->add( '' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( '' ); $this->assertWPError( $return ); $this->assertSame( $return->get_error_code(), 'empty' ); /** URI */ - $return = DarkMatter_Domains::instance()->add( 'http://example.com/' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( 'http://example.com/' ); $this->assertWPError( $return ); $this->assertSame( $return->get_error_code(), 'unsure' ); /** Domain + Path */ - $return = DarkMatter_Domains::instance()->add( 'example.com/hello-world' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( 'example.com/hello-world' ); $this->assertWPError( $return ); $this->assertSame( $return->get_error_code(), 'unsure' ); /** Domain + Port */ - $return = DarkMatter_Domains::instance()->add( 'example.com:443' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( 'example.com:443' ); $this->assertWPError( $return ); $this->assertSame( $return->get_error_code(), 'unsure' ); /** DOMAIN_CURRENT_SITE */ - $return = DarkMatter_Domains::instance()->add( 'darkmatter.test' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( 'darkmatter.test' ); $this->assertWPError( $return ); $this->assertSame( $return->get_error_code(), 'wp-config' ); /** Non-ASCII - i.e. emojis, etc. */ - $return = DarkMatter_Domains::instance()->add( '🐲' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( '🐲' ); $this->assertWPError( $return ); $this->assertSame( $return->get_error_code(), 'domain' ); /** Stored XSS (and curious input from an administrator one time ... ... ...) */ - $return = DarkMatter_Domains::instance()->add( '' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( '' ); $this->assertWPError( $return ); $this->assertSame( $return->get_error_code(), 'unsure' ); } @@ -241,19 +241,19 @@ public function test_validation_valid_domains() { */ /** Localhost */ - $return = DarkMatter_Domains::instance()->add( 'localhost' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( 'localhost' ); $this->assertNotWPError( $return ); /** Example domain */ - $return = DarkMatter_Domains::instance()->add( 'example.com' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( 'example.com' ); $this->assertNotWPError( $return ); /** Example sub-domain */ - $return = DarkMatter_Domains::instance()->add( 'www.example.com' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( 'www.example.com' ); $this->assertNotWPError( $return ); /** Atypical test domain. */ - $return = DarkMatter_Domains::instance()->add( 'development.test' ); + $return = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( 'development.test' ); $this->assertNotWPError( $return ); } } diff --git a/tests/phpunit/domain-mapping/MappingDomainsTest.php b/tests/phpunit/domain-mapping/MappingDomainsTest.php index e6ea9a74..ca85af62 100644 --- a/tests/phpunit/domain-mapping/MappingDomainsTest.php +++ b/tests/phpunit/domain-mapping/MappingDomainsTest.php @@ -64,7 +64,7 @@ public function setUp() : void { ] ); - DarkMatter_Domains::instance()->network_media = [ + \DarkMatter\DomainMapping\Manager\Domain::instance()->network_media = [ $this->media_domain, ]; @@ -73,7 +73,7 @@ public function setUp() : void { /** * Add domains to the new site. */ - DarkMatter_Domains::instance()->add( + \DarkMatter\DomainMapping\Manager\Domain::instance()->add( $this->primary_domain, true, true @@ -188,7 +188,7 @@ public function test_logout_url() { * @return void */ public function test_rest_url() { - DM_URL::instance()->is_request_mapped = true; + \DarkMatter\DomainMapping\Processor\Mapping::$is_request_mapped = true; $this->assertEquals( /** @@ -199,6 +199,6 @@ public function test_rest_url() { 'REST API URL' ); - DM_URL::instance()->is_request_mapped = false; + \DarkMatter\DomainMapping\Processor\Mapping::$is_request_mapped = false; } } diff --git a/tests/phpunit/domain-mapping/MediaDomainsTest.php b/tests/phpunit/domain-mapping/MediaDomainsTest.php index 56c1befb..02b63633 100644 --- a/tests/phpunit/domain-mapping/MediaDomainsTest.php +++ b/tests/phpunit/domain-mapping/MediaDomainsTest.php @@ -36,7 +36,7 @@ public function setUp() : void { ] ); } - + /** * Media domains set by the `DM_NETWORK_MEDIA` constant. * @@ -47,14 +47,14 @@ public function test_get_media_domains_constant() { 'cdn1.darkmatter.test', ]; - DarkMatter_Domains::instance()->network_media = $constant_domains; + \DarkMatter\DomainMapping\Manager\Domain::instance()->network_media = $constant_domains; - $domains = DarkMatter_Domains::instance()->get_domains_by_type(); + $domains = \DarkMatter\DomainMapping\Manager\Domain::instance()->get_domains_by_type(); $expected = []; foreach ( $constant_domains as $media_domain ) { - $expected[] = new DM_Domain( + $expected[] = new \DarkMatter\DomainMapping\Data\Domain( (object) [ 'active' => true, 'blog_id' => get_current_blog_id(), @@ -79,7 +79,7 @@ public function test_get_media_domains_manual() { /** * Reset any hard-coded media domains. */ - DarkMatter_Domains::instance()->network_media = []; + \DarkMatter\DomainMapping\Manager\Domain::instance()->network_media = []; $media_domains = [ 'cdn1.mappeddomain1.test' => -1, @@ -93,7 +93,7 @@ public function test_get_media_domains_manual() { * Create domains. */ foreach ( $media_domains as $domain => $id ) { - $result = DarkMatter_Domains::instance()->add( + $result = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( $domain, false, true, @@ -109,12 +109,12 @@ public function test_get_media_domains_manual() { /** * Retrieve the domains. */ - $domains = DarkMatter_Domains::instance()->get_domains_by_type(); + $domains = \DarkMatter\DomainMapping\Manager\Domain::instance()->get_domains_by_type(); $expected = []; foreach ( $media_domains as $media_domain => $id ) { - $expected[] = new DM_Domain( + $expected[] = new \DarkMatter\DomainMapping\Data\Domain( (object) [ 'active' => true, 'blog_id' => get_current_blog_id(), diff --git a/tests/phpunit/domain-mapping/PrimaryDomainTest.php b/tests/phpunit/domain-mapping/PrimaryDomainTest.php index 36e3ec16..2eb8578b 100644 --- a/tests/phpunit/domain-mapping/PrimaryDomainTest.php +++ b/tests/phpunit/domain-mapping/PrimaryDomainTest.php @@ -19,14 +19,14 @@ class PrimaryDomainTest extends \WP_UnitTestCase { /** * Holder for Domains class. * - * @var DarkMatter_Domains|null + * @var \DarkMatter\DomainMapping\Manager\Domain|null */ private $darkmatter_domains = null; /** * Holder for Primary class. * - * @var DarkMatter_Primary|null + * @var \DarkMatter\DomainMapping\Manager\Primary|null */ private $darkmatter_primary = null; @@ -67,8 +67,8 @@ public static function wpTearDownAfterClass() { public function setUp(): void { parent::setUp(); - $this->darkmatter_domains = DarkMatter_Domains::instance(); - $this->darkmatter_primary = DarkMatter_Primary::instance(); + $this->darkmatter_domains = \DarkMatter\DomainMapping\Manager\Domain::instance(); + $this->darkmatter_primary = \DarkMatter\DomainMapping\Manager\Primary::instance(); switch_to_blog( self::$blog_id ); } diff --git a/tests/phpunit/domain-mapping/RestrictedDomainsTest.php b/tests/phpunit/domain-mapping/RestrictedDomainsTest.php index afb8937c..a7911165 100644 --- a/tests/phpunit/domain-mapping/RestrictedDomainsTest.php +++ b/tests/phpunit/domain-mapping/RestrictedDomainsTest.php @@ -44,7 +44,7 @@ public function setUp() : void { */ public function test_add_restrict_domain() { $domain = 'restricteddomain1.test'; - $result = DarkMatter_Restrict::instance()->add( $domain ); + $result = \DarkMatter\DomainMapping\Manager\Restricted::instance()->add( $domain ); $this->assertTrue( $result, 'Adding a restricted domain.' ); } @@ -60,13 +60,13 @@ public function test_remove_restrict_domain() { /** * Add domain. */ - $result = DarkMatter_Restrict::instance()->add( $domain ); + $result = \DarkMatter\DomainMapping\Manager\Restricted::instance()->add( $domain ); $this->assertTrue( $result, 'Adding a restricted domain.' ); /** * Remove domain. */ - $result = DarkMatter_Restrict::instance()->delete( $domain ); + $result = \DarkMatter\DomainMapping\Manager\Restricted::instance()->delete( $domain ); $this->assertTrue( $result, 'Removing a restricted domain.' ); } @@ -81,7 +81,7 @@ public function test_restrict_domain_add_domain() { /** * Add domain. */ - $result = DarkMatter_Restrict::instance()->add( $domain ); + $result = \DarkMatter\DomainMapping\Manager\Restricted::instance()->add( $domain ); $this->assertTrue( $result, 'Adding a restricted domain.' ); /** @@ -89,7 +89,7 @@ public function test_restrict_domain_add_domain() { */ switch_to_blog( $this->blog_id ); - $result = DarkMatter_Domains::instance()->add( $domain ); + $result = \DarkMatter\DomainMapping\Manager\Domain::instance()->add( $domain ); $this->assertWPError( $result, 'WP_Error for adding a restricted domain.' ); $this->assertSame( 'reserved', $result->get_error_code(), 'Correct WP_Error for restricted domain.' ); } @@ -103,13 +103,13 @@ public function test_get_restricted_domains() { $domains = [ 'restricteddomain1.test', 'restricteddomain2.test' ]; foreach ( $domains as $domain ) { - $result = DarkMatter_Restrict::instance()->add( $domain ); + $result = \DarkMatter\DomainMapping\Manager\Restricted::instance()->add( $domain ); $this->assertTrue( $result, 'Adding a restricted domain.' ); } $this->assertSame( $domains, - DarkMatter_Restrict::instance()->get(), + \DarkMatter\DomainMapping\Manager\Restricted::instance()->get(), 'Get returns all the restricted domains properly.' ); }