네, 가능합니다. 간단한 것부터 시작해 보겠습니다. 먼저, 새 테마 컴포넌트의 헤더 탭에 아래 코드를 추가하세요.
<script type="text/discourse-plugin" version="0.8.42">
</script>
이것은 무엇을 하는 것일까요? 이는 Discourse가 처리하는 특수한 종류의 스크립트 태그입니다. 그 장점은 무엇일까요? 플러그인 API 메서드에 접근할 수 있게 해 줍니다.
일부 링크에 제휴 코드(affiliate code)를 추가하고 싶다고 하셨죠. 즉, 게시물의 내용을 수정해야 한다는 뜻입니다. 플러그인 API를 확인해 보면 실제로 이를 위한 메서드가 있음을 알 수 있습니다.
아래와 같이 사용합니다.
api.decorateCookedElement(
element => {
// 여기서 작업을 수행합니다.
// 여기 전달되는 element는 렌더링된 게시물의 HTML 노드입니다.
},
{
// 옵션은 여기에 작성합니다
}
);
이것은 게시물이 렌더링될 때 코드가 실행되도록 해야 하는 래퍼입니다. 자, 한번 시도해 보겠습니다.
사용자 코드를 그대로 추가해 보면 다음과 같습니다.
api.decorateCookedElement(
element => {
++ // 아래 "my-affiliate-id"를 실제 제휴 ID로 변경하세요
++ const aid = "my-affiliate-id";
++
++ // 링크에 아직 제휴 ID가 없다면 슬래시와 함께 제휴 ID를 추가합니다
++ const goglinks = document.querySelectorAll('a[href*="gog.com"]');
++ goglinks.forEach(function (el) {
++ if (!el.href.includes("pp=")) {
++ el.href = el.href.replace(/\?.*$/, "") + "?pp=" + aid;
++ }
++ });
},
{
// 옵션은 여기에 작성합니다
}
);
이것이 작동합니까? 네, 작동합니다. 하지만 게시물의 요소가 아닌 document에서 링크를 조회하고 있기 때문에 일부 중복된 작업도 수행하고 있습니다. 그렇다면 이를 어떻게 수정할까요?
메서드에 전달한 element 인수를 기억하십니까? 바로 여기서 그 유용함이 드러납니다.
문서를 조회하는 대신, 대상이 되는 요소를 조회합니다. 따라서 이 부분을 다음과 같이 변경합니다.
const goglinks = document.querySelectorAll('a[href*="gog.com"]');
다음과 같이 변경합니다.
const goglinks = element.querySelectorAll('a[href*="gog.com"]');
그리고 최종적으로 다음과 같은 코드가 됩니다.
api.decorateCookedElement(
element => {
// 아래 "my-affiliate-id"를 실제 제휴 ID로 변경하세요
const aid = "my-affiliate-id";
// 링크에 아직 제휴 ID가 없다면 슬래시와 함께 제휴 ID를 추가합니다
-- const goglinks = document.querySelectorAll('a[href*="gog.com"]');
++ const goglinks = element.querySelectorAll('a[href*="gog.com"]');
goglinks.forEach(function (el) {
if (!el.href.includes("pp=")) {
el.href = el.href.replace(/\?.*$/, "") + "?pp=" + aid;
}
});
},
{
// 옵션은 여기에 작성합니다
}
);
이제 잘 작동합니다. 하지만 여전히 조금 더 개선할 수 있습니다. 링크에만 제휴 ID를 추가하는 것이므로, 컴포저(composer)에서 작업할 때 이 코드가 실행되도록 할 필요는 없습니다. 바로 여기서 메서드 옵션이 유용합니다.
메서드에 전달할 수 있는 옵션 중 하나는 onlyStream입니다.
이것은 무엇을 하는 것일까요? 이 코드가 주제(topic) 내에서 게시물이 렌더링될 때만 실행되도록 메서드에 지시합니다. 해당 옵션을 추가해 보겠습니다.
api.decorateCookedElement(
element => {
// 아래 "my-affiliate-id"를 실제 제휴 ID로 변경하세요
const aid = "my-affiliate-id";
// 링크에 아직 제휴 ID가 없다면 슬래시와 함께 제휴 ID를 추가합니다
const goglinks = element.querySelectorAll('a[href*="gog.com"]');
goglinks.forEach(function (el) {
if (!el.href.includes("pp=")) {
el.href = el.href.replace(/\?.*$/, "") + "?pp=" + aid;
}
});
},
{
++ onlyStream: true
}
);
자, 이제 해야 할 일은 이 코드를 앞서 이야기했던 특수 스크립트 태그 안에 넣는 것뿐입니다.
<script type="text/discourse-plugin" version="0.8.42">
api.decorateCookedElement(
element => {
// 아래 "my-affiliate-id"를 실제 제휴 ID로 변경하세요
const aid = "my-affiliate-id";
// 링크에 아직 제휴 ID가 없다면 슬래시와 함께 제휴 ID를 추가합니다
const goglinks = element.querySelectorAll('a[href*="gog.com"]');
goglinks.forEach(function (el) {
if (!el.href.includes("pp=")) {
el.href = el.href.replace(/\?.*$/, "") + "?pp=" + aid;
}
});
},
{
onlyStream: true
}
);
</script>
그 다음, 이 코드를 컴포넌트의 헤더 탭에 추가하면 준비 완료입니다. 이 예제에서는 GOG를 사용했지만, 이는 질문하신 내용 때문이며, URL 구조만 알면 어떤 제휴 프로그램에도 이 패턴을 사용할 수 있습니다.