HighlightJS và Next.js, WordPress

Bài viết này dành cho việc thành công trong công cuộc chuyển đổi toàn bộ highlightjs phía FE đẩy hết về BE render HighlightJS Nó trông như thế này: Thay vì trông giống thế này: Rõ ràng là highlight lên trông sẽ dễ đọc hơn. Và cũng thân thiện hơn chữ trắng nền xanh như […]

Bài viết này dành cho việc thành công trong công cuộc chuyển đổi toàn bộ highlightjs phía FE đẩy hết về BE render

HighlightJS

Nó trông như thế này:

Thay vì trông giống thế này:

Rõ ràng là highlight lên trông sẽ dễ đọc hơn. Và cũng thân thiện hơn chữ trắng nền xanh như mặc định.
Vậy giờ thì làm sao cài đặt

Tích hợp highlight.js với Next.js

Cài đặt thì rất nhanh, dùng cái nào thì tuỳ bạn. Chú ý là dùng cái nào mà project đang dùng thôi chứ đừng có chạy cả 3

npm install highlight.js
yar add highlight.js
pnpm add highlight.jsCode language: Bash (bash)

Xong rồi đấy. Giờ import css vào thôi. Ở đây mình chọn github-dark theme

import 'highlight.js/styles/github-dark.css';Code language: TypeScript (typescript)

Còn code này để ở đâu à? Để ở file nào mà web render ấy. Như mình thì nó nằm trong SingleContent.tsx
Vì chỉ cần hiển thị trong phần bài viết nên mình khuyên load trong Single cho nhẹ.

Thông thường, mình sẽ tiếp tục load các thư viện và ngôn ngữ, sau đó dùng useEffect() để áp dụng

import hljs from 'highlight.js/lib/core';
//load thêm các ngôn ngữ, dùng ít thôi kẻo nặng, import gì cho nhiều
import bash from 'highlight.js/lib/languages/bash';
import dockerfile from 'highlight.js/lib/languages/dockerfile';
import powershell from 'highlight.js/lib/languages/powershell';
import javascript from 'highlight.js/lib/languages/javascript';
import makefile from 'highlight.js/lib/languages/makefile';
import markdown from 'highlight.js/lib/languages/markdown';
import php from 'highlight.js/lib/languages/php';
import shell from 'highlight.js/lib/languages/shell';Code language: TypeScript (typescript)

Nếu muốn thêm tên cho dễ gọi hay làm gì khác thì thêm đoạn sau

// thêm cái tên cho dễ gọi, nhưng mà thêm như không vậy nhỉ
hljs.registerLanguage('bash', bash);
hljs.registerLanguage('dockerfile', dockerfile);
hljs.registerLanguage('powershell', powershell);
hljs.registerLanguage('javascript', javascript);
hljs.registerLanguage('makefile', makefile);
hljs.registerLanguage('markdown', markdown);
hljs.registerLanguage('php', php);
hljs.registerLanguage('shell', shell);Code language: JavaScript (javascript)

Giờ apply thôi

// WordPress wrap code trong đoạn pre code nên select nó thôi
    const applyCodeHighlighting = () => {
        if (typeof window !== 'undefined') {
            document.querySelectorAll('pre code').forEach((block) => {
                hljs.highlightElement(block as HTMLElement);
            });
            document.querySelectorAll('p code').forEach((block) => {
                hljs.highlightElement(block as HTMLElement);
            });
        }
    };
    useEffect(() => {
        applyCodeHighlighting();
    }, []);Code language: TypeScript (typescript)

Chú ý: typeof window !== 'undefined' rất cần thiết, vì chúng ta không cần hoạt động khi render mà là phía trình duyệt của người dùng. Không thêm thì lỗi đấy.

Tích hợp với WordPress Backend

Mình giỏi code WordPress hơn, tại sao lại phải cực khổ với đống Typescript trên.

Import css thôi, cái khác khỏi cần.

