Lập trình với API
Lập trình với APIBổ sung WP-CLI

Bổ sung WP-CLI

WP-CLI là công cụ dòng lệnh để tương tác với WordPress, giúp chúng ta tự động hóa các tác vụ. Nó cho phép cài đặt site mới, tạo hoặc cập nhật bài viết, kích hoạt plugin, chỉnh sửa các tùy chọn và nhiều tính năng khác.

Các lệnh WP-CLI có thể được lồng vào nhau:

  1. Thực thi một lệnh WP-CLI trả về ID của một tài nguyên
  2. Đưa ID đó vào một lệnh WP-CLI khác để thực hiện thao tác trên tài nguyên đó

Ví dụ, script sau tìm ID của bài viết có slug nhất định rồi cập nhật meta của nó:

wp post meta set $(wp post list --name="hello-world" --format=ids) _wp_page_template about.php

Script này liên tục tạo một mục menu và đặt ID của nó làm cha của một mục menu mới khác, qua đó định nghĩa phân cấp của chúng ("Most ancestor menu item" > "Parent menu item" > "Child menu item"):

wp menu item add-custom bottom-menu "Child menu item" https://bbc.com --parent-id=$(wp menu item add-post bottom-menu 1 --title="Parent menu item" --parent-id=$(wp menu item add-post bottom-menu 1 --title="Most ancestor menu item" --porcelain) --porcelain)

Gato GraphQL có thể mở rộng khả năng tìm kiếm dữ liệu của WordPress. Vì vậy, chúng ta cũng có thể dùng Gato GraphQL để tìm dữ liệu cần thiết và đưa dữ liệu đó vào WP-CLI.

Các queries dưới đây sẽ minh họa cách thực hiện điều đó.

Thực thi một GraphQL query từ terminal

Hãy dùng một GraphQL query để tìm người dùng có ngôn ngữ địa phương tiếng Tây Ban Nha, và thực thi một lệnh WP-CLI trên người dùng đó.

Đầu tiên, chúng ta giới hạn kết quả chỉ 1 người dùng (thông qua pagination: { limit: 1 }):

query {
  users(
    filter: {
      metaQuery: {
        key: "locale",
        compareBy: {
          stringValue: {
            value: "es_[A-Z]+"
            operator: REGEXP
          }
        }
      }
    },
    pagination: {
      limit: 1
    }
  ) {
    id
    name
    locale: metaValue(key: "locale")
  }
}

Trong terminal, chúng ta có thể dùng curl (hoặc công cụ tương tự) để thực thi một query đối với GraphQL server, truyền vào các dữ liệu sau:

  • Thực thi phương thức POST
  • Kiểu nội dung chấp nhận là application/json
  • Body là một dictionary với mục "query" và GraphQL query (và nếu cần, cả các mục "variables""operationName")
  • Chuỗi query phải được định dạng: Tất cả dấu " phải được escape thành \", và dấu xuống dòng phải được thay bằng \n
  • Trỏ đến URL endpoint của Gato GraphQL (endpoint đơn hoặc endpoint tùy chỉnh)
curl \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"query": "query {\n  users(\n    filter: {\n      metaQuery: {\n        key: \"locale\",\n        compareBy: {\n          stringValue: {\n            value: \"es_[A-Z]+\"\n            operator: REGEXP\n          }\n        }\n      }\n    },\n    pagination: {\n      limit: 1\n    }\n  ) {\n    id\n    name\n    locale: metaValue(key: \"locale\")\n  }\n}"}' \
  https://mysite.com/graphql/

Kết quả sẽ được in trực tiếp ra terminal:

{"data":{"users":[{"id":3,"name":"Subscriber Bennett","locale":"es_AR"}]}}

Trích xuất ID từ phản hồi GraphQL

Tương tự như dùng --field=ID, --format=ids hay --porcelain trong WP-CLI, chúng ta cần tìm cách trích xuất đúng phần dữ liệu cần thiết từ phản hồi GraphQL. Trong ví dụ này, đó là ID người dùng.

