서버사이드 React 렌더링으로 PHP/JS 간에 양방향 함수 호출이 가능한 워드프레스 관리자용 플러그인 만들기

 뻘짓하게된 동기

지난번 회사에서 누적된 과로가 퇴사한 후 몇일 쉬는 동안 갑자기 허리 디스크로 찾아와 꽤 오래 누워있었다.  덥고 습한데 누워있자니 죽을맛..   몇일 동안은 그저 잠으로 일관하다 한 귀퉁이에 밀어뒀던 ‘그 문제’를 다시 꺼내기로 했다. 글쓰는 플랫폼으로써 뿐만 아니라 두루 활용도 높은 워드프레스 플러그인을 React로 구현하는 것인데,  서버사이드 렌더링을 거치면서 WP의 모든 API를 React에서 호출할 수 있고, PHP 쪽에서도 JS/React 로 작성된 함수를 상호 호출할 수 있다면 상당히 재미난 것들을 만들 수 있을 것이라 생각해왔다.  그러나 난 WP Plugin/Theme 관련된 API에 대해선 쥐뿔만큼 알고 있는데다 PHP 코드를 보고있자면 육두문자를 자연스럽게 방출할 만큼 싫어하는 편이다. 그저 WP를 글쓰는 플랫폼으로써 또한 개인정보 관리 시스템으로 잘 활용하고 싶다는 욕심이 있을 뿐. 

 

구글도 지원하는 WP, 내가 필요한 건 JavaScript Bridge!

인터넷에서 WP가 차지하는 비율은 30%가 넘기 때문에 근시일 내에 사장될 수 없다는 여기저기 글들을 봐왔지만 레드오션도 고인 레드오션 급 아니던가.  그런데 작년에 구글이 워드프레스를 지원하겠다는 계획을 발표할 때는 상당히 혹하게 하더니 먹튀하는데 둘쨰라면 구글이 Site Kit1https://sitekit.withgoogle.com 이라는 구글 서비스관련한 공식 툴을 내놓았다. 기능이나 디자인은 둘째치고 내가 인상깊게 받은 건 어떤 서비스나 시스템이 ‘워프프레스 안’으로 들어온 후에 발생 가능한 시너지였다. 나는 워드프레스를 글쓰는 것과 개인정보 관리쪽에만 사용하고 있으나 만약 쭉 생각만 해오던  JavaScript Bridge를 만들어서 PHP 사용을 최소화 하고 모든 영역에서 JS를 사용해보기로 했다.

 

 과정 요약

만들긴 뭘 만들어.. 걍 가져다 잘 사용하면 된다.

모든 잡스런 설명을 줄이고 직접적인 코드로 설명하자면: 1) PHP extension으로써 V8Js를 추가하고, 2) React 코드를 작성해서 잘 잘라둔 다음, 3) 최소한의 PHP로 메뉴와 형틀을 잡고, 4) 나머지는 JS로 코딩하면 된다.

 

 

1) V8Js 설치는 극히 평범하다… -_-)  언제나 그렇듯 개삽질을 하게 해주니 말이다.   따로 정리해둔 글2http://andrwj.com/env/phpv8/을 참조하자.

 

2) React 코드를 잘 자르는게 핵심이다.  Webpack과 친하게 지내야 한다. 칼로 자르던 가위로 자르던 잘 자르자.  몇 번의 삽질을 하다보니 어떻게 / 어느 부분에서 잘라야 좋은지 감이 왔다. 아마 PHP쪽 개발자는 이 과정을 즐겁게 하긴 힘들 것이라 추측한다. 구성하는 방식은 제 각각이므로 자세한 설명은 패스. 내 경우는 myEtherWallet3https://vintage.myetherwallet.com/과 유사한 API를 제공하는 myKlaytnContract4https://github.com/andrwj/myKlaytnContract 이라는 이미 작성해뒀던 어플을 관리자 패널에 넣기위해  세 부분으로 나눴다. 

 

 

3) 최소한의 형틀은 WP Admin UI5https://www.wpadminui.net/ 플러그인을 사용했다. 가져다 쓸만한 게 너무 많아 문제다. 

 

