Chuyển đến nội dung chính

Umbraco 13: Xây dựng menu từ Content Tree - Day 3.1

Ở các phần trước, chúng ta đã tạo cấu trúc nội dung cho website nhà sách trong Umbraco CMS. Website hiện có một node gốc Bookstore Home và các danh mục như Lịch sử và Triết học.

Tuy nhiên, việc tạo danh mục trong Backoffice mới chỉ là bước đầu. Khi xây dựng website thực tế, chúng ta cần lấy các danh mục này để tạo menu điều hướng. Nếu tên danh mục thay đổi hoặc biên tập viên thêm một danh mục mới, menu nên phản ánh những thay đổi đó mà không cần lập trình viên sửa code mỗi lần.

Trong bài thực hành này, chúng ta sẽ tìm hiểu cách sử dụng Content Tree và Content Delivery API để lấy dữ liệu danh mục, sau đó xác định cấu trúc JSON phù hợp cho menu.

Mục tiêu của bài viết:

  • Hiểu mối liên hệ giữa Content Tree và menu điều hướng.
  • Lấy các node con của Bookstore Home bằng Content Delivery API.
  • Đọc JSON response và xác định dữ liệu cần dùng cho menu.
  • Phân biệt dữ liệu API trả về với cấu trúc menu mà frontend cần.
  • Chuẩn bị dữ liệu để tích hợp menu vào Next.js ở phần tiếp theo.

1. Từ Content Tree đến menu website

1.1. Cấu trúc nội dung trong Umbraco

Giả sử Content Tree của website nhà sách có cấu trúc như sau:

Content
└── Bookstore Home
    ├── Lịch sử
    └── Triết học

Trong đó:

  • Bookstore Home: node gốc của website nhà sách.
  • Lịch sử: danh mục sách về lịch sử.
  • Triết học: danh mục sách về triết học.

Content Tree biểu diễn quan hệ cha–con giữa các content item. Đây là cấu trúc mà chúng ta có thể sử dụng để xác định những mục sẽ xuất hiện trên menu.

1.2. Menu trên website sẽ trông như thế nào?

Với cấu trúc hiện tại, menu mong muốn có thể đơn giản như sau:

Nhà sách
├── Lịch sử
└── Triết học

Khi người dùng nhấn vào Lịch sử, website sẽ điều hướng đến trang danh mục Lịch sử. Tương tự, mục Triết học sẽ dẫn đến trang danh mục tương ứng.

Điểm quan trọng là tên và đường dẫn của menu nên được lấy từ dữ liệu nội dung, thay vì viết cố định trực tiếp trong frontend.

1.3. Kiến trúc dữ liệu

flowchart TD A["Biên tập viên"] --> B["Umbraco Backoffice"] B --> C["Content Tree"] C --> D["Content Delivery API"] D --> E["JSON Response"] E --> F["Ánh xạ thành dữ liệu menu"] F --> G["Frontend Next.js"] G --> H["Menu trên website"]

Trong kiến trúc này, Umbraco chịu trách nhiệm quản lý nội dung. Content Delivery API cung cấp nội dung đã publish dưới dạng JSON. Frontend sử dụng JSON để xây dựng menu và quyết định cách hiển thị.

2. Chuẩn bị nội dung trong Backoffice

Trước khi gọi API, hãy mở Umbraco Backoffice và kiểm tra cấu trúc Content Tree.

  1. Mở node Bookstore Home.
  2. Xác nhận node Lịch sử và Triết học nằm bên dưới node này.
  3. Kiểm tra các node cần hiển thị trên menu đã được publish.
  4. Kiểm tra đường dẫn thực tế của từng node trong phần thông tin của content item.

Lưu ý: tên hiển thị trong Backoffice có thể khác URL segment và alias của Document Type. Không nên tự suy đoán URL từ tên tiếng Việt; hãy kiểm tra route thực tế trong project.

3. Lấy các node con bằng Content Delivery API

3.1. Endpoint truy vấn nhiều content item

Content Delivery API của Umbraco 13 cung cấp endpoint truy vấn danh sách content item:

GET /umbraco/delivery/api/v2/content

Endpoint này hỗ trợ tham số fetch để truy vấn nội dung dựa trên cấu trúc Content Tree. Để lấy các node con trực tiếp của node gốc (Trang chủ), chúng ta sử dụng selector children: kết hợp với GUID hoặc Path:

  • Truy vấn theo GUID (Khuyên dùng - Chuẩn xác nhất):
    GET /umbraco/delivery/api/v2/content?fetch=children:256048db-162d-4cc7-b7e3-c4537fb970bd
  • Truy vấn theo Path (Trang chủ có route /):
    GET /umbraco/delivery/api/v2/content?fetch=children:/

Lưu ý: GUID của node trang chủ (256048db-162d-4cc7-b7e3-c4537fb970bd) có thể lấy trong tab Info (Thông tin) của node Bookstore Home ở Umbraco Backoffice. Tham số fetch=children:... chỉ lấy các node con trực tiếp cấp 1, không tự động lấy toàn bộ cây con nhiều cấp.

