ESNext #4: 블록 에디터 속성

블록 에디터는 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,
	]
);

편집기에서 값을 저장하고 저장된 상태를 확인해 본다. 값이 잘 저장되는 것을 확인했다.

편집기 화면, 이름으로 Simth, Ashley를 입력했다.
저장 후 프론트에서 본 화면.
해당 포스트의 포스트 메타 상황을 데이터베이스 테이블에서 검사.

단, 값이 잘 저장된 것처럼 보이지만 헛점이 하나 있다. 이 글을 코드 에디터로 봐서 본문을 날것 그대로 보면 아래 그림처럼 나온다.

메타 값으로 지정한 Ashly는 그저 텍스트로 출력되어 있다. 만약 다른 곳에서 메타 값을 Ashly에서 Simpson으로 변경한다 하더라도, 이 텍스트는 변경되지 않는다. 이렇게 DB로 저장된 값을 가져와 표시하려면 지금처럼 정적인 렌더링은 알맞지 않다. 이것은 차후 동적 렌더링에서 따로 알아보도록 하자.

댓글 남기기