Blog

  • ESNext #2: 블록 제작

    블록과 블록 에디터 환경에서 자유자재로 원하는 기능을 만들고 싶다.

    기존에는 페이지를 제작할때 주로 숏코드를 사용했다. 물론 숏코드는 여전히 유용하고 유효하다. 페이지의 모든 내용이 고정되며 페이지 전반에 어떤 특정 기능을 구현해야 할 때, 그리고 그 때 서버 사이드 스크립트가 더 편리할 때는 그렇게 작성하는 것도 편리하다.

    그러나 엘레멘터 같은 비주얼 빌더들이 워드프레스 제작 환경에는 사실상 표준이 되어가고 있고, 구텐베르크 또한 마찬가지다. 더구나 엘레멘터는 구텐베르크의 블록또한 가져와 사용할 수 있도록 호환성마저 제공하기도 한다. 아무튼 이제는 블록 에디터를 개발에 활용해야 할 때다.

    블록 에디터에 익숙해지기 위해 우선 이 버전의 hello, world! 부터 해 보자. 이것도 이전과 마찬가지로 github 리포지터리에 코드를 커밋해 두었다.

    블록 등록 절차

    커스텀 블록을 사용하려면 크게 두 가지 과정을 거치면 된다. 코어에 블록을 등록한다. 그리고 그 블록이 어떻게 동작할지 정의한다. 각각의 역할은 PHP와 JS 에서 나눠 구현된다.

    대략 API 함수를 보면 PHP 측에서 등록은 자바스크립트 의존성, 인큐잉의 순서 같은 올바른 스크립트 삽입을 위한 코드인 것 같다. 반면 JS 는 등록된 커스텀 블록이 에디터에서, 프론트엔드에서 어떤 동작을 취하는지에 대한 동작을 상세하게 지정하는 성격이 강하다. 뭐, 사실 당연한 말인 것 같다.

    보통 워드프레스 스크립트를 등록(register), 인큐(enqueue) 처리할 때 ‘init’, ‘wp_enqueue_scripts’, ‘admin_enqueue_scripts’ 세 훅을 사용한다. 한편 블록 에디터를 위한 ‘enqueue_block_editor_assets’ 훅이 추가되었다. 이 훅은 ‘init’ 보다는 뒤에, 그러나 ‘wp_enqueue_scripts’ 보다는 앞에 불릴 것이다. 보통 예제에서는 init을 많이 사용하는데 상황에 따라 적절히 선택하면 될 것 같다.

    PHP 사이드에서 블록 등록 절차

    1. wp_register_script()를 호출해 블록을 등록하는 스크립트를 등록 처리한다.
      • 이 때 빌드된 디렉토리 쪽에 *.asset.php 파일이 있을 것이다. 이 파일은 하나의 배열을 리턴한다. 이 배열에는 해당 스크립트이 의존성 목록과 버전 정보가 담겨있다.
      • wp-script가 작성된 코드를 분석해 적절히 의존성을 결정해준 것이다.
      • 버전은 매번 변경되는 코드가 캐싱되지 않도록 하는 목적이 크다.
    2. register_block_type() 함수를 사용해 블록을 코어에 등록시킨다.
      • 첫번째 인자로 쓰는 블록 이름은 소문자로만, 케밥 케이스로, 또 ‘{네임스페이스}/{블록 이름}‘ 식으로 작명하도록 한다. 네임스페이스는 플러그인 고유의 구분자로, 블록 이름은 블록의 구분자로 생각할 수 있다.
      • 두번째 인자에 배열이 들어가는데 ‘editor_script’는 반드시 지정한다. 이 값으로 1단계에서 등록한 스크립트의 핸들을 입력한다.
    3. 추가적으로 번역 파일이 있다면 wp_set_script_translations() 함수를 사용해 등록한다.
      • 번역 파일의 이름은 {텍스트도메인}-{언어 코드}-{핸들}.json 이다. 혹은 {텍스트도메인}-{언어 코드}-{해시}.json 로도 사용할 수 있다.
      • 첫번째 인자는 스크립트 핸들, 두번째는 텍스트 도메인, 세번째는 번역 파일이 있는 디렉토리의 절대경로이다.
      • .json 파일을 생성하는 것이 고역일 수 있다. 그러나 이후 설명할 WP CLI를 사용하면 어렵지 않다.

    JS 사이드에서 블록 등록 절차

    아주 기본적인 함수를 불러오는 것(import … from …)부터 시작하자.

    • ‘@wordpress/blocks’ 패키지에서 ‘registerBlockType’ 함수
    • ‘@wordpress/i18n’에서 번역을 위한 ‘__’ 함수를 불러온다.

    이 두 패키지를 devDependencies에 등록시키자. 그리고 가져온 registerBlockType 함수를 호출하면 된다.

    • 첫번째 인자는 이 블록의 이름이다. PHP의 register_block_type() 함수에서 썼던 것과 동일한 이름, 즉 ‘{네임스페이스}/{블록 이름}‘을 입력해야 한다.
    • 두번째 인자는 이 블록이 어떤 속성을 가지는지 상세하게 정의하는 부분이다. 이 부분은 많은 설명이 필요하며 여기서는 다 다룰 수가 없다. 차후 개발 문서를 자주 방문하면서 숙련도를 쌓아야 할 것 같다.
    • 예제를 위해 사용한 속성은 총 5개인데 아래에서 간단히 설명한다.
      • title: 블록의 제목. 문자열.
      • description: 블록의 상세 설명. 문자열.
      • category: 어떤 분류에 속하는지 지정한다. 텍스트, 미디어, 임베드 등등이 있다. 문자열.
      • edit: 콜백 함수. 에디터 화면에서 어떻게 그려져야 할지를 지정한다.
      • save: 저장된 후 프론트에서 어떻게 그려져야 할지를 결정한다.

    안녕, 세상!을 위해 만든 간단한 블록은 아래 코드처럼 처리했다.

    registerBlockType('wp-esnext-study/wes02-hello-world', {
        title: __('WP ES Next #2 Hello, World!', 'wp-esnext-study'),
        description: __('"Hello, World!" sample for block editor.', 'wp-esnext-study'),
        category: 'common',
        edit() {
            /* 이 블록이 관리자 편집시 보이는 내용입니다. */
            return (
                <p>Hello, World!</p>
            )
        },
        save() {
            /* 이 블록이 저장될 때 내용입니다. */
            const helloText = __('WP ES Next #2 Hello, World!', 'wp-esnext-study');
            return (
                <p>{helloText}</p>
            )
        }
    });

    관리자 페이지에서 보면 이렇게 나온다.

    이것을 프론트에서 보면 이렇게 나온다.

    번역문 처리

    번역 파일을 로드하려면 주로 ‘init’ 훅의 콜백에서 다음처럼 코드를 작성한다.

    PHP에서 번역문 로드

    load_plugin_textdomain( 'wp-esnext-study', false, wp_basename( dirname( __DIR__ ) ) . '/languages' );
    • 첫번째 인자는 번역 텍스트도메인.
    • 둘째는 사용하지 않는다.
    • 셋째는 번역 파일이 있는 곳의 디렉토리. wp-content/plugins 디렉토리로부터 상대 경로이다. 주로 wp_basename( dirname( plugin_dir_path( MAIN_FILE ) ) ) . '/languages' 식으로 입력하곤 한다.

    pot 파일 생성

    poedit 같은 프로그램을 통해 디렉토리를 분석해 po 파일을 생성하는 방법도 있지만, 이렇게 하면 플러그인의 헤더 부분이 제대로 번역되지 않는다. 플러그인 이름, 제작자 같은 플러그인의 헤더 정보까지 올바르게 번역하려면 WP CLI i18n 커맨드를 이용하는 것이 좋다. 커맨드는 플러그인 루트에서 아래처럼 입력한다.

    mkdir languages # languages 디렉토리가 없다면 입력.
    wp i18n make-pot . languages/{텍스트도메인}.pot --domain={텍스트도메인}

    그러면 languages 디렉토리에 텍스트도메인으로된 .pot 파일이 생성될 것이다. 여기에 JS, PHP에서 사용한 모든 번역문이 담겨있을 것이다.

    이 POT 파일을 가져다 languages/{텍스트도메인}-{언어코드}.po 파일을 작성해야 한다. 보통 poedit 같은 프로그램을 이용한다. 내 예제를 보면 languages/wp-esnext-study-ko_KR.po 파일이 생성된 것을 알 수 있다.

    poedit을 사용하면 .po 파일과 함께 컴파일된 .mo 파일도 생성할 수 있다. PHP에서는 결국 이 .mo 파일을 이용하여 번역 텍스트를 처리할 것이다.

    번역문 JSON 생성

    그런데 .mo 파일의 번역은 PHP로 작성한 코드에서만 유효하다. 자바스크립트에서 번역문이 올바르게 처리되려면 .mo 파일이 아닌, .json 파일을 사용해야 한다. 이것은 pot 때와 마찬가지로 WP CLI를 사용하면 보다 편리하게 작업 가능하다.

    JSON 생성을 위해 번역을 두 벌 해야 할 필요가 없다. JSON 번역 파일은 .po 파일을 기본으로 하여 작성되기 때문이다. 그러므로 우선 .po 파일의 번역을 끝마친 후에 .json 파일을 생성해야 할 것이다.

    명령은 플러그인의 루트 디렉토리에서 아래처럼 실행한다.

    wp i18n make-json languages

    이 명령을 실행하면 .po 파일로부터 JS 쪽의 번역문만 따로 뽑아내 .json으로 만든다. 이후 .po 파일에서는 JS 쪽 번역문은 사라지게 된다. 이런 파일의 수정을 일어나지 않게 하려면 뒤에 --no-purge 옵션을 더해 주면 된다.

    번역 JSON 파일의 해시값

    생성된 JSON 파일의 이름을 보면 {텍스트도메인}-{언어}-{해시}.json으로 되어 있다. 워드프레스는 이보다 {텍스트도메인}-{언어}-{핸들}.json을 먼저 읽기는 한다. 그러나 WP CLI i18n make-json 명령으로는 핸들로 된 파일을 만들지 않고 해시로 된 파일을 만든다.

    그런데 의문점이 있다. 해시는 어떻게 생성하는가? 그리고 해당 명령으로 만들면 파일은 2개가 생성된다. 이것은 왜 그러는가?

    우선 파일이 2개 생성되는 이유를 살펴보자. 파일의 JSON 구조를 보면 “source” 키의 값으로 “build/index.js”, “src/index.js” 각각 두개로 나눠져 있는 것을 알 수 있다. 그 외에 두 파일의 내용은 동일하다.

    그리고 src/index.js와 build/index.js 각각의 md5 해시값이 뒤에 붙어 다른 파일이 2개 생성되는 것이다. 이렇게 되는 이유는 pot 파일에서 찾을 수 있다. 아래는 pot 파일의 일부이다.

    #: 02-block-editor-hello-world/build/index.js:115
    #: 02-block-editor-hello-world/src/index.js:11
    msgid "\"Hello, World!\" sample for block editor."
    msgstr ""

    #은 주석인데, 해당 소스 코드 어디에서 이 문자열이 발견되었는지를 기록한다. js 파일에 대해 src와 build 두 곳에서 문자열을 가지고 오게 된다. 그리고 저 위치는 .json 파일을 만들때 ‘source’ 키에 사용하게 된다. 또한 이 ‘source’ 의 값을 md5 해시로 돌려 보면 해당 파일의 이름으로 된 해시값과 동일한 결과가 나옴을 알 수 있다.

    각 md5 해시 값의 결과는 아래와 같다. 만들어진 json 파일의 결과와 비교해 보면 서로 동일하다는 것을 알 수 있다.

    • 02-block-editor-hello-world/src/index.js – 8fd9b2d6decbdc39f7e175586b1ca3a2
    • 02-block-editor-hello-world/build/index.js – e3c4e88d8ce2f5a27f6d3f9da2c228e6

    이런 이유로 language 디렉토리는 플러그인 디렉토리 바로 밑에서 작성하고, 번역문은 플러그인 전역에서 처리하는 것이 좋다. 그렇지 않으면 해시값에 대해 따로 처리를 해 주어야 할 것이다.

  • ESNext #1: 리액트 사용

    블록 에디터가 워드프레스 생태계에 주는 여파는 꽤 크다. 단순히 쓰기 편한 새로운 에디터가 등장한 것 뿐만이 닐 것이다. 이제 새로운 프론트엔드 개발 기법들을 적극적으로 반영해야 한다.

    리액트는 새로운 워드프레스 코어 코드의 중요한 의존성이 되었다. 물론 필수는 아니겠지만 개발자는 보다 리액트를 잘 이해해야 할 필요가 있다. 아마 꽤 오랫동안은 그 영향력이 유지되겠지만 점차 jQuery는 폐기될 것이다. 정말 많은 요소들이 변화하고 있으며, 나 같은 개발자는 따라가기 벅차다.

    이번 기회에 기존의 기술과 대두되는 새로운 기술들을 어떻게 사용해야 할지 좀 정리해야 할 필요가 있다고 생각했다. 새로운 기술들은 아직 사용하기 익숙치 않아 계속 실무에 투입하기 어려웠다. 하지만 이제 점점 사용해야 하지 않으면 안 될 시기가 온 것 같다. 고객들도 점점 구텐베르크를 위시한 새로운 프론트엔드 개발에 대한 사용 경험을 쌓아 왔고, 나도 그에 맞추지 않으면 안 된다고 생각한다.

    우선 블럭 에디터나 리액트를 플러그인 개발에서 사용하기 위한 절차? 방법들에 대해 정리해보자. 대략 알고 있지만, 숙련도가 높지 않은 탓에 자연스럽게 되지 않는다.

    플러그인 기본 셋업

    기존과 동일하게 플러그인 메인 파일에 헤더를 생성한다. 이러면 코어는 플러그인을 인식한다. 그러나 이제는 자바스크립트 기반의 개발 환경을 위해 package.json 파일의 추가를 반드시 해 줘야 한다.

    package.json은 NPM으로 가능하지만, 나는 yarn을 더 선호한다. 혹시 개발하는 시스템에 yarn이 설치되지 않았다면 yarn 설치하기 페이지를 보고 우선 진행하기 바란다.

    Yarn이나 NPM이 설치되었으며 ‘npm init’ 혹은 ‘yarn init’으로 package.json을 시작하자. package.json은 단순한 JSON 파일이므로 스키마를 잘 안다면 수동으로 만들어도 무방하다.

    아래 JSON 일부분은 라이센스와 기본 빌드 스크립트를 지정하는 예제이다. 아마 이 셋업은 자주 반복될 것이다.

    {
      ...
      "scripts": {
        "start": "wp-scripts start",
        "build": "wp-scripts build"
      },
      ...
      "license": "GPL-2.0-or-later"
    }

    @wordpress/scripts 설치

    솔직히 내가 프론트엔드 프레임워크에서 매우 짜증내는 부분 중 하나이다. 바로 과도한 설정 홍수. 프론트를 위한 온갖 잡다한 부분이 package.json을 위시한 별별 js 파일 설정에 뒤범벅이 되어 있는 것. 나도 한 사람의 개발하는 사람으로서 그런 이유와 결과에 대해 이해하지만, 내 개인적으로는 덕지덕지 붙어있는 이런 잡다한 설정 덩어리들은 괴물같아 싫다.

    물론 더욱 정밀한 설정, 고급 설정을 하려면 그런 세세한 설정이 없으면 안되는 것은 알지만… 적어도 나한테는 프론트엔드 개발에 큰 장벽이 된다.

    그래도 좀 다행이다. 이러한 개발 설정들은 한 번 잘 설정해 두면 잘 복사해서 재사용할 수 있다는 점이고, 워드프레스 코어 개발자들은 아예 그 재사용성을 활용해 그러한 설정마저 하나의 패키지로 묶어 놨다는 사실. 보다 세세한 설정에 눈뜨게 될 때 까지는 훌륭한 조력자가 될 것이다.

    이 조력자는 yarn add --dev @wordpress/scripts라는 한 줄의 명령어로 쉽게 설치된다. 그리고 위 package.json 의 scripts 부분에 미리 설정을 해 두었으니 npm start, npm build 명령과 연계하여 사용하면 된다. 보다 복잡한 설정은 문서를 참고하면 된다.

    리액트로 Hello, World! 시작하기

    블록 에디터를 위한 커스텀 블록 생성 전에 먼저 그냥 먼저 리액트를 사용해 보자. 최초의 예제는 언제나 ‘Hello, World!’니까 그것부터 시작해 보자.

    예제는 github에 작성했고, 앞으로도 거기에 내용을 업데이트할 예정이다. 코드가 워낙 간단하니 디테일한 설명은 생략한다. 자세한 설명은 소스 코드에 주석으로 대신한다. 여기서는 중요한 포인트 몇가지만 기술하고자 한다.

    • 리액트가 프론트엔드 부분의 마크업까지 작성하게 되므로, PHP 코드 자체에서는 그다지 많은 할 일이 없다. PHP 코드는 껍데기라고 느껴질 정도로.
    • 중요. 보통 ‘depencencies’에 ‘react’, ‘react-dom’를 넣게 된다. 그러나 워드프레스에서는 ‘devDependencies’에 둘을 넣는다. 워드프레스 코어 자체에 리액트가 내장되어 있고 wp-script가 서로 다른 버전의 리액트가 중구난방하지 않도록 제어하기 때문이다. 물론 스크립트가 알아서 잘 처리하니 그냥 dependencies에 넣어도 문제가 되지는 않는다.
    • 리액트 뿐 아니라 블록 에디터를 위해 만들어진 여러 패키지, 예를 들어 UI 요소들 같은 노드 패키지들도 코어에 이미 지정되어 있다면 코어의 것을 쓰지, node_modules로 임의 설치된 것을 사용치 않는다. 즉, 패키지 설치는 단지 코드를 참조하기 위함으로 알아두자.

  • 워드프레스 코어 #3

    2020년 08월 04일 네번째 모임 발표 자료

    워드프레스 데이터베이스와 회원 로그인에 대한 자료입니다.

    슬라이드 링크

  • 워드프레스 코어 #2

    지난 시간에 이어 코어 두 번째 이야기를 준비했습니다. 이번에는 wp() 함수에서 일어나는 라우팅에 대해 알아봅니다.

    URL을 입력하면 각 주소에 따라 서로 다른 콘텐츠가 나옵니다. 어떤 주소로는 단일 포스트 세부 내용이 나오고, 또다른 주소로는 아카이브 페이지가, RSS 피드가 나옵니다. 이게 어떻게 가능할까요? 이 원리를 간단히 알아봤습니다.

    슬라이드 보기

  • 워드프레스 코어 #1

    2020년 7월 2일 두번째 모임 발표

    워드프레스가 사용자로부터 요청을 받으면, 응답을 보내기까지 어떤 일들이 일어나는지 간략하게 알아본 자료입니다.

    슬라이드 링크

  • 워드프레스 개발자 관련 커뮤니티를 만들고 싶습니다

    강력한 워드프레스 개발자 커뮤니티를 구축하고 싶습니다.

    워드프레스 개발자니까 기반은 워드프레스로 작성하고 싶습니다. 탄탄한 사이트를 원합니다. 그래서 테마와 플러그인은 직접 개발하고 싶습니다. 개발자끼리 정보를 공유하고 개발 관련 이슈를 많이 논하는 커뮤니티로 만들고 싶습니다.