Linkreviewscanner - Source Excerpt 01
Summary
This source excerpt preserves a bounded section of Antichrist.net/wp-content/plugins/uaix-locale-router/src/Diagnostics/LinkReviewScanner.php so readers can inspect the evidence without opening the full source file.
**Source path:** Antichrist.net/wp-content/plugins/uaix-locale-router/src/Diagnostics/LinkReviewScanner.php
<?php
namespace UAIXLocaleRouter\Diagnostics;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
final class LinkReviewScanner {
/**
* Review active UAIX theme and plugin files for hardcoded locale-link patterns.
*
* @param bool $force_refresh Whether to bypass the transient cache.
* @return array
*/
public static function locale_link_review_diagnostics( $force_refresh = false ) {
if ( ! $force_refresh ) {
$cached = get_transient( 'uaixlr_link_review' );
if ( is_array( $cached ) ) {
return $cached;
}
}
$roots = self::link_review_scope();
$findings = array();
$counts = array(
'bare_internal_links' => 0,
'explicit_locale_links' => 0,
'files_scanned' => 0,
);
foreach ( $roots as $root ) {
self::scan_link_review_root( $root, $findings, $counts );
}
$severity = 'good';
$summary = __( 'No hardcoded locale-link issues were detected in the active UAIX theme and plugin sources.', 'uaix-locale-router' );
$issues = array();
if ( $counts['bare_internal_links'] > 0 ) {
$severity = 'warning';
$issues[] = sprintf(
/* translators: %d: finding count */
__( 'Found %d root-relative internal link(s) such as href="/spec/" or href="/". These rely on redirect fallback and do not preserve the active locale context.', 'uaix-locale-router' ),
$counts['bare_internal_links']
);
}
if ( $counts['explicit_locale_links'] > 0 ) {
$severity = 'warning';
$issues[] = sprintf(
/* translators: %d: finding count */
__( 'Found %d explicit locale-pinned link(s) such as /en-us/... . These should be limited to intentional language switchers or documented exceptions.', 'uaix-locale-router' ),
$counts['explicit_locale_links']
);
}
if ( ! empty( $issues ) ) {
$summary = __( 'Review locale-link findings before publishing. Bare internal links should be locale-aware, and explicit locale URLs should only exist when they intentionally pin one language.', 'uaix-locale-router' );
}
$result = array(
'severity' => $severity,
'summary' => $summary,
'issues' => $issues,
'findings' => array_slice( $findings, 0, 12 ),
'bare_internal_links' => $counts['bare_internal_links'],
'explicit_locale_links' => $counts['explicit_locale_links'],
'files_scanned' => $counts['files_scanned'],
'roots' => $roots,
'guidance' => array(
__( 'Use WordPress or locale-aware helpers for internal navigation instead of bare root-relative links such as href="/spec/" or href="/".', 'uaix-locale-router' ),
__( 'Reserve explicit locale-prefixed links such as /en-us/... for intentional language switchers or similarly explicit language-pinning flows.', 'uaix-locale-router' ),
__( 'Bare non-locale URLs are acceptable for external entry points, but normal internal navigation should preserve the active locale instead of forcing a redirect hop.', 'uaix-locale-router' ),
__( 'If a finding is intentionally exempt, add a nearby uaixlr-review-ignore marker and document why before publishing.', 'uaix-locale-router' ),
),
'checked_at' => time(),
);
set_transient( 'uaixlr_link_review', $result, 15 * MINUTE_IN_SECONDS );
return $result;
}
/**
* Build the review scope for active UAIX-controlled theme and plugin code.
*
* @return array
*/
private static function link_review_scope() {
$roots = array();
$stylesheet_dir = function_exists( 'get_stylesheet_directory' ) ? get_stylesheet_directory() : '';
$template_dir = function_exists( 'get_template_directory' ) ? get_template_directory() : '';
$plugin_roots = array( 'uaix-locale-router', 'uaix-core', 'uaix-bridge', 'uaix-modules' );
if ( $stylesheet_dir && is_dir( $stylesheet_dir ) ) {
$roots[ $stylesheet_dir ] = array(
'label' => __( 'Active theme', 'uaix-locale-router' ),
'path' => $stylesheet_dir,
);
}
if ( $template_dir && $template_dir !== $stylesheet_dir && is_dir( $template_dir ) ) {
$roots[ $template_dir ] = array(
'label' => __( 'Parent theme', 'uaix-locale-router' ),
'path' => $template_dir,
);
}
foreach ( $plugin_roots as $plugin_root ) {
$path = trailingslashit( WP_PLUGIN_DIR ) . $plugin_root;
if ( is_dir( $path ) ) {
$roots[ $path ] = array(
'label' => sprintf(
/* translators: %s: plugin slug */
__( 'Plugin: %s', 'uaix-locale-router' ),
$plugin_root
),
'path' => $path,
);
}
}
return array_values( $roots );
}
/**
* Scan one source root for locale-link review findings.
*
* @param array $root Root metadata.
* @param array $findings Findings accumulator.
* @param array $counts Counts accumulator.
* @return void
*/
private static function scan_link_review_root( array $root, array &$findings, array &$counts ) {
if ( empty( $root['path'] ) || ! is_dir( $root['path'] ) ) {
return;
}
$max_files = (int) apply_filters( 'uaixlr_link_review_max_files', 500 );
$max_bytes = (int) apply_filters( 'uaixlr_link_review_max_file_bytes', 262144 );
$max_files = $max_files > 0 ? $max_files : 500;
$max_bytes = $max_bytes > 0 ? $max_bytes : 262144;
try {
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator(
$root['path'],
\FilesystemIterator::SKIP_DOTS
)
);
} catch ( \UnexpectedValueException $exception ) {
return;
}
foreach ( $iterator as $file_info ) {
if ( $counts['files_scanned'] >= $max_files ) {
return;
}
if ( ! $file_info instanceof \SplFileInfo || ! $file_info->isFile() ) {
continue;
}
$file_path = $file_info->getPathname();
if ( $file_info->getSize() > $max_bytes || self::should_skip_link_review_path( $file_path ) || ! self::is_link_review_file( $file_path ) ) {
continue;
}
++$counts['files_scanned'];
self::scan_link_review_file( $file_path, $root['label'], $findings, $counts );
}
}
/**
* Scan a single file for locale-link review findings.
*
* @param string $file_path File path.
* @param string $root_label Human-readable source label.
* @param array $findings Findings accumulator.
* @param array $counts Counts accumulator.
* @return void
*/
private static function scan_link_review_file( $file_path, $root_label, array &$findings, array &$counts ) {
$lines = @file( $file_path );
if ( false === $lines ) {
return;
}
$bare_internal_pattern = '~<[^>]*\b(?:href|action)\s*=\s*(["\'])/(?!/|#|wp-admin/|wp-login\.php|wp-json/|wp-content/|wp-includes/|favicon\.ico|robots\.txt|xmlrpc\.php|feed(?:["\'/]|$)|sitemap(?:["\'/.\-]|$)|[A-Za-z]{2,8}(?:-[A-Za-z0-9]{2,8})+/)([^"\']*)\1~i';
$explicit_locale_pattern = '~<[^>]*\b(?:href|action)\s*=\s*(["\'])/([A-Za-z]{2,8}(?:-[A-Za-z0-9]{2,8})+)(?:/[^"\']*)?\1~';
foreach ( $lines as $index => $line ) {
if ( false !== strpos( $line, 'uaixlr-review-ignore' ) ) {
continue;
}
if ( preg_match( $bare_internal_pattern, $line ) ) {
++$counts['bare_internal_links'];
if ( count( $findings ) < 12 ) {
$findings[] = array(
'type' => 'bare_internal_link',
'label' => __( 'Bare internal link', 'uaix-locale-router' ),
'source' => $root_label,
'path' => self::relative_review_path( $file_path ),
'line' => $index + 1,
'snippet' => trim( $line ),
);
}
}
if ( preg_match( $explicit_locale_pattern, $line ) ) {
++$counts['explicit_locale_links'];
if ( count( $findings ) < 12 ) {
$findings[] = array(
'type' => 'explicit_locale_link',
'label' => __( 'Explicit locale link', 'uaix-locale-router' ),
'source' => $root_label,
'path' => self::relative_review_path( $file_path ),
'line' => $index + 1,
'snippet' => trim( $line ),
);
}
}
}
}
/**
* Determine whether a file should be included in locale-link review.
*
* @param string $file_path File path.
* @return bool
*/
private static function is_link_review_file( $file_path ) {
return in_array( strtolower( (string) pathinfo( $file_path, PATHINFO_EXTENSION ) ), array( 'php', 'html', 'js' ), true );
}
/**
* Determine whether a path should be excluded from locale-link review.
*
* @param string $file_path File path.
* @return bool
*/
private static function should_skip_link_review_path( $file_path ) {
$normalized = str_replace( '\\', '/', (string) $file_path );
$skip_parts = array(
'/vendor/',
'/node_modules/',
'/languages/',
'/data/',
'/docs/',
'/tests/',
);
foreach ( $skip_parts as $skip_part ) {
if ( false !== strpos( $normalized, $skip_part ) ) {