3.2. Thực hành gọi API trên Swagger UI

Mở Swagger UI của ứng dụng Umbraco trong môi trường Development:

https://localhost:44366/umbraco/swagger

Các bước thực hiện:

  1. Tìm và mở endpoint GET /umbraco/delivery/api/v2/content.
  2. Nhấn nút Try it out.
  3. Tại tham số fetch:
    • Chọn dropdown mẫu Examples → chọn Select all children of a node by id (hoặc by path).
    • Nhập giá trị thực tế vào ô input bên dưới: children:256048db-162d-4cc7-b7e3-c4537fb970bd (hoặc children:/).
    • Lưu ý: Khi bạn tự gõ hoặc chỉnh sửa nội dung ô input, dropdown Examples sẽ tự động chuyển nhãn thành [Modified value] — đây là phản hồi bình thường của Swagger UI xác nhận giá trị tùy chỉnh của bạn đã được ghi nhận.
  4. Nhập Api-Key vào header nếu project có yêu cầu xác thực.
  5. Nhấn Execute và kiểm tra HTTP status cùng JSON response.

Cách kiểm tra kết quả: Nếu API trả về mã HTTP 200, kiểm tra mảng "items" trong JSON response. Bạn sẽ thấy danh sách các danh mục con trực tiếp (như Lịch sử, Triết học) nằm bên dưới node Trang chủ.

4. Đọc JSON response

4.1. Ví dụ response minh họa

Giả sử API trả về danh sách content item có cấu trúc tương tự ví dụ rút gọn dưới đây:

{
  "total": 2,
  "items": [
    {
      "contentType": "bookCategory",
      "name": "Lịch sử",
      "route": {
        "path": "/lich-su/"
      },
      "id": "00000000-0000-0000-0000-000000000001",
      "properties": {
        "categoryTitle": "Lịch sử"
      }
    },
    {
      "contentType": "bookCategory",
      "name": "Triết học",
      "route": {
        "path": "/triet-hoc/"
      },
      "id": "00000000-0000-0000-0000-000000000002",
      "properties": {
        "categoryTitle": "Triết học"
      }
    }
  ]
}

Đây là JSON giả lập để minh họa cách đọc dữ liệu, không phải response nguyên bản được bảo đảm của Umbraco 13. Tên trường, đường dẫn, GUID, alias và giá trị property trong project của bạn có thể khác. Hãy dùng JSON thực tế thu được từ Swagger để triển khai.

4.2. Những trường cần quan tâm

Trường Ý nghĩa Sử dụng cho menu
name Tên content item. Làm nhãn menu nếu phù hợp.
route.path Đường dẫn của content item. Dùng làm cơ sở tạo URL điều hướng.
contentType Alias của Document Type. Giúp phân biệt loại nội dung.
id GUID của content item. Hữu ích khi cần tham chiếu đến item.
properties Các property được trả về. Có thể cung cấp tên menu hoặc tùy chọn hiển thị nếu được cấu hình.

Không nên giả định rằng mọi Document Type đều có property categoryTitle. Nếu project chỉ sử dụng tên node trong Backoffice, trường name có thể đã đủ cho menu cơ bản.

5. Từ JSON API đến cấu trúc menu

5.1. Không nên dùng nguyên JSON API làm model giao diện

Response của Content Delivery API được thiết kế để biểu diễn content item của Umbraco. Trong khi đó, menu frontend thường chỉ cần một số thông tin như nhãn, URL và các mục con.

Vì vậy, chúng ta có thể ánh xạ dữ liệu API sang một cấu trúc menu đơn giản hơn:

[
  {
    "label": "Lịch sử",
    "href": "/lich-su/",
    "children": []
  },
  {
    "label": "Triết học",
    "href": "/triet-hoc/",
    "children": []
  }
]

Cấu trúc này chỉ là model dành cho frontend. Nó không phải format mặc định mà Content Delivery API trả về.

5.2. Quy tắc ánh xạ dữ liệu

Khi viết hàm chuyển JSON API thành dữ liệu menu, ta có thể áp dụng các quy tắc sau:

  • label lấy từ name hoặc một property dành riêng cho nhãn menu.
  • href lấy từ route thực tế của content item.
  • children chứa các mục menu con nếu ứng dụng đã truy vấn và ánh xạ những node đó.
  • Chỉ đưa vào menu những content item đáp ứng quy tắc hiển thị của website.

Ví dụ, nếu sau này Bookstore Home có thêm danh mục Văn học và danh mục đó được publish, menu có thể cập nhật theo dữ liệu mới mà không cần viết thêm một mục menu cố định trong frontend.

Tuy nhiên, để điều này hoạt động, ứng dụng cần truy vấn và ánh xạ lại dữ liệu phù hợp. Chỉ tạo một node mới trong Backoffice không có nghĩa là mọi frontend sẽ tự cập nhật ngay lập tức; kết quả còn phụ thuộc vào cache, cơ chế fetch và thời điểm build của ứng dụng.

