WordPress как на ладони

Удаляем дублированные строки в каждой следующей части крошек

Kama Breadcrumbs

Была задача удалить из крошек повторяющиеся части в названии.

Например, у нас есть такие крошки:

Дом > Посуда > Посуда для офиса > Посуда для офиса дешево > Тарелки для офиса

Нам нужно получить такое:

Дом > Посуда > Для офиса > Дешево > Тарелки для офиса

Решение (не идеальное, его унжно переделать):

// Хук для kama_breadcrumbs
// удаляет дублированные строки в каждой следующей части крошек
add_filter( 'kama_breadcrumbs', [ Kama_Breadcrumbs_Delete_Duplicate_Strings::class, 'del_duplicate_strings' ], 10, 2 );

final class Kama_Breadcrumbs_Delete_Duplicate_Strings {

	public static function del_duplicate_strings( $html, $sep ) {

		$parts = explode( $sep, $html );
		$elements = array_map( 'strip_tags', $parts );
		$elements = array_map( 'trim', $elements );

		$new_elements = self::collect_new_elements( $elements );

		foreach( $parts as $k => $part ){
			$parts[ $k ] = str_replace( $elements[ $k ], $new_elements[ $k ], $part );
		}

		return implode( $sep, $parts );
	}

	private static function collect_new_elements( $elements ){

		$prev_strs = [];
		$new_elements = [];

		foreach( $elements as $str ){
			$has_replaced = 0;

			$lower_str = mb_strtolower( $str );

			$replaced_str = $lower_str;
			foreach( $prev_strs as $prevstr ){
				$replaced_str = str_replace( $prevstr, '', $replaced_str, $repcount );

				if( $repcount ){
					$has_replaced++;
					// break - нельзя!
				}
			}

			$replaced_str = trim( $replaced_str );
			$new_elements[] = $has_replaced ? self::mb_ucfirst( $replaced_str ) : $str;
			$prev_strs[] = $lower_str; // предыдущие элементы крошек (строки)

			if( $has_replaced ){
				$prev_strs[] = $replaced_str; // новая строка в список замены

				self::split_string_to_words( $replaced_str, $prev_strs );
			}
		}

		return $new_elements;
	}

	/**
	 *
	 * разобьем строку на слова и добавим их в замену
	 *
	 * @param string $rep_str
	 *
	 * @return void
	 */
	private static function split_string_to_words( $rep_str, & $prev_strs ){

		$rep_str_arr = preg_split( '~( +)~u', $rep_str, -1, PREG_SPLIT_DELIM_CAPTURE );
		$_rep_str_arr = [];

		foreach( $rep_str_arr as $index => $val ){

			$nextval = $rep_str_arr[ $index + 1 ] ?? null;

			if( ! $nextval ){
				break;
			}

			if( $nextval[0] === ' ' ){
				$_rep_str_arr[] = $val . $nextval;
			}
			elseif( $val[0] !== ' ' ){
				$_rep_str_arr[] = $val;
			}
		}
		$rep_str_arr = $_rep_str_arr;

		// отдельные слова для замены (с пробелами на концах)
		foreach( $rep_str_arr as $val ){
			$prev_strs[] = $val;
		}
	}

	private static function mb_ucfirst( $string ) {
		// echo mb_internal_encoding();
		// mb_internal_encoding('UTF-8');
		$string = trim( $string );

		return mb_strtoupper( mb_substr( $string, 0, 1 ) ) . mb_substr( $string, 1 );
	}

}
4 комментария
    Войти