4) 브릿지 부분과 이를 불러 쓰는 부분으로 나눈다

 

// 브릿지를 사용하는 쪽에서 호출하는 부분. 
// $library_js는 webpacket으로 컴파일되서 하나로 모아진 React App 소스.
// $application_js는 ReactJS를 React를 Rendering 하는 부분 
public static function setup( $application_js, $library_js, $stylesheet_url) {
      if ( empty( self::$instance ) ) {
            self::$instance = new self();
            self::$instance->application_js = $application_js;
            self::$instance->library_js     = $library_js;
            self::$instance->stylesheet_url = $stylesheet_url;
            self::$instance->init();
            self::$instance->attach_php_api();
      }
    return self::$instance;
}

 

 

// 위의 브릿지를 호출하는 부분
$bridge = \JSBridge\App::setup( __DIR__ . '/js/app.js', __DIR__ . '/js/bundle.js', get_plugin_url() . '/css/style.css' );

 

 

// React로 작성된 코드를 Snapshot으로 만들고 JS쪽에 전달할 Global Scope(PHP)를 만든다
$library_js = file_get_contents( self::$instance->library_js );
$library = V8Js::createSnapshot( $library_js );
$this->$v8 = new \V8Js('PHP', array(), array(), true, $library);
$this->v8->context = new \stdClass();

// JS에서 호출할 PHP함수 맵핑. JS에서도 동일한 이름으로 호출할 수 있게된다.
$this->register_func( 'wp_head', function() {
  ob_start();
  wp_head();
  return ob_get_clean();
} );

// React 코드를 DOM에다 렌더링 하는게 아니라 문자열로 받아 화면에 출력하면 ok 
$application_js = file_get_contents( self::$instance->application_js );
//내용 예: print(includes.ReactDOMServer.renderToStaticMarkup()
echo $v8->executeString($application_js);

 

보다시피, 어이가 없이 간단한 것이었다;;;;

 

 WP의 DB 접근 및 활용은 너무 간단하지만 충분히 실용적이라 어떤 것이든 쉽게 저장하고 업데이트/삭제할 수 있다

이 점이 젤 큰 매력중에 하나가 아닐까 생각한다. myKlaytnContract 어플리케이션에서는 저장하는게 세가지다. 

  • Application Binary Interface: JSON 포맷으로써 제법 긴 문자열이다. Contract의 API를 기술하는 내용이다
  • Owner Private Key: 물론 프라이빗 키를 이렇게 저장하는 건 분명히 문제가 될 소지가 있지만, 뭐 어때; 어차피 내 블로그는 외부에서 접근 못한다.6http://andrwj.com/post/2019/07/wordpress-as-static-site-generator/
  • Deployed Address of Contract: Klaytn Network 상의 주소 값이다. 테스트 할 때마다 바뀔 수 있어서 저장은 필수! 아님 너무 귀찮아진다.

 

입력한 정보는 Custom Post Type으로 저장되서 WP 안에서는 일반 문서로 취급되서 좋다. Custom Field를 적용해서 프로그래밍 없이 부가 정보를 달아둘 수도 있고. 또 다른 어플로 연결하는 것도 쉬운 일이다. 그야말로 재미난 놀이터;;;ㅎ

 

 

 컨셉은 증명됐다. 이젠 재미를 내려놓고 생활을 위해 구직활동을 해야 할 때

지금껏 재직했던 회사중에선 워드프레스를 활용하는 회사는 단 한군데도 없었다. 걔중 두군데서 BackOffice 제작에 WP를 활용해보자고 운을 띄워봤지만 찬밥;;  모르는 바 아니다ㅋ WP에 익숙해 지는건 FrontEnd 학습하는 것 만큼이나 시간이 걸릴 수 있는데다 이런 Hybrid Type을 솔류션으로 쓰자고 주장하는게 아니다.  오랬동안 머리속에서 맴돌던 걸 정리하는 차원에서 만들어 보았다. 속 후련한다;;

