Ideal House
콘텐츠로 이동

Shopify 개발자 연동#

Shopify 테마에 ideal.house 버튼을 추가하고 선택한 상품 옵션의 SKU에 매핑하세요.

<!-- DASHBOARD_READINESS -->

SDK를 불러오기 전에: Dashboard → Settings를 열고 **Allowed Origins (CORS)**에 스토어 출처를 추가한 다음 저장을 클릭하세요. 배포된 호스트 이름과 사용 중인 미리보기 또는 스테이징 출처를 포함하고, 여러 출처는 쉼표로 구분하세요. 설정 절차를 참고하세요.

1. 사전 준비 확인#

  • 운영 테마 코드 또는 안전한 테마 복사본을 편집할 수 있어야 합니다.
  • 테스트 상품 하나 이상을 카탈로그로 가져왔으며 활성 상태여야 합니다.
  • 선택한 상품 옵션의 SKU는 카탈로그가 해당 스토어에 저장한 productCode와 같아야 합니다.

2. 버튼 스니펫 생성#

snippets/idealhouse-view-button.liquid#

liquid
{%- comment -%}
  Renders an ideal.house authored visualizer button.

  Accepts:
  - product_code: {String} Variant SKU used by the ideal.house Catalog mapping.
  - placement: {String} "card", "pdp-desktop", or "pdp-mobile".
{%- endcomment -%}

{%- liquid
  assign button_code = product_code | strip
  assign button_placement = placement | default: 'card'
-%}

<button
  type="button"
  class="idealhouse-view-button idealhouse-view-button--{{ button_placement | escape }}"
  data-idealhouse-authored-button
  data-active="false"
  {% if button_code != blank %}
    data-product-code="{{ button_code | escape }}"
  {% else %}
    disabled
  {% endif %}
  style="visibility: hidden;"
>
  <span>View in my room</span>
</button>

SDK가 상품의 사용 요건 충족을 확인할 때까지 버튼을 숨겨 두세요.

3. 테마 영역에 버튼 렌더링#

컬렉션 및 검색 카드#

liquid
{%- render 'idealhouse-view-button',
  product_code: card_product.selected_or_first_available_variant.sku,
  placement: 'card'
-%}

일반적으로 snippets/card-product.liquid, snippets/product-card.liquid 또는 snippets/product-grid-item.liquid 파일을 사용합니다. card_product를 테마에서 사용하는 상품 변수에 맞게 조정하세요.

상품 상세 페이지#

liquid
{%- render 'idealhouse-view-button',
  product_code: product.selected_or_first_available_variant.sku,
  placement: 'pdp-desktop'
-%}

{%- render 'idealhouse-view-button',
  product_code: product.selected_or_first_available_variant.sku,
  placement: 'pdp-mobile'
-%}

일반적으로 sections/main-product.liquid 또는 snippets/product.liquid 파일을 사용합니다. 테마에 별도 레이아웃이 있을 때만 데스크톱 및 모바일 렌더링을 각각 배치하세요.

4. SDK 불러오기 및 상품 옵션 동기화#

assets/idealhouse-room-visualizer.js#

js
(function () {
  'use strict';

  var buttonSelector = '[data-idealhouse-authored-button]';
  var sdkRequested = false;
  var buttonObserver = null;

  function resetButton(button) {
    button.dataset.active = 'false';
    button.style.visibility = 'hidden';
    delete button.dataset.rvProductCode;
    delete button.dataset.rvProductType;
    delete button.dataset.rvProductId;
    delete button.dataset.rvProductIds;
  }

  function syncButton(button, productCode) {
    if (!button) return false;
    var code = typeof productCode === 'string' ? productCode.trim() : '';
    resetButton(button);
    delete button.dataset.productCode;

    if (!code) {
      button.disabled = true;
      return false;
    }

    button.disabled = false;
    button.dataset.productCode = code;
    return true;
  }

  function syncButtons(container, productCode) {
    (container || document).querySelectorAll(buttonSelector).forEach(function (button) {
      syncButton(button, productCode);
    });
  }

  function loadSdk() {
    if (sdkRequested || !document.querySelector(buttonSelector)) return false;
    sdkRequested = true;
    if (buttonObserver) buttonObserver.disconnect();

    var script = document.createElement('script');
    script.src = 'https://sdk.ideal.house/sdk.js';
    script.async = true;
    script.dataset.shopId = '<SHOP_ID>';
    script.dataset.publishableKey = '<PUBLISHABLE_KEY>';
    script.dataset.authoredButtonSelector = buttonSelector;
    document.head.appendChild(script);
    return true;
  }

  function startSdkLoader() {
    if (loadSdk() || typeof MutationObserver === 'undefined') return;
    buttonObserver = new MutationObserver(loadSdk);
    buttonObserver.observe(document.documentElement, { childList: true, subtree: true });
  }

  // Dispatch this event from your theme's variant-change callback.
  document.addEventListener('idealhouse:variant-change', function (event) {
    var detail = event.detail || {};
    syncButtons(detail.container || document, event.detail && event.detail.sku);
  });

  window.IdealhouseShopify = {
    syncButton: syncButton,
    syncButtons: syncButtons
  };

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', startSdkLoader);
  } else {
    startSdkLoader();
  }
}());

