Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Thay thế meta tag mặc định từ layout bằng meta tag tùy chỉnh trong view (HTML/PHP)


Vấn đề

Trong các framework MVC (Yii, Laravel, CodeIgniter, v.v.), layout định nghĩa meta tag mặc định. View con cần ghi đè (override) các meta tag này (title, description, og:tags, v.v.).

Giải pháp pattern: Register Meta Tags

Cách phổ biến: Layout đăng ký meta tag mặc định, View ghi đè bằng key tương tự.

Ví dụ với PHP thuần / Framework tùy chỉnh

1. Config mặc định (config/meta.php)

<?php
return [
    'default_meta' => [
        'author' => 'Demo Company',
        'description' => 'Mô tả mặc định cho website',
        'keywords' => 'web, development, html5',
        'og:title' => 'Demo Website',
        'og:description' => 'Mô tả mặc định cho social share',
        'og:image' => '/assets/images/default-og.jpg',
        'og:type' => 'website',
        'twitter:card' => 'summary_large_image',
    ]
];

2. Layout (views/layouts/main.php)

<!DOCTYPE html>
<html lang="vi">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <?php
  // Load config mặc định
  $defaultMeta = require __DIR__ . '/../../config/meta.php';
  $meta = $defaultMeta['default_meta'];
  
  // Merge với meta từ view (nếu có)
  if (isset($this->meta) && is_array($this->meta)) {
      $meta = array_merge($meta, $this->meta);
  }
  
  // Render meta tags
  foreach ($meta as $name => $content) {
      $attr = strpos($name, ':') !== false ? 'property' : 'name';
      echo "<meta $attr=\"$name\" content=\"" . htmlspecialchars($content, ENT_QUOTES, 'UTF-8') . "\">\n";
  }
  ?>
  
  <title><?= htmlspecialchars($this->title ?? 'Default Title') ?></title>
  
  <!-- CSS/JS -->
</head>
<body>
  <?= $content ?>
</body>
</html>

3. View con ghi đè (views/post/view.php)

<?php
// Ghi đè meta tags cho trang này
$this->meta = [
    'description' => 'Chi tiết bài viết: ' . $post->excerpt,
    'keywords' => implode(', ', $post->tags),
    'og:title' => $post->title,
    'og:description' => $post->excerpt,
    'og:image' => $post->thumbnail_url,
    'og:type' => 'article',
    'article:published_time' => $post->created_at->format('c'),
    'article:author' => $post->author->name,
];
$this->title = $post->title;
?>

<article>
  <h1><?= htmlspecialchars($post->title) ?></h1>
  <div><?= $post->content ?></div>
</article>

Cách làm với Yii2 (Framework phổ biến)

<?php
// Layout: views/layouts/main.php
use yii\helpers\Html;

$this->registerMetaTag(['name' => 'author', 'content' => 'Default Author']);
$this->registerMetaTag(['name' => 'description', 'content' => 'Default description']);
$this->registerLinkTag(['rel' => 'canonical', 'href' => Yii::$app->request->absoluteUrl]);
?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
  <meta charset="<?= Yii::$app->charset ?>">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <?= Html::csrfMetaTags() ?>
  <title><?= Html::encode($this->title) ?></title>
  <?php $this->head() ?>
</head>
<body>
  <?php $this->beginBody() ?>
  <?= $content ?>
  <?php $this->endBody() ?>
</body>
</html>
<?php
// View: views/post/view.php
use yii\helpers\Html;

$this->title = $post->title;

// Ghi đè meta tags
$this->registerMetaTag([
    'name' => 'description', 
    'content' => $post->excerpt
], 'description'); // Key 'description' để ghi đè tag cùng name

$this->registerMetaTag([
    'property' => 'og:title', 
    'content' => $post->title
], 'og:title');

$this->registerMetaTag([
    'property' => 'og:description', 
    'content' => $post->excerpt
], 'og:description');

$this->registerMetaTag([
    'property' => 'og:image', 
    'content' => $post->thumbnailUrl
], 'og:image');

$this->registerLinkTag([
    'rel' => 'canonical', 
    'href' => $post->canonicalUrl
], 'canonical');
?>

Cách làm với Laravel (Blade)

<!-- layouts/app.blade.php -->
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  
  <!-- Default meta -->
  <meta name="description" content="{{ config('app.default_description') }}">
  <meta property="og:title" content="{{ config('app.name') }}">
  
  <!-- Override từ view -->
  @stack('meta')
  
  <title>@yield('title', config('app.name'))</title>
</head>
<body>
  @yield('content')
</body>
</html>
<!-- views/post/show.blade.php -->
@extends('layouts.app')

@section('title', $post->title)

@push('meta')
  <meta name="description" content="{{ $post->excerpt }}">
  <meta property="og:title" content="{{ $post->title }}">
  <meta property="og:description" content="{{ $post->excerpt }}">
  <meta property="og:image" content="{{ $post->thumbnail_url }}">
  <meta property="og:type" content="article">
  <link rel="canonical" href="{{ $post->canonical_url }}">
@endpush

@section('content')
  <article>
    <h1>{{ $post->title }}</h1>
    <div>{{ $post->content }}</div>
  </article>
@endsection

Best Practices

  • Key-based override: Dùng key (name/property) để xác định tag nào bị ghi đè
  • Merge strategy: Deep merge cho object, replace cho string
  • Validation: Sanitize output (htmlspecialchars) để tránh XSS
  • Canonical URL: Luôn set canonical để tránh duplicate content SEO
  • Open Graph / Twitter Card: Đầy đủ cho social sharing