6. Xử lý menu nhiều cấp

Hiện tại website chỉ có hai danh mục cấp đầu tiên. Trong tương lai, Content Tree có thể mở rộng như sau:

Bookstore Home
├── Lịch sử
│   ├── Lịch sử Việt Nam
│   └── Lịch sử Trung Quốc
└── Triết học
    ├── Triết học phương Đông
    └── Triết học phương Tây

Để xây dựng menu nhiều cấp, cần lấy thêm các node con của từng danh mục hoặc sử dụng một truy vấn phù hợp để lấy các node descendants, sau đó xây dựng quan hệ cha–con trong model menu.

Không nên mặc định rằng một request lấy Bookstore Home sẽ tự động trả về toàn bộ cây con theo dạng đệ quy. Hãy kiểm tra response và chọn cách truy vấn phù hợp với yêu cầu thực tế.

Đối với website lớn, cũng cần cân nhắc số lượng request, giới hạn dữ liệu trả về, phân trang, cache và cách xử lý các danh mục không được phép hiển thị trên menu.

7. Những vấn đề cần lưu ý

7.1. Node chưa publish

Content Delivery API chủ yếu cung cấp nội dung đã publish. Nếu một danh mục mới chỉ được lưu nháp, nó có thể không xuất hiện trong response thông thường.

7.2. Sai đường dẫn hoặc GUID

Tham số fetch cần tham chiếu đúng content item. Nếu kết quả rỗng hoặc API trả lỗi, hãy kiểm tra lại đường dẫn hoặc GUID của Bookstore Home.

7.3. API Key

Nếu Delivery API đã được cấu hình để yêu cầu API Key, request phải gửi đúng header Api-Key. Không đưa API Key bí mật vào JavaScript chạy trên trình duyệt hoặc biến môi trường có tiền tố NEXT_PUBLIC_. Khi tích hợp với Next.js, hãy xử lý khóa bí mật ở phía server.

7.4. API trả về dữ liệu nhưng menu không hiển thị

Nếu JSON đã có dữ liệu nhưng menu chưa hiển thị, cần kiểm tra riêng phần ánh xạ trường dữ liệu, URL, điều kiện lọc và code render của frontend.

Hãy kiểm tra API độc lập trước. Việc này giúp phân biệt lỗi phía Umbraco với lỗi trong ứng dụng frontend.

8. Bài tập thực hành

Bài tập 1: Lấy danh mục cấp đầu tiên

  • Gọi endpoint Content Delivery API với selector fetch=children cho Bookstore Home.
  • Kiểm tra response có các node Lịch sử và Triết học hay không.
  • Ghi lại tên node, route và content type alias thực tế.

Bài tập 2: Thiết kế model menu

Từ JSON thực tế, tự tạo một JSON riêng chỉ chứa những trường cần thiết cho menu, chẳng hạn:

[
  {
    "label": "Tên danh mục",
    "href": "/duong-dan-danh-muc/",
    "children": []
  }
]

Thay các giá trị ví dụ bằng dữ liệu thực tế của project.

Bài tập 3: Kiểm tra khả năng mở rộng

  • Thêm một danh mục thử nghiệm trong môi trường Development.
  • Publish danh mục đó.
  • Gọi lại API và kiểm tra danh sách node con.
  • Xác định các bước cần thiết để model menu nhận được danh mục mới.

9. Checklist hoàn thành Day 3.1

  • Hiểu mối liên hệ giữa Content Tree và menu điều hướng.
  • Biết cách truy vấn các node con bằng Content Delivery API.
  • Đọc được tên node, route và content type alias trong JSON.
  • Phân biệt JSON response của Umbraco với model menu của frontend.
  • Biết rằng menu nhiều cấp cần xử lý thêm quan hệ cha–con.
  • Biết kiểm tra trạng thái publish, API Key và lỗi truy vấn.

10. Tổng kết và bước tiếp theo

Qua bài thực hành này, chúng ta đã kết nối ba khái niệm: Content Tree, Content Delivery API và menu điều hướng.

Ba ý quan trọng cần ghi nhớ:

  1. Content Tree tổ chức các content item theo quan hệ cha–con.
  2. Content Delivery API cung cấp dữ liệu nội dung dưới dạng JSON; selector children có thể được dùng để truy vấn các node con trực tiếp.
  3. Frontend chịu trách nhiệm chuyển JSON thành model menu và render giao diện.

Ở phần tiếp theo, chúng ta sẽ kết nối Umbraco với Next.js, gọi Content Delivery API từ phía server và sử dụng dữ liệu nhận được để hiển thị menu trên website. Đây là bước chuyển từ việc kiểm tra API độc lập sang xây dựng một ứng dụng Headless CMS hoàn chỉnh hơn.

Tài liệu tham khảo

Nhận xét

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.