<aside> 💡
お客様アカウントを「新しいお客様アカウント」に設定されているお客様は、【新しいお客様アカウント】退会ボタンのテーマへの導入方法をご確認ください。
</aside>

テーマエディタでアカウントページにテーマアプリ拡張機能を追加するには、以下の手順に従ってください:
「テーマを選択」ボタンをクリックしてテーマを選択します。
選択したテーマの「エディタを開く」ボタンをクリックしてテーマエディタを開きます。
テーマエディタで、「customers/account」テンプレートを選択します。
「セクションを追加」から「アプリ」をクリックし、「退会ボタン App Unity Safe Delete」を選択します。

必要に応じてブロックの設定からCSSを調整してください。
コードでアカウントページに退会ボタンを追加するには、以下のコード例をご利用ください。
※アカウントページ(例:sections/main-account.liquid)への実装を想定しています。当アプリのアプリプロキシ(/apps/customer/ がストアから届く設定)が有効であることが前提です。
【退会アンケート】次のコード例では、GET /apps/customer/cancellation-survey-config のレスポンス(enabled / choices / freeTextEnabled / required)だけを使い、チェックボックスの選択肢ラベルはサーバーが返す choices 配列から自動生成します(テーマ側で固定列挙しません)。退会時は POST /apps/customer/disactivate に survey_choices と任意で survey_free_text を付与します。表示文言はコード内の S を編集して調整できます。
※2026年6月更新:退会アンケート機能に対応した最新のコードに差し替えました。以前掲載していた旧コードをご利用の場合、退会アンケートを「オン(必須)」に設定すると退会時にエラーとなり退会処理が実行されません。お手数ですが以下の最新のコードへの差し替えをお願いいたします。
コード例(以下のコードをアカウントページの任意の場所に追加してください。スタイルなどは自由に変更可能です。):
<style>
#au-confirm-popup {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 24px;
border: 1px solid black;
border-radius: 5px;
z-index: 1000;
text-align: left;
width: min(420px, 92vw);
max-height: 85vh;
overflow-y: auto;
font-size: 1rem;
box-sizing: border-box;
}
#au-confirm-popup button {
font-size: 15px;
padding: 8px 16px;
margin: 6px 6px 0 0;
cursor: pointer;
display: inline-block;
}
#au-confirm-popup .au-survey-reasons label {
display: block;
margin: 8px 0;
cursor: pointer;
font-size: 0.95rem;
}
#au-confirm-popup textarea.au-survey-freetext {
width: 100%;
min-height: 88px;
margin-top: 10px;
font-size: 0.95rem;
box-sizing: border-box;
padding: 8px;
}
#au-popup-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
z-index: 999;
}
</style>
<div id="au-customer-disactivate">
{% if customer %}
<p class="customer"><a href="#" onclick="auOpenDisactivateFlow(); return false;">退会する</a></p>
{% else %}
<p class="customer">
<a href="#" onclick="alert('退会するためにはログインしてください'); window.location.href = '/account/login'; return false;">
退会する
</a>
</p>
{% endif %}
</div>
<div id="au-confirm-popup" role="dialog" aria-modal="true"></div>
<div id="au-popup-overlay" onclick="auClosePopup()"></div>
{% if customer %}
<script>
(function () {
const AU_CUSTOMER_ID = {{ customer.id | json }};
const S = {
intro: "退会の理由をお選びください(任意)。",
next: "次へ",
freeLabel: "自由記述",
cancel: "キャンセル",
confirm: "本当に退会しますか?",
yes: "はい",
no: "いいえ",
ok: "退会処理が完了しました。",
err: "退会処理に失敗しました",
needSurvey: "退会アンケートの回答を入力してください。",
};
const byId = (id) => document.getElementById(id);
const esc = (s) =>
String(s ?? '')
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/"/g, '"')
.replace(/'/g, ''');
const escAttr = (s) => String(s).replace(/&/g, '&').replace(/"/g, '"');
const norm = (data) => {
const o = data && typeof data === 'object' ? data : {};
const choices = Array.isArray(o.choices)
? o.choices.map((c) => String(c).trim()).filter(Boolean)
: [];
return {
enabled: !!o.enabled,
choices,
freeTextEnabled: o.freeTextEnabled !== false,
required: !!o.required,
};
};
let config = norm(null);
let picked = [];
let freeText = '';
const show = (html) => {
byId('au-confirm-popup').innerHTML = html;
byId('au-confirm-popup').style.display = 'block';
byId('au-popup-overlay').style.display = 'block';
};
window.auClosePopup = () => {
byId('au-confirm-popup').style.display = 'none';
byId('au-popup-overlay').style.display = 'none';
};
const useSurvey = (c) => c.enabled && (c.choices.length > 0 || c.freeTextEnabled);
const renderSurvey = () => {
let h = '<p>' + esc(S.intro) + '</p><div class="au-survey-reasons">';
for (const c of config.choices) {
const on = picked.includes(c) ? ' checked' : '';
h += '<label><input type="checkbox" name="au-survey-reason" value="' + escAttr(c) + '"' + on + '> ' + esc(c) + '</label>';
}
h += '</div>';
if (config.freeTextEnabled) {
h += '<label for="au-survey-freetext">' + esc(S.freeLabel) + '</label>';
h += '<textarea id="au-survey-freetext" class="au-survey-freetext" maxlength="2000">' + esc(freeText) + '</textarea>';
}
h += '<div style="margin-top:14px;"><button type="button" onclick="auSurveyNext()">' + esc(S.next) + '</button> ';
h += '<button type="button" onclick="auClosePopup()">' + esc(S.cancel) + '</button></div>';
show(h);
};
const renderConfirm = () => {
let h = '<p>' + esc(S.confirm) + '</p><div style="margin-top:14px;">';
h += '<button type="button" onclick="auDisactivate()">' + esc(S.yes) + '</button> ';
h += '<button type="button" onclick="auConfirmBack()">' + esc(S.no) + '</button></div>';
show(h);
};
window.auSurveyNext = () => {
picked = Array.from(document.querySelectorAll('#au-confirm-popup input[name="au-survey-reason"]:checked')).map((b) => b.value);
const ta = byId('au-survey-freetext');
freeText = ta ? ta.value.trim() : '';
if (config.required) {
const hasCh = config.choices.length > 0;
const hasFt = config.freeTextEnabled;
const ok =
(!hasCh && !hasFt) ||
(hasCh && hasFt && (picked.length > 0 || freeText.length > 0)) ||
(hasCh && !hasFt && picked.length > 0) ||
(!hasCh && hasFt && freeText.length > 0);
if (!ok) {
alert(S.needSurvey);
return;
}
}
renderConfirm();
};
window.auConfirmBack = () => (useSurvey(config) ? renderSurvey() : auClosePopup());
window.auOpenDisactivateFlow = async () => {
picked = [];
freeText = '';
try {
const r = await fetch('/apps/customer/cancellation-survey-config');
config = norm(r.ok ? await r.json() : {});
} catch {
config = norm(null);
}
useSurvey(config) ? renderSurvey() : renderConfirm();
};
window.auDisactivate = async () => {
if (AU_CUSTOMER_ID == null) return;
const body = {
customer_id: AU_CUSTOMER_ID,
survey_choices: picked.length ? picked : undefined,
survey_free_text: freeText || undefined,
};
try {
const r = await fetch('/apps/customer/disactivate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
if (r.status !== 200) throw new Error(S.err);
alert(S.ok);
window.location.href = '/account/logout';
} catch (e) {
alert(S.err);
console.error("エラーが発生しました:", e);
}
};
})();
</script>
{% endif %}