ring REST API requests. static $adminTranslationsLoaded = false; if ( ! $adminTranslationsLoaded ) { $adminTranslationsLoaded = true; $locale = determine_locale(); if ( 'en_US' !== $locale ) { load_textdomain( 'default', WP_LANG_DIR . "/admin-{$locale}.mo" ); } } // phpcs:disable AIOSEO.Wp.I18n.MissingArgDomain, WordPress.WP.I18n.MissingArgDomain $defaultTitles = array_unique( [ 'Hello world!', __( 'Hello world!' ) ] ); $defaultSlugs = array_unique( [ 'hello-world', sanitize_title( _x( 'hello-world', 'Default post slug' ) ) ] ); // phpcs:enable // WordPress appends "__trashed" to the post slug when a post is trashed (see wp_trash_post()). $defaultSlugs = array_merge( $defaultSlugs, array_map( function ( $slug ) { return $slug . '__trashed'; }, $defaultSlugs ) ); return in_array( $post->post_title, $defaultTitles, true ) && in_array( $post->post_name, $defaultSlugs, true ); } /** * Check if the hello world post has been deleted. * * @since 4.9.4 * * @return bool True if hello world post has been deleted. */ protected function checkDeleteHelloWorld() { $post = get_post( 1 ); return empty( $post->ID ) || ! empty( $post->post_status ) && 'trash' === $post->post_status; } /** * Check if the setup wizard has been completed. * * @since 4.9.4 * * @return bool True if completed. */ protected function checkFinishSetupWizard() { return aioseo()->internalOptions->internal->wizardCompleted; } /** * Check if Google Search Console is connected. * * @since 4.9.4 * * @return bool True if connected. */ protected function checkConnectGoogleSearchConsole() { return aioseo()->searchStatistics->api->auth->isConnected(); } /** * Check if a homepage SEO audit has been run. * * @since 4.9.4 * * @return bool True if audit has been run. */ protected function checkRunHomepageAudit() { return ! empty( SeoAnalyzerResult::getResults() ); } /** * Check if Site Title is set. * * @since 4.9.4 * * @return bool True if Site Title is set. */ protected function checkSiteTitle() { $siteTitle = get_option( 'blogname' ); return ! empty( $siteTitle ); } /** * Check if Tagline is set. * * @since 4.9.4 * * @return bool True if Tagline is set. */ protected function checkTagline() { $tagline = get_option( 'blogdescription' ); return ! empty( $tagline ); } /** * Check if both Site Title and Tagline are set. * * @since 4.9.4 * * @return bool True if both Site Title and Tagline are set. */ protected function checkSiteTitleAndTagline() { return $this->checkSiteTitle() && $this->checkTagline(); } /** * Check if Social Profiles have been filled out. * * @since 4.9.4 * * @return bool True if at least one social profile is configured. */ protected function checkFillSocialProfiles() { $profiles = aioseo()->options->social->profiles->all(); // Check if "Use the same username for multiple social networks" is enabled with a username and at least one network selected. if ( ! empty( $profiles['sameUsername']['enable'] ) && ! empty( $profiles['sameUsername']['username'] ) && ! empty( $profiles['sameUsername']['included'] ) ) { return true; } // Check if any social URL is set. $urls = $profiles['urls'] ?? []; foreach ( $urls as $url ) { if ( ! empty( $url ) ) { return true; } } // Check if additional profiles URLs are set. if ( ! empty( trim( $profiles['additionalUrls'] ?? '' ) ) ) { return true; } return false; } /** * Check if site indexing is enabled. * * @since 4.9.4 * * @return bool True if indexing is enabled (blog_public is 1). */ protected function checkIndexingEnabled() { return '1' === get_option( 'blog_public' ); } /** * Check if llms.txt is enabled. * * @since 4.9.4 * * @return bool True if llms.txt is enabled. */ protected function checkLlmsTxtEnabled() { return aioseo()->options->sitemap->llms->enable; } /** * Check if Broken Link Checker is installed. * * @since 4.9.4 * * @return bool True if BLC is installed. */ protected function checkBrokenLinkCheckerInstalled() { $pluginData = aioseo()->helpers->getPluginData(); return ! empty( $pluginData['brokenLinkChecker']['installed'] ); } /** * Check if Broken Link Checker is connected. * * @since 4.9.4 * * @return bool True if BLC is connected. */ protected function checkBrokenLinkCheckerConnected() { return $this->isBrokenLinkCheckerConnected(); } /** * Helper to check if Broken Link Checker is active. * * @since 4.9.4 * * @return bool True if BLC is installed and active. */ protected function isBrokenLinkCheckerActive() { return function_exists( 'aioseoBrokenLinkChecker' ); } /** * Helper to check if Broken Link Checker is connected. * * @since 4.9.4 * * @return bool True if BLC is connected. */ protected function isBrokenLinkCheckerConnected() { if ( ! $this->isBrokenLinkCheckerActive() ) { return false; } // Check if BLC has completed its initial scan or has an API key set. return aioseoBrokenLinkChecker()->license->isActive(); } /** * Complete a check. * * @since 4.9.4 * * @param string $checkName The name of the check to complete. * @return void */ public function completeCheck( $checkName ) { // Check permissions if the user is logged in. // Don't do this if wp_get_current_user() is not loaded. // This prevents errors when the method is called inside the plugin during init, and not via the API. if ( function_exists( 'wp_get_current_user' ) ) { // User needs access to the general settings or setup wizard. if ( ! aioseo()->access->hasCapability( 'aioseo_general_settings' ) && ! aioseo()->access->hasCapability( 'aioseo_setup_wizard' ) ) { return; } // User should also have the cap required to complete this check. if ( ! $this->hasCapability( $checkName ) ) { return; } } $completedChecks = aioseo()->internalOptions->internal->seoChecklist->completed; $completedChecks[] = $checkName; $completedChecks = array_values( array_unique( $completedChecks ) ); aioseo()->internalOptions->internal->seoChecklist->completed = $completedChecks; } /** * Uncomplete a check (remove completed status). * * @since 4.9.4 * * @param string $checkName The name of the check to uncomplete. * @return void */ public function uncompleteCheck( $checkName ) { // Check permissions if the user is logged in. // Don't do this if wp_get_current_user() is not loaded. // This prevents errors when the method is called inside the plugin during init, and not via the API. if ( function_exists( 'wp_get_current_user' ) ) { // User needs access to the general settings or setup wizard. if ( ! aioseo()->access->hasCapability( 'aioseo_general_settings' ) && ! aioseo()->access->hasCapability( 'aioseo_setup_wizard' ) ) { return; } // User should also have the cap required to uncomplete this check. if ( ! $this->hasCapability( $checkName ) ) { return; } } $completedChecks = aioseo()->internalOptions->internal->seoChecklist->completed; $completedChecks = array_values( array_unique( array_diff( $completedChecks, [ $checkName ] ) ) ); aioseo()->internalOptions->internal->seoChecklist->completed = $completedChecks; } /** * Execute an action for a check. * * @since 4.9.4 * * @param string $checkName The name of the check to execute the action for. * @param string $action The action to execute. * @return bool True if successful. */ public function doAction( $checkName, $action ) { // Check if the user is logged in and has access to the general settings or setup wizard. // Don't do this if wp_get_current_user() is not loaded. // This prevents errors when the method is called inside the plugin during init, and not via the API. if ( function_exists( 'wp_get_current_user' ) ) { // User needs access to the general settings or setup wizard. if ( ! aioseo()->access->hasCapability( 'aioseo_general_settings' ) && ! aioseo()->access->hasCapability( 'aioseo_setup_wizard' ) ) { return; } // User should also have the cap required to uncomplete this check. if ( ! $this->hasCapability( $checkName ) ) { return; } } switch ( $action ) { case 'completeCheck': // Just mark as complete, no additional action needed. return true; case 'deleteHelloWorld': return $this->deleteHelloWorld(); case 'enableIndexing': return $this->enableIndexing(); case 'enableLlmsTxt': return $this->enableLlmsTxt(); case 'installBrokenLinkChecker': return $this->installBrokenLinkChecker(); default: return false; } } /** * Delete the Hello World post. * * @since 4.9.4 * * @return bool True if successful. */ private function deleteHelloWorld() { // Check if user has permission to delete the post. if ( ! current_user_can( 'delete_post', 1 ) ) { return false; } // Only delete if the post is still the default "Hello World" post. $post = get_post( 1 ); if ( empty( $post ) || ! $this->isDefaultHelloWorldPost( $post ) ) { return false; } // Delete the post. wp_trash_post( 1 ); return true; } /** * Enable site indexing. * * @since 4.9.4 * * @return bool True if successful. */ private function enableIndexing() { if ( ! current_user_can( 'manage_options' ) ) { return false; } update_option( 'blog_public', '1' ); return true; } /** * Enable llms.txt. * * @since 4.9.4 * * @return bool True if successful. */ private function enableLlmsTxt() { if ( ! aioseo()->access->hasCapability( 'aioseo_sitemap_settings' ) ) { return false; } aioseo()->options->sitemap->llms->enable = true; // Schedule llms.txt generation. if ( aioseo()->llms ) { aioseo()->llms->scheduleSingleGenerationForLlmsTxt(); } return true; } /** * Install Broken Link Checker. * * @since 4.9.4 * * @return bool True if successful. */ private function installBrokenLinkChecker() { if ( ! current_user_can( 'install_plugins' ) ) { return false; } if ( ! aioseo()->addons->canInstall() ) { return false; } $installed = aioseo()->addons->installAddon( 'brokenLinkChecker' ); if ( $installed && function_exists( 'aioseoBrokenLinkChecker' ) ) { aioseoBrokenLinkChecker()->core->cache->delete( 'activation_redirect' ); } return $installed; } /** * Check if the user has the capability to complete a check. * * @since 4.9.4 * * @param string $checkName The name of the check. * @return bool True if the user has the capability. */ public function hasCapability( $checkName ) { // Ensure checks are registered before looking up capabilities. if ( empty( $this->checks ) ) { $this->registerChecks(); } // Find the check by name. $check = array_filter( $this->checks, function ( $check ) use ( $checkName ) { return $check['name'] === $checkName; } ); $check = reset( $check ); // If the check was not found, deny access by default. if ( false === $check ) { return false; } // If the check does not have a capability, return true. if ( ! isset( $check['capability'] ) ) { return true; } if ( is_callable( $check['capability'] ) ) { return call_user_func( $check['capability'] ); } if ( is_string( $check['capability'] ) ) { return aioseo()->access->hasCapability( $check['capability'] ); } if ( is_array( $check['capability'] ) ) { foreach ( $check['capability'] as $capability ) { // If user has any allowed capability, return true. if ( aioseo()->access->hasCapability( $capability ) ) { return true; } } return false; } return false; } }