아마 이후로도 시간날 때마다 관련 프로세스를 정립하고 자동화 시키며 완전히 자동화 할 수 있게 만들어 나갈 걸로 생각한다. 그러나 한동안은 이걸 손에서 떼 놓아야 나중에 더 나은 생각이 들수도 있겠지.

 

PHP 문법에서 그 놈의 변수명 앞 ‘$‘ 표기좀 없어지기만 해도 한결 보기 좋을 텐데;;

 

References   [ + ]

1. https://sitekit.withgoogle.com
2. http://andrwj.com/env/phpv8/
3. https://vintage.myetherwallet.com/
4. https://github.com/andrwj/myKlaytnContract
5. https://www.wpadminui.net/
6. http://andrwj.com/post/2019/07/wordpress-as-static-site-generator/

근 일년이 되가는 에스프레소 커피 라이프

구매 이유

지난 번 회사를 다닐 때 구매했던 아웃도어용 에스프레소1http://andrwj.com/post/2018/11/wacaco-minipreso/를 사용한지 거의 일년이 다 되간다. 어지간한 회사에는 커피머신이 있지만 당시 이런 종류를 구매하게 된건 특정 커피에 대해 내 손가락이 구부러지고 제법 통증이 일어났기 때문이다. 커피를 안마시면 그만이겠으나, 내겐 커피 끊는게 제일 힘들다. 야동은 안봐도 커피는 마신다. 그런 내게 당시 이사한 회사 건물 공용 커피 머신에서 나온 에스프레소 한 잔 마셨다가 3일동안 손가락이 구부러졌었다. 젠장, 커피를 마시긴 마셔야했고 근처 널리고 널린게 카페지만 비용을 생각지 않을 수 없었다. 그러다가 마침 뻔썁에서 홍보 때리는 걸 보고 냅다 첫번째 미니프레소라는 제품을 구매했었다. 몇 달뒤 더 나은 성능인데 가격은 동일한 나노프레스란 제품을 내놓더라. 빡치지만 미니프레소의 문제점 때문에 나노프레소까지 샀다. 그리고 리뷰에 한마디 남겨줬었다. “장사 잘해서 좋으시겠어요…

 

알게된 것들

사실 난 커피추출에 대해 아무것도 몰랐다.  네스프레소 캡슐을 일년 동안 손으로 펌프질 해가며 압력이 커피 맛에 겁나 영향을 끼친다는 건 알게되기 까진 그리 오래걸리지 않았는데, 네스프레소 캡슐이 카페에서 파는 커피값에 비해 아무리 싸다해도 헤프기 그지없어 10줄 들이 한통 끝내는건 이틀이나 삼일 정도 밖에 걸리지 않는다. 결국 몇 번은 캡슐을 사서 사용하다 비용 문제도 있고 구매처 가는 것도 싫어서 일반 커피 콩을 갈아서 에스프레소를 만들기 시작하게됐고 캡슐 커피에서 맛보던 ‘그 맛’이 나오지 않아 이리저리 실험해보다가 맛에 영향을 주는 요인을 알게된거다. 

 

처음엔 에스프레소 그라인더를 비싼 놈으로 사야하나 싶었으나 20,000원도 하지않는 값 싼 세라믹 날을 써서 갈아도 문제없더라. 오히려 곱게 갈아내놓은 커피가루에 물을 통과시킬 압력이 부족해 에스프레소를 만들 수 없다는 걸 깨닫게된것. 두번째 구입한 나노프레스가 주장하듯 16기압을 만들 수 있다해도 사람 손으로는 레벨 11 이상의 고운 가루로 에스프레소를 만드는 건 너무 힘들다. 그리고 아무리 힘을 써도 나노프레스란 놈은 기준치 이상의 압력이 발생하면 뒤로 새버리는 안전장치?를 만들어뒀더라. 결국 어떤 이유로 기계를 쓸 수 밖에 없는지 알게됐다는 소득을 얻고 다른 방법을 시도해봤다.

 

네스프레소가 만들어내는 진하기의 85% 정도에 만족한다

