resolve_delivery_mode(); } /** * Whether the notice should render on this request. * * @return bool */ private function should_display(): bool { if (self::root_is_writable()) { return false; } // Only users who can act on it (or ask the host to) are shown the // warning. if (!current_user_can('manage_options')) { return false; } return !get_option(self::OPT_DISMISSED); } /** * Load the shared notice stylesheet when the notice will render. * * @return void */ public function enqueue_assets(): void { if (!$this->should_display()) { return; } wp_enqueue_style( 'thinkrank-admin-notices', THINKRANK_PLUGIN_URL . 'static/css/admin-notices.css', [], THINKRANK_VERSION ); } /** * Render the notice. * * @return void */ public function render(): void { if (!$this->should_display()) { return; } ?>

' . esc_html(untrailingslashit(ABSPATH)) . '', esc_html(implode(', ', self::affected_features())) ); ?>

__('ThinkRank can publish files to your WordPress folder', 'thinkrank'), 'test' => [$this, 'run_health_test'], ]; return $tests; } /** * Site Health test body. * * @since 2.9.0 * * @return array Site Health result array. */ public function run_health_test(): array { $result = [ 'label' => __('ThinkRank can publish files to your WordPress folder', 'thinkrank'), 'status' => 'good', 'badge' => [ 'label' => __('SEO', 'thinkrank'), 'color' => 'blue', ], 'description' => '

' . esc_html__('ThinkRank can write to the WordPress root, so robots.txt, llms.txt and the Instant Indexing key file can be published.', 'thinkrank') . '

', 'actions' => '', 'test' => self::HEALTH_TEST, ]; if (self::root_is_writable()) { return $result; } $result['status'] = 'recommended'; $result['label'] = __('ThinkRank cannot publish files to your WordPress folder', 'thinkrank'); $description = '

' . sprintf( /* translators: 1: absolute path to the WordPress root, 2: comma-separated list of affected features. */ esc_html__('The folder %1$s is not writable by PHP, so ThinkRank cannot publish %2$s.', 'thinkrank'), '' . esc_html(untrailingslashit(ABSPATH)) . '', esc_html(implode(', ', self::affected_features())) ) . '

'; $description .= self::sitemap_is_unaffected() ? '

' . esc_html__('Your XML sitemap is not affected. ThinkRank detects this and serves the sitemap directly instead of writing it to a file.', 'thinkrank') . '

' : '

' . esc_html__('Your XML sitemap is affected too. Sitemap delivery is set to write files, and those files cannot be written. Set sitemap delivery to automatic so WordPress serves the sitemap directly, or make the folder writable.', 'thinkrank') . '

'; // Named explicitly because both are the usual first guesses and neither // has any effect here: the write fails on the root directory itself, // and get_filesystem_method() still reports "direct" because with no // context argument it tests wp-content, not the root. $description .= '

' . esc_html__('Adding FS_METHOD or FTP credentials to wp-config.php will not resolve this. Ask your host to make the WordPress root writable by the web server user.', 'thinkrank') . '

'; if (get_option(self::OPT_ACTIVATION_STATE) === 'writable') { $description .= '

' . esc_html__('This folder was writable when ThinkRank was activated, so something on the hosting side changed since then.', 'thinkrank') . '

'; } $result['description'] = $description; return $result; } /** * Clear the dismissal once the root becomes writable again. * * Called from the Site Health test and the notice path is cheap, so this * runs wherever the condition is evaluated rather than on a schedule. * * @since 2.9.0 * * @return void */ public function reset_dismissal(): void { if (self::root_is_writable()) { delete_option(self::OPT_DISMISSED); } } }