Sửa lỗi Mixed Content WordPress sau khi cài SSL/HTTPS

beginner📝 WordPress2026-05-31| WordPress 5.x–6.x, Apache/Nginx, mọi hosting đã cài SSL certificate

Error Message

Mixed Content: The page at 'https://example.com' was loaded over HTTPS, but requested an insecure stylesheet 'http://example.com/wp-content/themes/style.css'
#wordpress#ssl#https#mixed-content

Lỗi Gặp Phải

Sau khi cài đặt chứng chỉ SSL và chuyển trang WordPress sang HTTPS, console trình duyệt hiển thị các cảnh báo như sau:

Mixed Content: The page at 'https://example.com' was loaded over HTTPS,
but requested an insecure stylesheet 'http://example.com/wp-content/themes/style.css'

Mixed Content: The page at 'https://example.com' was loaded over HTTPS,
but requested an insecure image 'http://example.com/wp-content/uploads/2024/01/photo.jpg'

Trình duyệt chặn các tài nguyên đó, biểu tượng ổ khóa biến mất hoặc hiển thị tam giác cảnh báo, và một số phần trên trang bị hỏng.

Nguyên Nhân Gốc Rễ

Mọi URL mà WordPress lưu — địa chỉ trang, đường dẫn ảnh, liên kết bài viết — đều được ghi vào cơ sở dữ liệu dưới dạng http:// tại thời điểm cài đặt. Khi chuyển sang HTTPS sau đó, các mục đó không tự động cập nhật.

Bản thân trang tải qua https://, nhưng các tài nguyên nhúng vẫn trỏ đến http://. Trình duyệt chặn các tài nguyên không an toàn đó trên trang bảo mật. Đó chính là lỗi mixed content.

Những URL cũ này ẩn ở ba nơi:

  • Cơ sở dữ liệu WordPress — wp_options (URL trang, URL home) và wp_posts (nội dung bài viết với URL được mã hóa cứng)
  • wp-config.php — nếu bạn đã mã hóa cứng URL ở đó
  • Các file theme và nội dung page builder chứa URL tuyệt đối

Cách Sửa 1: Cập Nhật URL WordPress và Home Trong Cài Đặt

Bắt đầu từ đây — đây là nguyên nhân phổ biến nhất. Vào WordPress Admin → Cài đặt → Chung và thay đổi cả hai trường:

WordPress Address (URL): https://example.com
Site Address (URL):      https://example.com

Nhấn Lưu thay đổi. WordPress sẽ đăng xuất bạn — đăng nhập lại và kiểm tra xem biểu tượng ổ khóa đã sạch chưa.

Bị khóa vì vòng lặp redirect? Hãy đặt URL trực tiếp trong wp-config.php thay thế:

define('WP_HOME', 'https://example.com');
define('WP_SITEURL', 'https://example.com');

Cách Sửa 2: Thay Thế Toàn Bộ URL http:// Trong Cơ Sở Dữ Liệu (WP-CLI — Khuyến Nghị)

Cách sửa trong Cài đặt chỉ cập nhật hai hàng. Một trang có nội dung cả năm có thể dễ dàng có 500–2.000 liên kết http:// được mã hóa cứng rải rác trong bài viết, widget và các giá trị tùy chọn. Lệnh search-replace của WP-CLI xử lý tất cả chúng trong một lần:

# Chạy thử trước — xem những gì sẽ thay đổi mà không động vào dữ liệu
wp search-replace 'http://example.com' 'https://example.com' --dry-run

# Thực hiện thay thế thật sự
wp search-replace 'http://example.com' 'https://example.com' \
  --skip-columns=guid \
  --report-changed-only

# Nếu trang của bạn nằm trong thư mục con, hãy thay thế cả đường dẫn đó
wp search-replace 'http://example.com/blog' 'https://example.com/blog' \
  --skip-columns=guid

Tham số --skip-columns=guid giữ nguyên GUID của bài viết. Thay đổi chúng và các RSS reader theo dõi danh tính bài viết bằng GUID sẽ hiển thị lại các bài cũ như bài mới.

Xóa cache sau khi chạy search-replace:

wp cache flush
wp rewrite flush

Cách Sửa 3: Dùng Plugin Really Simple SSL (Không Cần Truy Cập Server)