나노프레스를 사용하는 이유는 캡슐과 함께 일반 그라인더로 갈아진 커피가루까지 지원하기 때문이다. 사용하다 고장나서 도저히 못쓰게되면 모를까, 다른 에스프레소 머신을 구입하지는 않을 예정. 그래서 적당한 가루 굵기를 찾아내기위해 마실 때 마다 그라인더 간격을 조절해나갔다. 그러나 원재료인 로스팅 커피 콩에 따라 적당한 가루 굵기가 다르더라는!!!  뭐 당연한 거긴 하지만 수동으로 이걸 하고 있자니 커피 한잔 마시려고 별 짓을 다하고 있다고 생각든다. 일반 콩으로 갈아서 마실 경우, 제품 자체의 설계에서 비롯된 압력 누수 때문에 커피 맛이 그리 좋지 않았다. 쇠가 아니라 플라스틱이라 뭐든지 과하게 하면 부서질 것 같아 조심스럽게 해야한다. (이런 짓을 하느니 돈들여서 제대로 된 맛을 내놓는 제품을 사는게 낫지만 그냥 버릴 수는 없는 노릇아닌가. 잘 써야지)  이리저리 부족한 압력을 보충하기 위해 드립커피 필터 종이를 끼움으로써 해결되는가 싶더니 만족할 만한 퀄리티에는 조금 부족했다. 몇달 동안의 실험적 시도 끝에, 갈아서 만드는 에스프레소는 네스프레소 캡슐 농도의 85% 정도에 만족할 수 밖에 없다는 결론에 도달했다.  재사용 캡슐에 곱게 갈은 커피로 시도해볼까 생각도 했으나, 그것도 리필을 해가면서 사용해야해서 굳이 그럴필요 있냐는 생각에 접었다.

 

시중에 파는 커피와의 다른 점

왜 손가락이 멀쩡하냐는 거다! 아파야하는게 정상이란 말이 아니다. 코스코에서 구매한 스타벅스 커피콩을 사용해도 멀쩡하더란 거지. (내 손가락이 스타벅스 커피에 가장 민감하게 반응하기 때문에 절대 마시지 않는 것도 있고 악덕 기업이라 개인적으로 보이콧 하고 있다) 그렇다는 건 커피 콩에 문제가 있는게 아니라 추출 방식 때문에 손가락에 염증을 유발하는게 아닐까?  마시지 않으면 될 일이지만, 마시고 싶기 때문에 이런 잡스런 일과 생각이 끊이질 않는다.  제일 심하게 반응하는 커피가 스타벅스이고 카페베네 커피에도 절반 정도 반응한다. 면역력이 떨어져서 그런가 싶었는데 의외로 나 같은 증상을 가진 사람이 주변에 나 말고 두명 더 있다. 추출 방식이 아니라 커피 자체에 문제가 있는게 맞을 듯…  유전자 조작된 밀이 더 이상 그 옛날의 ‘밀’이 아니듯 커피에도 뭔가 돈의 논리에 따른 해악이 있을 법하다.

 

그래서 오늘도 커피를 갈아 필터로 압력을 높인 뒤 쒼나게 펌프질해서 한잔의 85% 진하기의 에스프레소를 마신다.

 

 

References   [ + ]

1. http://andrwj.com/post/2018/11/wacaco-minipreso/

워드프레스를 정적사이트 생성기로 사용

워드프레스를 개인 블로그로 사용해오면서 끝없이 들어오는 해킹 시도를 막는 게 귀찮아서 대안을 찾다가 발견한 방법이다.

 

Jekyll1https://jekyllrb.com/Hexo2https://hexo.io/, Hugo3https://gohugo.io/ 등.. 정적 사이트를 만들어 주는 툴이 많은데 굳이 워드프레스를 개인 블로그로 쓴다고 하면 별스러운 놈 취급 받는 경향이 있다. 텍스트 중심의 블로그 시대가 저문지 오래되었다해도 개인의 역사를 기록하는 것은 그 자체로 의미가 있다고 난 믿는다. 쓸모없이 보이는 하루 한 때의 기록이 몇년 지난 뒤에 어떤 식으로 평가될지 섵불리 판단 할  수 없다. 조선 시대 왕의 일거수 일투족을 기록했던 사무관이 기록했던 것이 현대와서 당시의 시대를 이해하는데 도움되는 정도라고 할수도 없고 어차피 디지털인 정보는 사라지는 건 한순간이니 너무 과하게 생각하지 않는다.  난 생계형 작가가 아니며 잘 쓰는 것도 아니다. 단지 뭔가 기록으로 남기는 걸 좋아할 뿐이다.

 

 발단

