권한 제한이 있는 WordPress 사이트를 위한 검색 모달 구축하기

대부분의 WordPress 검색 튜토리얼은 너무 단순합니다. 단순히 헤더에 위젯을 넣으라고만 하죠. 이는 공개 블로그에는 작동하지만, 멤버십 사이트에서는 실패합니다.

유료 강의나 비공개 영상이 있는 경우, 기본 검색 기능은 데이터를 유출할 수 있습니다. 로그아웃된 사용자에게 비공개 콘텐츠의 제목을 보여주기 때문입니다. 이는 페이월(paywall)을 무너뜨립니다.

저는 WordPress, WooCommerce, LearnDash를 사용하여 피트니스 사이트를 위한 커스텀 검색 모달을 구축했습니다. 여기 권한 규칙을 준수하는 검색을 구축하는 방법을 소개합니다.

아키텍처

저는 각 콘텐츠 유형별로 별도의 검색을 사용하는 대신, 단일 통합 인덱스를 사용했습니다. 이를 통해 쿼리 수준에서 권한 제어를 강제할 수 있었습니다.

검색 결과는 다음 규칙을 따릅니다:

  • 블로그 포스트는 공개됩니다.
  • 온디맨드 비디오는 권한이 제한됩니다.
  • 코스는 LearnDash를 통해 권한이 제한됩니다.
  • 스토어 제품은 공개됩니다.

자식 테마(child theme)에 커스텀 REST route를 구축했습니다. 검색의 안정성을 보장하기 위해 스니펫 플러그인 사용은 피했습니다.

주요 엔지니어링 세부 사항

서버 측 권한 제어(Server-Side Gating): JavaScript를 사용하여 결과를 숨기지 마세요. 브라우저에서 결과를 숨기더라도 데이터는 여전히 네트워크 응답에 남아 있습니다. 사용자는 DevTools에서 이를 볼 수 있습니다. 데이터가 사이트를 떠나기 전에 반드시 서버에서 필터링해야 합니다.

캐시 관리(Cache Management): 검색 결과를 캐싱하면 멤버의 비공개 결과를 외부인에게 제공할 수도 있습니다. 데이터 유출을 방지하려면 페이지 캐시에서 검색 REST route를 제외하세요.

그레이스풀 디그레이데이션(Graceful Degradation): Relevanssi와 같은 서드파티 플러그인을 호출할 때는 가드(guards)를 사용하세요. 플러그인이 실패하더라도 사이트가 다운되는 대신 WordPress 코어 검색으로 전환되어야 합니다.

성능(Performance): 디바운스 함수(250ms)와 AbortController를 사용하세요. 이는 브라우저가 키를 누를 때마다 새로운 요청을 보내는 것을 방지합니다. 또한 오래된 요청을 취소하여 오래된 데이터가 새로운 결과를 덮어쓰지 않도록 합니다.

보안(Security): innerHTML을 사용하기 전에 항상 문자열을 이스케이프(escape)하세요. 이는 악성 포스트 제목을 통한 XSS 공격을 방지합니다.

모바일에서의 교훈

페이지 빌더가 모바일 메뉴 안에서 제 검색 버튼을 삼켜버리는 문제로 고생했습니다. 여러 CSS 수정을 시도했지만 모두 실패했습니다.

해결책은 간단했습니다. 테마와 싸우는 것을 멈추는 것이었습니다. 버튼을 메뉴 안에 넣는 대신, 헤더에 별도의 요소로 주입했습니다. 특정 컴포넌트가 변경 사항을 거부한다면, 그 안에 넣으려 하지 말고 옆에 배치하세요.

최선의 실천 방법 요약:

  • 서버에서 액세스 제어를 강제하세요.
  • 캐시에서 검색 엔드포인트를 제외하세요.
  • 원활한 UX를 위해 debounce와 AbortController를 사용하세요.
  • XSS 방지를 위해 모든 API 데이터를 이스케이프하세요.
  • 고집스러운 테마 컨테이너 외부로 요소를 배치하세요.

Source: https://dev.to/highcenburg/building-a-search-modal-for-a-membership-gated-wordpress-site-b92