import 'highlight.js/styles/github-dark.css';Code language: JavaScript (javascript)

Hoặc cho luôn vào header cũng được

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">Code language: HTML, XML (xml)

Giờ thì code một chút để có thể inject class name và style vào bài viết từ phía WordPress khi truy vấn lấy Content thôi

/**
 * Inject class names and styles into the
 *
 * @param string $pre_start_tag  The `<pre>` start tag.
 * @param string $code_start_tag The `<code>` start tag.
 * @param array{
 *     language: string,
 *     highlightedLines: string,
 *     showLineNumbers: bool,
 *     wrapLines: bool
 * }             $attributes     Attributes.
 * @param string $content        Content.
 * @return string Injected markup.
 */
function inject_markup( string $pre_start_tag, string $code_start_tag, array $attributes, string $content ): string {
	$added_classes = 'hljs';

	if ( $attributes['language'] ) {
		$added_classes .= " language-{$attributes['language']}";
	}

	if ( $attributes['showLineNumbers'] || $attributes['highlightedLines'] ) {
		$added_classes .= ' shcb-code-table';
	}

	if ( $attributes['showLineNumbers'] ) {
		$added_classes .= ' shcb-line-numbers';
	}

	if ( $attributes['wrapLines'] ) {
		$added_classes .= ' shcb-wrap-lines';
	}

	// @todo Update this to use WP_HTML_Tag_Processor.
	$code_start_tag = (string) preg_replace(
		'/(<code[^>]*\sclass=")/',
		'$1' . esc_attr( $added_classes ) . ' ',
		$code_start_tag,
		1,
		$count
	);
	if ( 0 === $count ) {
		$code_start_tag = (string) preg_replace(
			'/(?<=<code\b)/',
			sprintf( ' class="%s"', esc_attr( $added_classes ) ),
			$code_start_tag,
			1
		);
	}

	$end_tags = '</code></span>';

	// Add language label if one was detected and if we're not in a feed.
	if ( ! is_feed() && ! empty( $attributes['language'] ) ) {
		$language_names = get_language_names();
		$language_name  = $language_names[ $attributes['language'] ] ?? $attributes['language'];

		$element_id = wp_unique_id( 'shcb-language-' );

		// Add the language info to markup with semantic label.
		$end_tags .= sprintf(
			'<small class="shcb-language" id="%s"><span class="shcb-language__label">%s</span> <span class="shcb-language__name">%s</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">%s</span><span class="shcb-language__paren">)</span></small>',
			esc_attr( $element_id ),
			esc_html__( 'Code language:', 'syntax-highlighting-code-block' ),
			esc_html( $language_name ),
			esc_html( $attributes['language'] )
		);

		// Also include the language in data attributes on the root <pre> element for maximum styling flexibility.
		$pre_start_tag = str_replace(
			'>',
			sprintf(
				' aria-describedby="%s" data-shcb-language-name="%s" data-shcb-language-slug="%s">',
				esc_attr( $element_id ),
				esc_attr( $language_name ),
				esc_attr( $attributes['language'] )
			),
			$pre_start_tag
		);
	}
	$end_tags .= '</pre>';

	return $pre_start_tag . '<span>' . $code_start_tag . escape( $content ) . $end_tags;
}Code language: PHP (php)

Đùa chút thôi, cài plugin này vào là đủ rồi:

https://wordpress.org/plugins/syntax-highlighting-code-block

https://github.com/westonruter/syntax-highlighting-code-block

Kích hoạt, và xong

Dùng thì nhớ chọn ngôn ngữ kẻo nhận lung tung nhé

Vì khi get dữ liệu, thì nội dung đã được thêm sẵn các class name rồi, chỉ cần mỗi css để thể hiện thôi:

Nhanh gọn và nhẹ hơn là ngồi chờ useEffect, vì kiểu gì PHP cache cũng dễ hơn mà.

A
WRITTEN BY

ArcLight

Responses (0 )