난 명령형 정적사이트 생성 툴이 불편하다. 마크다운 형식을 미워하진 않지만 그렇다고 블로그에 쓰는 글에 적합하다 생각진 않는다. 단순히 글을 남기는 용도라면 훌륭하다. 그러나 난 정해진 형식 외에도 실험적인 것들을 모두 담아넣고 싶기 때문에 하루가 다르게 새로운 정적생성 툴이 나오더라도 내겐 고려대상이 아니었다. 또한 내가 아무리 명령형 어플을 선호한다 해도 블로그 글까지 VIM 이나 Spcemacs로 편집하고 싶지는 않다.  MediaWiki 와 Phabricator를 개인 정보 관리용으로 사용하는 건 한계가 분명했기에 한동안 지겹게도 시도하는 워드프레스 해킹 시도를 막는데 시간 좀 보냈었다. 그러다가 문뜩, WP SuperCache 같은 플러그인이 정적 파일을 만들어내서 접근 속도를 높이는 거라면 모든 공개 가능한 컨텐트를  정적파일로 만들어 내면 되지 않겠는가 생각이 들었다.

 

Simple-Static4https://www.simplystatic.co/, WP2Static5https://wp2static.com/ 두가지를 시도해보니 WP2Static 이 월등히 우수하고 내 목적에 맞았다. 라즈베리파이에서 동작 중이던 기존 워드프레스를 걷어내고 NginX 만 사용하도록 변경한 뒤, 내 맥북에서 생성된 정적 파일을 rsync로 전송했다. 덕분에 해킹때문에 신경 쓰던 것과 속도 때문에 라즈베리파이4를 구매할려고 했던 생각들이 한방에 정리됐다. 

 

 공개할 기능 설정과 기존 Permalink 문제

일단 정적 사이트에는 검색 기능을 제공하지 않기로 결정했다. Algoria6https://community.algolia.com/wordpress/ 라는 플러그인의 소스를 약간 수정하면 되지만, 서두에 말했다시피 나는 워드프레스에 민감한 정보를 많이 저장하는 타입이라 Algoria가 내 컨텐트를 싹 쓸어 가는 걸 원치 않는다. 게다가 해당 팀에서 공식적으로 플러그인 지원을 중단했으므로 시간 들여서 소스를 수정할 정도로 사람들에게 보여주고 싶은 컨텐트가 없다는게 검색 기능을 제외한 이유다.  글 목록 페이지를 보거나 분류/태그 등 블로그 방문객이 검객할 방법은 아예 없진 않다. 외부에서 유입되는 건 어차피 구글이 알아서 다 사용자들에게 보여주겠지…

 

검색기능 외에 무분별하게 설정했던 기존 permalink URL이 더 큰 문제였다. 한글로 된 permalink는 WP2Static 생성기가 encoding 해버리는 과정에서 파일이 생성되지만 찾을 수 없는 404 Not Found 상황을 만들어 버린다. 한글 permalink를 사용한 포스트를 일일이 변경시키는 과정은 시간도 제법 잡아먹었고 변경한 뒤에도 뭔가 제대로 동작하지 않는 상황이 반복되었다. 짜증;;; 

결국 SQL을 덤프해서 perl/sed/awk 등으로 일괄 패턴 처리 해버림으로써 일단락했다… 싶었더니, slug 에 한글이 끼어들어간게 또 문제인 것을 뒤늦게 발견… 다시 한번 SequelPro7https://www.sequelpro.com/로 수동 조작해서 정리해버렸다.  이렇게되니 기존 permalink로 들어오는 모든 접근을 rewrite 해야하는 상황이 됐는데,  어차피 내 블로그를 찾는 사람은 페블 언어팩 다운로드가 목적인 사람이 80% 이기 때문에 기존 박살난 permalink rewrite 문제는 걍 포기하기로 결정했다. 뭐.. 그리 중요한 글이 있는 것도 아니고;;;  잔뜩 쌓여져 있는 MediaWiki 글을 블로그에 포함 시킬 수도 있으나 /blog/ 로 시작하는 Base URL이 거슬려 / 로 변경했다. 덕분에 구글링 된 기존 링크는 모두 개털이 됐다. 

 

 Custom Post Type 적극 활용

