` / * `# END ` shape WordPress's own insert_with_markers() produces, * so it stays recognizable/editable by that convention. * * @return string Block text, including a trailing newline. */ public static function build_block() { $lines = array( '# BEGIN ' . self::MARKER, '', 'RewriteEngine On', 'RewriteCond %{REQUEST_URI} ^/(llms\.txt|llms-full\.txt)$', 'RewriteCond %{REQUEST_FILENAME} -f', 'RewriteRule ^ - [L]', '', '# END ' . self::MARKER, ); return implode( "\n", $lines ) . "\n"; } /** * Remove a previously-inserted block (any content between our BEGIN/END * markers, markers included) from $content, leaving everything else and * its original order untouched. Safe to call when no block is present. * * @param string $content Full .htaccess content. * @return string */ public static function strip_block( $content ) { $pattern = '/#\s*BEGIN\s+' . preg_quote( self::MARKER, '/' ) . '.*?#\s*END\s+' . preg_quote( self::MARKER, '/' ) . '\s*\n?/s'; return (string) preg_replace( $pattern, '', (string) $content ); } /** * Whether $content already carries our block. * * @param string $content Full .htaccess content. * @return bool */ public static function has_block( $content ) { return false !== strpos( (string) $content, '# BEGIN ' . self::MARKER ); } /** * Prepend our block to $htaccess_path, replacing any earlier copy of it * (idempotent — safe to re-run), and leaving a timestamped backup of the * previous file so the change can be undone by hand. * * @param string $htaccess_path Absolute path to the .htaccess file. * @return array{applied:bool,reason:string,backup:string} */ public static function apply( $htaccess_path ) { $dir = dirname( $htaccess_path ); if ( ! is_dir( $dir ) || ! is_writable( $dir ) ) { return array( 'applied' => false, 'reason' => 'not_writable', 'backup' => '' ); } if ( file_exists( $htaccess_path ) && ! is_writable( $htaccess_path ) ) { return array( 'applied' => false, 'reason' => 'not_writable', 'backup' => '' ); } $existing = file_exists( $htaccess_path ) ? (string) file_get_contents( $htaccess_path ) : ''; $backup = ''; if ( '' !== $existing ) { $backup = $htaccess_path . '.adg-backup-' . gmdate( 'Ymd-His' ); if ( false === @file_put_contents( $backup, $existing, LOCK_EX ) ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- outcome checked via return value. return array( 'applied' => false, 'reason' => 'backup_failed', 'backup' => '' ); } } $new_content = self::build_block() . "\n" . ltrim( self::strip_block( $existing ) ); if ( false === @file_put_contents( $htaccess_path, $new_content, LOCK_EX ) ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- outcome checked via return value. return array( 'applied' => false, 'reason' => 'write_failed', 'backup' => $backup ); } return array( 'applied' => true, 'reason' => 'ok', 'backup' => $backup ); } }