서버사이드 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/