플러그인 간의 충돌 해결이 제일 시간소요가 많았고 갖가지 문제가 발생해서 추적하느라 힘들었지만 내가 블로그에 담고자 했던 시도를 통일되게 해결하는게 필요했다. MediaWiki 컨텐트를 가져오는 건 너무 쉬운 일인데 CSS 수정에 시간이 좀 들어간다.게다가 추가적인 접근을 차단하기 위해서는 해당 플러그인의 소스를 수정해야 한다. Jupyter-Notebook을 Embed 하는 건 쉬운데 역시 CSS/JS 적용에 통일 된 방법이 필요했다. ReactJS Project를 포스트/페이지에 포함하는 것도 CSS/JS 관련 문제다.  비슷한 모든 문제는 대부분 CSS/JS 적용 방법 때문이었고 그동안 사용하지 않았던 Custom Post Type으로 해결할 수 있어보여 간단한 플러그인을 만들어 넣었더니 의외로 한방에 해결됐다. Custom CSS/JS 관련 플러그인이 많지만 무료에 내 요구사항에 맞는게 없었다. 어쨌든  정말 이번 작업하면서 워드프레스의 설계에 감탄을 금하지 않을 수 없었다. 

 

 WIX8https://ko.wix.com/, Medium9https://medium.com/ 등에 비해 워드프레스가 뒤처진다고 해도 개인적인 사용 용도에는 끝내주는 물건이다

헤아리기 힘들 정도로 많은 수의 플러그인, 테마가 널려있어 입맛대로 선택할 수 있는데다  특정 부분은 내 입맛대로 코드 수정가능하다. 마크다운 기반으로 정적사이트 생성하는 툴과 달리, 수 많은 사용자 플러그인을 지원 받는 워드프레스는 명령행 기반 정적 사이트 생성 툴과 비교할 수 없다고 생각한다.  개인 사진파일과 짤, 화면샷 등의 이미지를 보기좋게 관리할 수 있고 문서내에서 참조하기도 쉽다. Pixave10http://www.littlehj.com/mac/ 어플 같은 근사한 어플의 기능에 비할 수는 없지만 이 어플이 언제 종료될지, 또 내가 계속해서 맥을 쓴다는 보장도 없고 Pixave 기능의 일부에 해당하는 것만 지원되도 문제없어서 워드프레스 갤러리 플러그인으로 만족한다. 한 때 절대 macOS 만 쓰겠다고 생각했던 적 있었지만 인증서 문제로 모든 어플을 다시 다운받아야 했던 사건 이후로 생각이 달라졌다. 게다가 요즘 Window10 도 괜찮아 보인다. 비록 워드프레스 v5 이후로 망조라고 해도 나같은 개인 사용자에겐 충분하다.

 

얼마간은 계속해서 설정을 손봐야 겠지만 워드프레스를 정적사이트 생성툴로 사용한 건 정말 잘했다고 생각한다.  permalink 변경시 NginX rewrite 룰을 자동생성해주는 툴을 달고 블록에디터도 활용할 방법을 찾아 적용하면 개인 정보와 컨텐트 관리용으로서 10년 정도는 계속해서 사용할 수 있지 않을까? 어차피 가상화해둔 공간에서 동작하는 워드프레스이니 그냥 계속 쭉~ 사용할 예정이다.

References   [ + ]

1. https://jekyllrb.com/
2. https://hexo.io/
3. https://gohugo.io/
4. https://www.simplystatic.co/
5. https://wp2static.com/
6. https://community.algolia.com/wordpress/
7. https://www.sequelpro.com/
8. https://ko.wix.com/
9. https://medium.com/
10. http://www.littlehj.com/mac/