.txt` (one word * per line). Lookups return the parsed list for a given language code, * cached for the lifetime of the request. * * Site owners can extend or override the list via the * `postlinkly_ignore_words` filter, which takes the loaded list and the * language code and returns the list to use. * * @since 1.0.0 */ final class IgnoreWords { /** * Cached lists keyed by language code. * * @var array> */ private array $cache = array(); /** * Returns the stop-word list for a language code. * * Unknown codes return an empty list. Words are returned lower-cased * and trimmed. * * @since 1.0.0 * * @param string $language Two-letter language code. * * @return array List of stop words. */ public function for_language( string $language ): array { $language = strtolower( trim( $language ) ); if ( '' === $language ) { return array(); } if ( isset( $this->cache[ $language ] ) ) { return $this->cache[ $language ]; } $list = $this->load_from_disk( $language ); /** * Filters the stop-word list for a language. * * @since 1.0.0 * * @param array $list The loaded list. * @param string $language Two-letter language code. */ $list = (array) apply_filters( 'postlinkly_ignore_words', $list, $language ); $this->cache[ $language ] = $list; return $list; } /** * Returns the stop-word list as a flipped lookup map (word => true). * * Use this when you only need O(1) "is this a stop word?" checks. * * @since 1.0.0 * * @param string $language Two-letter language code. * * @return array Lookup map. */ public function lookup_for_language( string $language ): array { return array_fill_keys( $this->for_language( $language ), true ); } /** * Reads and parses the on-disk stop-word file for a language. * * @since 1.0.0 * * @param string $language Two-letter language code (must already be normalised). * * @return array Parsed list. */ private function load_from_disk( string $language ): array { // Locate the data file. The plugin ships the lists in `assets/ignore-words/`. $base_dir = defined( 'POSTLINKLY_PLUGIN_DIR' ) ? (string) POSTLINKLY_PLUGIN_DIR : dirname( __DIR__, 2 ) . '/'; $path = $base_dir . 'assets/ignore-words/' . $language . '.txt'; if ( ! is_readable( $path ) ) { return array(); } $contents = file_get_contents( $path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Local file read; wp_remote_get is for HTTP. if ( false === $contents || '' === $contents ) { return array(); } $lines = preg_split( '/\R/u', $contents ); if ( false === $lines ) { $lines = array(); } $out = array(); foreach ( $lines as $line ) { $word = mb_strtolower( trim( $line ), 'UTF-8' ); // Skip empties and comment lines. if ( '' === $word || '#' === $word[0] ) { continue; } $out[] = $word; } return $out; } }