Cách xóa title khỏi thẻ <a> trong bài viết WordPress

minhnc
Thành viên
Bài viết: 2
Ngày tham gia: 15:39 - 21/4/2022
Được thả tim: 10 lần

Cách xóa title khỏi thẻ <a> trong bài viết WordPress

Mình đang gặp một vấn đề nhỏ với website WordPress và cần sự hỗ trợ từ các bạn. Mình muốn xóa bỏ thuộc tính title trong các thẻ <a> có class="custom-internal-link" trong phần nội dung bài viết. Hiện tại, mình có khoảng 7000 bài viết, mỗi bài trung bình có khoảng 20 liên kết như vậy.

Mình đã thử viết một đoạn script PHP như sau:

Mã: Chọn tất cả

<?php
require_once('wp-load.php'); // Nạp WordPress

global $wpdb;

// Lấy danh sách bài viết có chứa class="custom-internal-link"
$posts = $wpdb->get_results("SELECT ID, post_content FROM {$wpdb->posts} WHERE post_content LIKE '%class=\"custom-internal-link\"%'", ARRAY_A);

foreach ($posts as $post) {
    // Xóa title trong các thẻ <a> có class="custom-internal-link"
    $new_content = preg_replace('/<a([^>]*?)\s+title="[^"]*"\s+class="custom-internal-link"([^>]*?)>/', '<a\1 class="custom-internal-link"\2>', $post['post_content']);
    
    if ($new_content !== $post['post_content']) {
        $wpdb->update(
            $wpdb->posts,
            ['post_content' => $new_content],
            ['ID' => $post['ID']],
            ['%s'],
            ['%d']
        );
    }
}

echo "Cập nhật thành công!";
?>

Một số thắc mắc và lưu ý mình đang có:

- Độ tin cậy của regex: Đoạn regex này có hoạt động ổn không nếu thứ tự của thuộc tính trong thẻ <a> thay đổi (ví dụ: class đứng trước title)? Có cần cải tiến thêm để xử lý được nhiều trường hợp khác nhau không?

- Hiệu năng khi xử lý 7000 bài viết: Mình có nên chia nhỏ xử lý theo từng lô (batch processing) hay chạy qua CLI thay vì trình duyệt để tránh lỗi timeout không?

- Ảnh hưởng đến các liên kết khác: Liệu đoạn script này có vô tình làm thay đổi các liên kết không có thuộc tính title hoặc không có class="custom-internal-link" không?

Mình mong nhận được góp ý, cải tiến hoặc giải pháp thay thế nếu có. Cảm ơn mọi người rất nhiều!
Từ khóa:
Google Adsense
Đã xác thực
Quảng Cáo
minhlvt123
Thành viên
Bài viết: 25
Ngày tham gia: 11:56 - 25/4/2018
Được thả tim: 50 lần

Re: Cách xóa title khỏi thẻ <a> trong bài viết WordPress

Bạn nên sử dụng DOMDocument thay vì regex để đảm bảo tính chính xác. Regex không phải lúc nào cũng xử lý đúng HTML phức tạp. Nếu thuộc tính title và class bị đảo vị trí, regex của bạn có thể bỏ sót hoặc làm hỏng thẻ <a>.

Dưới đây là cách dùng DOMDocument để xử lý an toàn hơn:

Mã: Chọn tất cả

<?php
require_once('wp-load.php'); 

global $wpdb;

$posts = $wpdb->get_results("SELECT ID, post_content FROM {$wpdb->posts} WHERE post_content LIKE '%class=\"custom-internal-link\"%'", ARRAY_A);