Không có quyền truy cập SSH? Hãy cài plugin Really Simple SSL từ thư mục plugin WordPress. Sau khi kích hoạt, plugin sẽ:

  • Tự động cập nhật URL WordPress/Home
  • Thêm chuyển hướng 301 từ HTTP sang HTTPS
  • Sửa mixed content bằng cách viết lại URL ngay lập tức thông qua output buffering

Vào Cài đặt → SSL và nhấn Go ahead, activate SSL!

Plugin hoạt động được, nhưng output buffering thêm khoảng 10–30ms vào mỗi lần render trang. Sau khi đã dọn sạch URL trong cơ sở dữ liệu theo cách thủ công, hãy vô hiệu hóa plugin — việc viết lại URL lúc chạy trở thành chi phí không cần thiết.

Cách Sửa 4: Buộc Chuyển Hướng HTTPS Trong .htaccess (Apache)

Sửa đúng URL trong cơ sở dữ liệu không ngăn được người dùng gõ trực tiếp http:// vào thanh địa chỉ. Hãy thêm chuyển hướng ở cấp server. Đặt đoạn này lên đầu file .htaccess, trước block WordPress:

# Buộc HTTPS
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{HTTPS} off
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>

# BEGIN WordPress
# ... các quy tắc WordPress hiện có bên dưới ...

Với Nginx, thêm đoạn này vào server block của bạn:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

Cách Sửa 5: Tìm Các Nguồn Mixed Content Còn Lại

Cơ sở dữ liệu đã sạch? Vẫn có thể còn những URL được mã hóa cứng trực tiếp trong file PHP của theme hoặc code plugin. Browser DevTools giúp tìm chúng nhanh chóng:

  • Mở Chrome DevTools → tab Console
  • Tìm các dòng bắt đầu bằng Mixed Content: — URL ở cuối cho bạn biết chính xác file nào đang tải qua HTTP
  • Chuyển sang tab Network, lọc theo http để xem tất cả các yêu cầu không an toàn cùng lúc

Khi đã biết file, hãy tìm kiếm trong source của theme hoặc plugin:

# Tìm kiếm http:// được mã hóa cứng trong theme đang kích hoạt
grep -r 'http://' /var/www/html/wp-content/themes/your-theme/ --include='*.php'

# Kiểm tra cả child theme
grep -r 'http://' /var/www/html/wp-content/themes/your-child-theme/ --include='*.php'

Thay thế mọi http://example.com được mã hóa cứng bằng https://example.com hoặc URL tương đối như /wp-content/themes/....

Xác Nhận Đã Sửa Thành Công

Ba kiểm tra nhanh để xác nhận bạn đã hoàn thành:

  • Biểu tượng ổ khóa trên trình duyệt: Biểu tượng ổ khóa phải hiển thị rõ ràng không có tam giác cảnh báo. Nhấn vào đó và xác nhận "Connection is secure".
  • Kiểm tra Console: Mở DevTools → Console. Không có dòng nào bắt đầu bằng "Mixed Content:" nghĩa là đã sạch.
  • Công cụ kiểm tra trực tuyến: Chạy URL của bạn qua whynopadlock.com hoặc SSL Labs — chúng quét tất cả tài nguyên trang và đánh dấu mọi tài nguyên HTTP còn lại.
# Xác minh URL trong cơ sở dữ liệu đã cập nhật đúng qua WP-CLI
wp option get siteurl
wp option get home
# Cả hai phải trả về https://example.com

Phòng Ngừa

Cách tiếp cận sạch nhất: cài SSL trước khi đăng bất kỳ bài viết nào. Không cần migration, không cần search-replace, không cần dọn dẹp.

Di chuyển trang hiện có? Chạy WP-CLI search-replace ngay khi bạn chuyển DNS sang HTTPS — trước khi có nội dung mới nào được đăng.

Thêm đoạn này vào wp-config.php như một lưới an toàn vĩnh viễn:

define('FORCE_SSL_ADMIN', true);
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

Block thứ hai xử lý các reverse proxy. Cloudflare, load balancer và hầu hết các hosting được quản lý đều chấm dứt SSL tại edge mạng — lưu lượng giữa proxy và server thực của bạn đi qua HTTP thuần. Nếu không có đoạn code này, WordPress thấy kết nối HTTP nội bộ đó và xử lý sai yêu cầu là không an toàn, điều này làm hỏng các chuyển hướng trong trang quản trị và luồng đăng nhập.

Related Error Notes