구글 reCaptcha가 월 1백만건 초과건에 대한 사용량에 따라 요금을 내야 한다고 한다. hCaptcha는 좋은 대안이 될 수 있을 것 같다. 엔터프라이즈가 아니라면 무제한으로 사용할 수 있다.
워드프레스나 설치형으로 작성하려면 BotDetect Captcha 가 대안이 될 것이다.
구글 reCaptcha가 월 1백만건 초과건에 대한 사용량에 따라 요금을 내야 한다고 한다. hCaptcha는 좋은 대안이 될 수 있을 것 같다. 엔터프라이즈가 아니라면 무제한으로 사용할 수 있다.
워드프레스나 설치형으로 작성하려면 BotDetect Captcha 가 대안이 될 것이다.
당뇨는 습관의 질병.
멀티 사이트는 여러 워드프레스 사이트를 하나의 설치본으로 관리할 수 있게 한다. 이렇게 만들면 데이터베이스에는 추가적으로 테이블이 생기게 된다.
이 중 wp_blogs, wp_site 가 눈에 뜨인다. 보통 멀티사이트를 만들면 wp_blogs 에는 멀티로 만든 사이트 목록이 기록된다. 그리고 wp_site는 주로 단일 레코드가 기록될 것이다.
그런데 wp_site의 레코드를 통해 멀티사이트의 확장이 가능하다. 즉, 하나의 워드프레스 설치본으로 멀티사이트를 여러 개 만드는 것까지 가능하다는 소리다. 즉 이런 계층구도가 생성된다.
이렇게 하려면 데이터베이스에 여러 레코드를 편집하면 되는데, 편집해야 할 양이 좀 많아 관리하기 까다롭다. wp_site, wp_blogs, {prefix}_{blog_id}_* 테이블을 괸리해야 하기 때문이다. 이 정도는 WP Multi Network 플러그인에게 맡기는 것이 좋을 것 같다. 멀티사이트 관련 API에 큰 변동이 없어 그런지 이 플러그인은 현재도 잘 동작한다.
즐거운 삶을 살자.
훅 기능은 워드프레스에서 구현한 기능이며 일반적인 자바스크립트가 아니지만, 카테고리를 간결하게 유지하고 싶어 이 곳에 작성한다.
PHP에서 작성된 add_action, add_filter 같은 훅 제어가 JavaScript에서도 아주 유사하게 작성되어 있다! 자바스크립트가 비동기 방식이고, 이벤트 핸들링을 위해 콜백 함수를 쓰는 것이 매우 일상적이긴 하지만, 자바스크립트 고유의 콜백 방식을 쓰기는 조금 난감할 때가 있는데, 이 패키지를 사용하면 문제 없이 훅을 다룰 수 있다.
리포지터리에 이 혹을 사용해 보는 코드를 작성해 봤다. 아주 간단하게 자바스크립트에서 액션과 필터가 동작하는 코드이다. 기대되는 동작은 기존에 사용하던 PHP 쪽 버전과 동일하게 동작하기 때문에 사용하는 법만 대충 테스트하면 충분할 듯하다.
예제를 위해 슬러그가 ‘hooks-test’인 포스트를 생성한다. 스크립트는 이 포스트에서만 동작하도록 처리했다. 결과는 아래 그림과 같다.
액션과 필터는 아래처럼 사용한다.
addAction('wes06-test-action', 'changwoo/wes06-hooks/index', actionCallback01, 30); addFilter('wes06-test-filter', 'changwoo/wes06-hooks/index', filterCallback01);
다 같은데, 두번째 인자가 네임스페이스라는 점이 다르다. 이 네임스페이스는 hasFilter(), hasAction() 체크시에 사용되는 것 외에는 크게 의미는 없다. 저걸 다르게 준다고 해서 doAction, applyFilters 함수 호출시 특별한 동작을 하게 되는 것은 아니다. 즉 네임스페이스가 다르되, 훅 이름이 같다 하더라도 각 훅이 구분되는 일 따위가 없을 것이다.
아무튼 이 훅 관련 함수는 이미 코어 여러 부분에 적용되어 있다. 응용하면 자바스크립트에서 그동안 아쉬웠던 훅을 통한 기능 수정이 편안하게 될 수 있으리라 기대한다.
지난 포스트에서는 블록의 속성값에 대해 간단하게 알아 보았다. 블록이 어떻게 자신의 값을 저장하고 표현하는지 알 수 있었다.
블록은 HTML 주석 부분에 블록이 필요한 데이터를 JSON 형태로 저장하거나, 자신이 가지고 있는 HTML 마크업 구조에서 가져올 수 있고, 또 커스텀 필드로부터 가져올 수 있다. 단, 블록 자체는 HTML 코드 그대로 기록하기 때문에 이런 동적인 값들을 표현하려면 생짜 HTML 코드를 사용할 수 없을 것이다.
마크업 구조나 주석에 표현된 JSON을 사용하려면 리액트의 콤포넌트를 활용하거나, 메타 값을 표현하려면 동적인 렌더링을 활용해야 할 것이다.
이번에는 이런 것들을 표현할 수 있도록 해 보자. 이번에 만들 블록의 요구 조건은 다음과 같이 정리해 볼 수 있을 것이다.
완성된 코드는 Github 레포지터리에 올려두었다.
예제는 ‘Dynamic Render’라는 블록을 생성한다. 이 블록은 이전처럼 name과 anotherName 속성을 가지고 Hello, World! 처럼 문자를 출력하는 단순한 역할을 한다. 그러나 이 값은 보다 동적이다.
name은 따로 텍스트 입력 상자로부터 가져오며, anotherName은 사이드바로부터 온다. 또 name은 주석에 있는 블록 속성에 저장하며 anotherName은 커스텀 필드 _another_name에 저장한다.
사이드바나 커스텀 블록을 만드는 것은 기존 예제와 크게 다를 것이 없다. 그러나 사이드바에 넣은 값이 메타 필드와 연동되어야만 한다는 점이 이 예제의 키 포인트라고 할 수 있겠다. 그리고 이번에는 save() 메소드는 사실상 아무것도 하지 않는다. 프론트 렌더링을 PHP 측에서 담당하기 때문이다.
우선 프론트 쪽 렌더링을 살펴보자. PHP 코드에서 register_block_type() 호출시 ‘editor_script’ 뿐 아니라 ‘render_callback’ 또한 지정해 준다.
register_block_type( 'wp-estnext-study/wes05-dynaic-render', [ 'editor_script' => 'wes05-dynamic-render', // 필수! 'render_callback' => 'wes05_render_callback', // 동적 렌더링. ] );
render callback 함수를 실제 작성해 보니, 이 함수는 관리자 페이지에서 포스트 편집 화면에서도, REST API 호출 때에도, 프론트에서도 다 불리는 것을 확인했다. 단순히 프론트에서 호출할 때만을 상정하고 이 함수를 작성하면 프론트 이외 작업에서 에러가 날 수 있다.
또한 관리자에서 포스트 편집 화면에 들어갈 때 잠깐의 화면 공백이 발생하는데, 그 때에도 이 출력이 나온다. 그러므로 렌더 콜백은 다음과 같은 if … else … 구문을 사용하여 구분하는 것이 좋을 것이다.
if ( is_admin() ) { // 관리자 편집 화면 진입시 } elseif ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { // REST API 호출시 } else { // 프론트 호출은 여기서. }
사이드바에서 TextControl 하나를 넣어 onClick 이벤트와 value 속성을 커스텀 필드의 값과 이어지도록 처리 한다. 그런데 커스텀 필드는 블록 속성이 아니고, 코어가 포스트 편집 화면을 위해 이미 불러와져 있는 상태이다. register_meta() 함수를 부를 때 우리는 ‘show_in_rest’ 항목에 true를 주었기 때문이다.
그런데 이 커스텀 필드를 불러오거나 업데이트해야 할 때는 조금 복잡하다. 아무튼 현재 수준에서 가능한 설명을 기록한다. 우선 TextControl을 하나 감싸 ‘DynamicRender’라고 하자.
let DynamicRender = ({anotherName, onChange}) => { return ( <TextControl label="Another Name" value={anotherName} onChange={onChange} /> ); }
이제 DynamicRender에 마법을 부려 보자. 메타 값을 불러와 컨트롤의 속성으로 넣어 주려면 아래 코드를 참고한다.
// withSelect 로 DynamicRender 함수를 래핑. DynamicRender = withSelect(select => { const {getEditedPostAttribute} = select('core/editor'); return { anotherName: getEditedPostAttribute('meta')['_another_name'] }; })(DynamicRender);
한편 메타 값을 다시 업데이트하려면 아래 코드를 작성한다.
// withDispatch 로 DynamicRender 함수를 다시 래핑. DynamicRender = withDispatch(dispatch => { const {editPost} = dispatch('core/editor'); return { onChange(value) { editPost({meta: {_another_name: value}}); } } })(DynamicRender);
Redux와 워드프레스 자바스크립트 코어가 겹치는 부분이라 어렵고 이해가 잘 안가는 부분이 있다. 이해하려 해도 파야 할 부분이 많아 보여 현재는 코드 조각 수준밖에는 이해하지 못하는게 불만이다. 보다 이해를 높이려면 리액트나 리덕스를 보다 이해해야만 알 수 있을 것 같다. 보다 시간과 노력이 필요한 부분인듯.