foreach ($posts as $post) {
    $doc = new DOMDocument();
    libxml_use_internal_errors(true); // Tránh lỗi do HTML không hợp lệ
    $doc->loadHTML('<?xml encoding="utf-8" ?>' . $post['post_content'], LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    
    $links = $doc->getElementsByTagName('a');

    foreach ($links as $link) {
        if ($link->hasAttribute('class') && strpos($link->getAttribute('class'), 'custom-internal-link') !== false) {
            $link->removeAttribute('title');
        }
    }

    $new_content = $doc->saveHTML();
    
    if ($new_content !== $post['post_content']) {
        $wpdb->update(
            $wpdb->posts,
            ['post_content' => $new_content],
            ['ID' => $post['ID']],
            ['%s'],
            ['%d']
        );
    }
}

echo "Cập nhật thành công!";
?>

Lợi ích của cách này:
✅ Không bị phụ thuộc vào thứ tự thuộc tính trong thẻ <a>
✅ Không làm hỏng HTML nếu có các dấu nháy đơn (') thay vì dấu nháy kép (")
✅ Xử lý chính xác từng phần tử thay vì dùng regex dễ gặp lỗi

Bạn thử test cách này xem sao nhé!
minhminh97, Nguyễn Dũng đã thả tim cho bài viết của minhlvt123 (tổng 2).
Đỗ Minh Quân
Thành viên
Bài viết: 4
Ngày tham gia: 06:35 - 14/6/2018
Đã thả tim: 8 lần
Được thả tim: 12 lần

Re: Cách xóa title khỏi thẻ <a> trong bài viết WordPress

Mình thấy bạn đang sửa trên toàn bộ 7000 bài viết trong một lần chạy. Điều này có thể gây timeout hoặc quá tải database. Mình đề xuất batch processing để tránh vấn đề này.

Thử chia nhỏ xử lý theo từng nhóm 100 bài viết mỗi lần như sau:

Mã: Chọn tất cả

<?php
require_once('wp-load.php');

global $wpdb;
$batch_size = 100;
$offset = 0;

do {
    $posts = $wpdb->get_results("SELECT ID, post_content FROM {$wpdb->posts} WHERE post_content LIKE '%class=\"custom-internal-link\"%' LIMIT $batch_size OFFSET $offset", ARRAY_A);

    foreach ($posts as $post) {
        $new_content = preg_replace('/<a([^>]*?)\s+title="[^"]*"\s+class="custom-internal-link"([^>]*?)>/', '<a\1 class="custom-internal-link"\2>', $post['post_content']);

        if ($new_content !== $post['post_content']) {
            $wpdb->update(
                $wpdb->posts,
                ['post_content' => $new_content],
                ['ID' => $post['ID']],
                ['%s'],
                ['%d']
            );
        }
    }

    $offset += $batch_size;
} while (count($posts) > 0);

echo "Cập nhật thành công theo từng batch!";
?>

Lợi ích của batch processing:
✅ Tránh timeout khi xử lý số lượng lớn bài viết
✅ Giảm tải cho database, tránh làm chậm website
✅ Dễ dàng theo dõi tiến trình

Bạn thử cách này và báo lại xem sao nhé!
minhminh97 đã thả tim cho bài viết của Đỗ Minh Quân (1).
kiennguyenduc95
Thành viên
Bài viết: 3
Ngày tham gia: 10:23 - 16/3/2022
Được thả tim: 3 lần

Re: Cách xóa title khỏi thẻ <a> trong bài viết WordPress

Về SEO: Không có title trong <a> không ảnh hưởng đến SEO. Google dựa vào anchor text (<a>text</a>) hơn là title="".

Tuy nhiên, bạn có thể tận dụng title theo cách tối ưu hơn. Thay vì xóa toàn bộ, bạn có thể kiểm tra nếu title trùng với anchor text thì mới xóa.

Ví dụ:
🚀 Xóa title nếu nó trùng với anchor text:

Mã: Chọn tất cả

if ($link->hasAttribute('title') && $link->nodeValue === $link->getAttribute('title')) {
    $link->removeAttribute('title');
}

🚀 Giữ lại title nếu nó cung cấp thêm thông tin hữu ích.

Nếu muốn tốt cho SEO và trải nghiệm người dùng (UX), bạn nên chỉ xóa những title dư thừa, thay vì xóa tất cả.

Bạn có muốn mình viết đoạn mã đầy đủ cho cách này không?
minhminh97 đã thả tim cho bài viết của kiennguyenduc95 (1).
Tiến Phát
Thành viên
Bài viết: 1
Ngày tham gia: 08:25 - 14/1/2021
Được thả tim: 1 lần

Re: Cách xóa title khỏi thẻ <a> trong bài viết WordPress

Mình có cách SQL đơn giản nhưng không xử lý được tất cả trường hợp. Nếu title có nội dung khác nhau, SQL sẽ khó thao tác linh hoạt.

Bạn có thể thử cách này (chạy trên phpMyAdmin):

Mã: Chọn tất cả

UPDATE wp_posts
SET post_content = REGEXP_REPLACE(
    post_content,
    '<a([^>]*?)\s+title="[^"]*"\s+class="custom-internal-link"([^>]*?)>',
    '<a\1 class="custom-internal-link"\2>'
)
WHERE post_content LIKE '%class="custom-internal-link"%';

❗ Lưu ý:
- Cách này chỉ hoạt động trên MariaDB 10.8 trở lên, bạn dùng MariaDB 10.5 thì không hỗ trợ.
- Nếu database lớn, nên chạy trên bản sao dữ liệu trước, tránh lỗi.

Giải pháp tốt nhất vẫn là PHP!
minhminh97 đã thả tim cho bài viết của Tiến Phát (1).
phpBB Việt Nam
Đã xác thực
Thành viên
Bài viết: 34
Ngày tham gia: 20:37 - 4/1/2022
Đã thả tim: 62 lần
Được thả tim: 150 lần

Re: Cách xóa title khỏi thẻ <a> trong bài viết WordPress

Mình hiểu cách làm của bạn đó là:

- B1: Lưu đoạn mã sau vào file remove_title_links.php và tải lên thư mục gốc WordPress.
- B2: Chạy file PHP bằng cách Truy cập file qua trình duyệt https://yourwebsite.com/remove_title_links.php
- B3: Chờ hoàn thành rồi xóa file để tránh lỗ hổng bảo mật.

Đúng chứ? Với đoạn code này:

Mã: Chọn tất cả

<?php
require_once('wp-load.php'); // Nạp WordPress

global $wpdb;

// Lấy danh sách bài viết có chứa class="custom-internal-link"
$posts = $wpdb->get_results("SELECT ID, post_content FROM {$wpdb->posts} WHERE post_content LIKE '%class=\"custom-internal-link\"%'", ARRAY_A);

foreach ($posts as $post) {
    // Xóa title trong các thẻ <a> có class="custom-internal-link"
    $new_content = preg_replace('/<a([^>]*?)\s+title="[^"]*"\s+class="custom-internal-link"([^>]*?)>/', '<a\1 class="custom-internal-link"\2>', $post['post_content']);
    
    if ($new_content !== $post['post_content']) {
        $wpdb->update(
            $wpdb->posts,
            ['post_content' => $new_content],
            ['ID' => $post['ID']],
            ['%s'],
            ['%d']
        );
    }
}

echo "Cập nhật thành công!";
?>

Việc phải xử lý khoảng 7.000 bài viết, mỗi bài trung bình có khoảng 20 liên kết, tương đương với khoảng 140.000 liên kết cần sửa, có thể không gây ra vấn đề nghiêm trọng về mặt tài nguyên nếu bạn xử lý đúng cách. Tuy nhiên, có một số điểm cần lưu ý:

- Thời gian thực thi: Nếu bạn chạy đoạn mã này qua trình duyệt, thời gian xử lý có thể vượt quá giới hạn max_execution_time của PHP, dẫn đến lỗi timeout. Giải pháp là chạy script qua dòng lệnh (CLI) hoặc tăng giá trị max_execution_time trong PHP khi cần thiết.

- Hiệu suất truy vấn cơ sở dữ liệu: Việc truy xuất và cập nhật 7.000 bài viết có thể tạo tải đáng kể cho cơ sở dữ liệu. Bạn nên cân nhắc chạy script theo từng lô (batch processing) để giảm thiểu rủi ro làm chậm hoặc khóa bảng trong quá trình cập nhật.

- Sao lưu dữ liệu: Trước khi chạy script trên toàn bộ cơ sở dữ liệu, hãy sao lưu dữ liệu để phòng trường hợp có lỗi phát sinh.

- Đa dạng định dạng HTML: Như đã lưu ý, nếu định dạng HTML trong các bài viết không đồng nhất (ví dụ: thứ tự thuộc tính khác nhau hoặc dấu nháy khác nhau), regex có thể bỏ sót một số trường hợp. Cần kiểm tra kỹ dữ liệu mẫu.

Tóm lại, nếu bạn xử lý theo từng lô và chạy qua CLI, thì việc cập nhật 7.000 bài viết với 140.000 liên kết không quá nặng, nhưng hãy đảm bảo sao lưu dữ liệu trước khi thực hiện và kiểm tra script trên một vài bài viết mẫu để đảm bảo hoạt động đúng như mong muốn.
minhminh97, thangnguyen, Nguyễn Dũng đã thả tim cho bài viết của phpBB Việt Nam (tổng 3).
Đã khóa
  • Chủ đề tương tự
    Trả lời
    Lượt xem
    Bài viết mới nhất
Diễn đàn Công nghệ là nơi chia sẻ kiến thức, thảo luận về các xu hướng công nghệ mới, lập trình, bảo mật, trí tuệ nhân tạo và nhiều lĩnh vực khác, kết nối những người yêu thích công nghệ.