블록 에디터는 post_content 필드에 직접 기록된다. 그리고 기본적으로 블록의 내용 또한 이 필드 안에 본문으로서 기록된다.
예를 들어, ESNext #2: 블록 제작에서 작성한 Hello, World! 블록은 다음처럼 텍스트로 기록된다.
<!-- wp:wp-esnext-study/wes02-hello-world --> <p class="wp-block-wp-esnext-study-wes02-hello-world">WP ES Next #2 안녕, 세상!</p> <!-- /wp:wp-esnext-study/wes02-hello-world -->
HTML 코드로 기록되는 것이 보인다. 그리고 주석으로 이것이 워드프레스 블록임을, 또 어떤 블록 타입인지를 기록하는 것이 보인다. wp:
로 시작하고 /wp:
로 닫는 것으로 보인다. ‘wp-esnext-study/wes02-hello-world
‘는 내가 지정한 블록 타입 이름이다.
블록은 워낙 단순해서 어떤 상태나 속성을 가지지 않지만, 이제 간단한 속성을 지정해 보도록 하자. 이것을 활용하면 블록 에디터에 값을 저장하고, 불러와 쓸 수 있게 된다.
Github 리포지터리에 04-attributes 디렉토리로 예제 코드를 작성하였다. 아래부터는 이 예제 코드에 대한 설명을 덧붙인다.
속성값에 대한 설명은 블록 에디터 문서에서 찾을 수 있다. 이 개념은 마치 리액트의 콤포넌트의 state와 약간 비슷한 느낌이다. registerBlockType() 함수의 옵션 인자로 주어지며, 해당 블록 타입 내 속성값의 키-값 쌍들의 목록이다.
registerBlockType('foo/bar', { ... attributes: { name: { type: 'string', default: 'John', } } ... });
키는 해당 속성의 이름, 값은 속성의 성격을 정의한다.
‘type’은 필수적으로 지정해야 하며 다음 문자열 중 하나여야 한다.
- null
- boolean
- object
- array
- number
- string
- integer
‘source’는 이 속성값이 블록 내 어떤 곳에서 오는지 지정한다.
- 생략: source를 생략할 수 있다. 이 때 블록의 주석에 인코딩된다. 명시적으로 주는 방법도 있을 텐데 정확히 알 수가 없다.
- attribute: 속성에서 가져온다.
- html: HTML 코드를 취한다.
- text: 텍스트를 취한다.
- children: 내부 자식 요소에서 취한다.
- meta: 메타 값에서 온다.
- query: 속성 값에 여러 군데에서 값을 가져와야 할 경우 유용하다.
‘source’와 더불어 ‘selector’, ‘attribute’ 속성을 더할 수 있다. ‘selector’는 CSS 선택자로 내부 요소를 선택할 때 쓰고, ‘attribute’는 검색된 노드에서 어트리뷰트 값을 취할 때 쓴다.
{ ... attributes: { ingredients: { type: 'array', source: 'children', selector: '.ingredients', }, url: { type: 'string', source: 'attribute', selector: 'img', attribute: 'src', }, comment: { type: 'string', source: 'meta', meta: '_my_comment' } } ... } // attributes의 예제. 'ingredients' 클래스를 가진 자식 노드의 텍스트를 가져온다. // img 노드의 src 속성에서 url 속성값을 채운다. // comment 속성은 메타 필드 '_my_commnet' 로부터 온다.
예제에서 나는 두 개의 입력 필드를 삽입했다. 이 입력 필드를 통해 위젯의 내용을 동적으로 표현한다. 하나는 주석에 저장하고, 하나는 메타 필드로부터 가져온다.
{ ... attributes: { name: { type: 'string', default: 'John', }, anotherName: { type: 'string', source: 'meta', meta: '_another_name', default: 'Jane', } }, ... }
나머지 edit(), save() 메소드를 완성한다.
edit({setAttributes, attributes}) { return ( <> <p>{__('Hello, World!', 'wp-esnext-study')}, {attributes.name}, {attributes.anotherName}!</p> {/* 첫번째 입력 요소. Hello, World!, {이름}을 출력하게 합니다. 이 요소는 HTML 주석에 JSON 인코드 됩니다. */} <TextControl label={__('Your Name', 'wp-esnext-study')} value={attributes.name} onChange={value => { setAttributes({name: value}); }} /> <TextControl label={__('Another Name', 'wp-esnext-study')} value={attributes.anotherName} onChange={value => { setAttributes({anotherName: value}); }} /> </> ); }, save({attributes}) { return ( <> <p>{__('Hello, World!', 'wp-esnext-study')}, {attributes.name}, {attributes.anotherName}!</p> </> ); }
이렇게 하면, name은 본문 블록의 주석에 저장되고, anotherName은 메타 값으로 저장된다. 단, 메타 값을 REST API에 노출하기 위해 index.php에 register_meta() 함수를 호출해 _another_name 필드를 지정한다.
<?php ... register_meta( 'post', '_another_name', [ 'type' => 'string', 'description' => 'Another name.', 'default' => 'Jane', 'single' => true, 'sanitize_callback' => function ( $value ) { return sanitize_text_field( $value ); }, /** * apply_filters( "auth_{$object_type}_meta_{$meta_key}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps ); * * @see map_meta_cap() */ 'auth_callback' => function ( $allowed, $meta_key, $object_id, $user_id ) { return user_can( $user_id, 'edit_post', $object_id ); }, 'show_in_rest' => true, ] );
편집기에서 값을 저장하고 저장된 상태를 확인해 본다. 값이 잘 저장되는 것을 확인했다.
단, 값이 잘 저장된 것처럼 보이지만 헛점이 하나 있다. 이 글을 코드 에디터로 봐서 본문을 날것 그대로 보면 아래 그림처럼 나온다.
메타 값으로 지정한 Ashly는 그저 텍스트로 출력되어 있다. 만약 다른 곳에서 메타 값을 Ashly에서 Simpson으로 변경한다 하더라도, 이 텍스트는 변경되지 않는다. 이렇게 DB로 저장된 값을 가져와 표시하려면 지금처럼 정적인 렌더링은 알맞지 않다. 이것은 차후 동적 렌더링에서 따로 알아보도록 하자.