Chúng ta gán phản hồi GraphQL vào một biến môi trường (chẳng hạn GRAPHQL_RESPONSE), và đặt alias cụ thể cho ID người dùng (chẳng hạn spanishLocaleUserID):

GRAPHQL_RESPONSE=$(curl \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"query": "query {\n  users(\n    filter: {\n      metaQuery: {\n        key: \"locale\",\n        compareBy: {\n          stringValue: {\n            value: \"es_[A-Z]+\"\n            operator: REGEXP\n          }\n        }\n      }\n    },\n    pagination: {\n      limit: 1\n    }\n  ) {\n    spanishLocaleUserID: id\n    name\n    locale: metaValue(key: \"locale\")\n  }\n}"}' \
  https://mysite.com/graphql/)

Thực thi echo $GRAPHQL_RESPONSE để xem phản hồi:

{"data":{"users":[{"spanishLocaleUserID":3,"name":"Subscriber Bennett","locale":"es_AR"}]}}

Tiếp theo, chúng ta thực thi grep với regex khớp với mẫu "spanishLocaleUserID":{ID}, và trích xuất ID vào biến môi trường SPANISH_LOCALE_USER_ID:

SPANISH_LOCALE_USER_ID=$(echo $GRAPHQL_RESPONSE \
  | grep -E -o '"spanishLocaleUserID\":(\d+)' \
  | cut -d':' -f2- | cut -d'"' -f2- | rev | cut -d'"' -f2- | rev)

Bây giờ chúng ta có thể đưa giá trị của biến này vào WP-CLI:

wp user update "$(echo $SPANISH_LOCALE_USER_ID)" --locale=fr_FR

Làm cho GraphQL query dễ đọc hơn

Khi định dạng GraphQL query để nhập vào curl, nó trở nên khó đọc.

Một giải pháp là áp dụng các phép biến đổi bằng lệnh bash như trsed:

GRAPHQL_QUERY='
  query {
    users(
      filter: {
        metaQuery: {
          key: "locale",
          compareBy: {
            stringValue: {
              value: "es_[A-Z]+"
              operator: REGEXP
            }
          }
        }
      },
      pagination: {
        limit: 1
      }
    ) {
      spanishLocaleUserID: id
      name
      locale: metaValue(key: "locale")
    }
  }
'
GRAPHQL_BODY="{\"query\": \"$(echo $GRAPHQL_QUERY | tr '\n' ' ' | sed 's/"/\\"/g')\"}"
GRAPHQL_RESPONSE=$(curl \
  -X POST \
  -H "Content-Type: application/json" \
  -d $GRAPHQL_BODY \
  https://mysite.com/graphql/)

Thêm tô sáng cú pháp cho GraphQL query

Một bước cải tiến tiếp theo so với bước trước là đặt GraphQL query trong một file .gql riêng biệt, sau đó có thể chỉnh sửa bằng editor (chẳng hạn VSCode) và tận dụng tính năng tô sáng cú pháp của nó:

# This query is stored in file "find-user-with-spanish-locale.gql"
query {
  users(
    filter: {
      metaQuery: {
        key: "locale",
        compareBy: {
          stringValue: {
            value: "es_[A-Z]+"
            operator: REGEXP
          }
        }
      }
    },
    pagination: {
      limit: 1
    }
  ) {
    spanishLocaleUserID: id
    name
    locale: metaValue(key: "locale")
  }
}

Sau đó, chúng ta đọc nội dung file này bằng cat:

GRAPHQL_QUERY=$(cat find-user-with-spanish-locale.gql)
GRAPHQL_BODY="{\"query\": \"$(echo $GRAPHQL_QUERY | tr '\n' ' ' | sed 's/"/\\"/g')\"}"
GRAPHQL_RESPONSE=$(curl \
  -X POST \
  -H "Content-Type: application/json" \
  -d $GRAPHQL_BODY \
  https://mysite.com/graphql/)