Shopify는 모든 테마에 공통으로 적용되는 상품 옵션 이벤트를 정의하지 않습니다. 아래의 작은 어댑터를 활성 테마가 제공하는 이벤트 또는 콜백에 연결하세요.

테마 이벤트 어댑터 예제#

예제 이벤트를 활성 테마 API로 교체하세요. 일부 테마는 window.subscribe로 이벤트를 전달하고, 다른 테마는 DOM 이벤트를 발생시키거나 product-info를 갱신합니다.

js
// Example only: replace "variant:change" with your theme's event.
document.addEventListener('variant:change', function (event) {
  var variant = event.detail && event.detail.variant;
  var productContainer = event.target.closest('product-info') || document;

  document.dispatchEvent(new CustomEvent('idealhouse:variant-change', {
    detail: {
      container: productContainer,
      sku: variant && variant.sku
    }
  }));
});

5. 테마 스타일 추가#

assets/idealhouse-room-visualizer.css#

css
.idealhouse-view-button {
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 44px;
  padding: 0.75rem 1rem;
  border: 1px solid currentColor;
  border-radius: 6px;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font: inherit;
}

.idealhouse-view-button[data-active="true"] {
  display: inline-flex;
  visibility: visible;
}

.idealhouse-view-button:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

테마가 이러한 시각적 스타일을 재정의할 수 있습니다.

6. theme.liquid에 자산 포함#

layout/theme.liquid에 시각화 스타일시트와 스크립트를 포함하여 스타일을 적용하고 SDK 로더를 활성화하세요.

스타일시트 포함 (<head> 내부)#

liquid
{{ 'idealhouse-room-visualizer.css' | asset_url | stylesheet_tag }}

스타일이 올바르게 불러와지도록 layout/theme.liquid의 <head> 태그 안에 배치하세요.

스크립트 포함 (</body> 앞)#

liquid
<script src="{{ 'idealhouse-room-visualizer.js' | asset_url }}" defer="defer"></script>

페이지 렌더링을 차단하지 않도록 defer를 사용하고 layout/theme.liquid의 닫는 </body> 태그 바로 앞에 배치하세요.

이 로더 스크립트가 theme.liquid에 포함될 때까지 '내 방에서 보기' 버튼은 숨겨진 상태로 유지됩니다.

7. 운영 스토어에서 검증#

  1. 네트워크 패널에 sdk.js가 HTTP 200으로 불러와진 것으로 표시되는지 확인하세요.
  2. 직접 작성한 버튼의 data-product-code가 카탈로그 productCode와 정확히 일치하는지 확인하세요.
  3. 사용 가능한 상품에는 버튼이 표시되고 요건을 충족하지 못한 상품에는 숨겨진 상태로 유지되는지 확인하세요.
  4. 상품 옵션을 전환하면 data-product-code가 갱신되고 버튼이 다시 검증되는지 확인하세요.
  5. 컬렉션/검색, 상품 상세 페이지 데스크톱 및 모바일 배치가 있는 곳에서 올바르게 동작하는지 확인하세요.
  6. 버튼을 클릭하면 선택한 상품으로 ideal.house Viewer가 열리는지 확인하세요.