テンプレート処理中にエラーが発生しました。
The following has evaluated to null or missing:
==> themeDisplay.getCanonicalURL  [in template "8911408109993434201#23484949#LEARN-ARTICLE" at line 184, column 120]

----
Tip: It's the step after the last dot that caused this error, not those before it.
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----

----
FTL stack trace ("~" means nesting-related):
	- Failed at: ${themeDisplay.getCanonicalURL()}  [in template "8911408109993434201#23484949#LEARN-ARTICLE" at line 184, column 118]
----
1<@liferay_aui.script> 
2	const _addEventListener = (selectors) => { 
3		var elements = document.querySelectorAll(selectors); 
4 
5		elements.forEach((element) => { 
6			element.addEventListener("click", (event) => { 
7				event.preventDefault(); 
8 
9				const anchorElement = document.getElementById(element.getAttribute("id").replace("toc-", "")); 
10 
11				if (anchorElement) { 
12					window.history.pushState( 
13						{}, 
14						"", 
15						"#" + element.getAttribute("id").replace("toc-", "") 
16					); 
17					scrollToElement(anchorElement); 
18
19			}); 
20		}); 
21
22 
23	const scrollToElement = (element) => { 
24		if (!element) return; 
25 
26		window.scrollTo({ 
27			behavior: "smooth", 
28			top: element.getBoundingClientRect().top + window.scrollY - 190, 
29		}); 
30	}; 
31 
32	window.addEventListener('load', function() { 
33		_addEventListener("h1 a, h2 a, h3 a"); 
34		_addEventListener(".toc li a"); 
35 
36		if (window.location.hash) { 
37			const hashLocation = document.getElementById(window.location.hash.substring(1)); 
38 
39			if (hashLocation) { 
40				setTimeout(() => { 
41					scrollToElement(hashLocation); 
42				}, 100); 
43
44
45	}); 
46 </@> 
47 
48<#assign 
49	journalArticleId = .vars["reserved-article-id"].data 
50 
51	structuredContent = restClient.get("/headless-delivery/v1.0/sites/${groupId}/structured-contents/by-key/${journalArticleId}?nestedFields=embeddedTaxonomyCategory") 
52 
53	showChildrenCards = showChildrenCards.getData()?boolean 
54	taxonomyCategoriesMap = {} 
55	taxonomyVocabularies = [] 
56	taxonomyCategoryBriefs = structuredContent.taxonomyCategoryBriefs 
57 
58	navigationJSONObject = jsonFactoryUtil.createJSONObject(htmlUtil.unescape(navigation.getData()?trim)) 
59 
60	breadcrumbJSONArray = navigationJSONObject.getJSONArray("breadcrumb") 
61	childrenJSONArray = navigationJSONObject.getJSONArray("children") 
62/> 
63 
64<#list taxonomyCategoryBriefs as taxonomyCategoryBrief> 
65	<#assign taxonomyVocabularyName = taxonomyCategoryBrief.embeddedTaxonomyCategory.parentTaxonomyVocabulary.name /> 
66 
67	<#if !taxonomyVocabularies?seq_contains(taxonomyVocabularyName)> 
68		<#assign taxonomyVocabularies = taxonomyVocabularies + [taxonomyVocabularyName] /> 
69	</#if> 
70 
71	<#if taxonomyCategoriesMap[taxonomyVocabularyName]?has_content> 
72		<#assign taxonomyCategoriesMap = taxonomyCategoriesMap + 
73
74				taxonomyVocabularyName: 
75					taxonomyCategoriesMap[taxonomyVocabularyName] + [{ 
76						"categoryId": taxonomyCategoryBrief.taxonomyCategoryId, 
77						"categoryName": taxonomyCategoryBrief.taxonomyCategoryName 
78					}] 
79
80		/> 
81	<#else> 
82		<#assign taxonomyCategoriesMap = taxonomyCategoriesMap + 
83
84				taxonomyVocabularyName: 
85					[{ 
86						"categoryId": taxonomyCategoryBrief.taxonomyCategoryId, 
87						"categoryName": taxonomyCategoryBrief.taxonomyCategoryName 
88					}] 
89
90		/> 
91	</#if> 
92</#list> 
93 
94<article class="learn-article"> 
95	<div class="d-flex flex-column"> 
96		<div class="learn-article-wrapper"> 
97			<div class="language-log learn-article-content"> 
98				<#if (content.getData())??> 
99					${content.getData()} 
100				</#if> 
101 
102				<#if showChildrenCards && childrenJSONArray.length() gt 0> 
103					<div class="learn-card-container"> 
104						<#list 0..childrenJSONArray.length()-1 as i> 
105							<#assign childJSONObject = childrenJSONArray.getJSONObject(i) /> 
106 
107							<div class="learn-card"> 
108								<a href="${childJSONObject.getString("url")}"> 
109									<h4>${childJSONObject.getString("title")}</h4> 
110								</a> 
111 
112								<#if childJSONObject.getJSONArray("children")?has_content> 
113									<#assign grandchildrenJSONArray = childJSONObject.getJSONArray("children") /> 
114 
115									<div class="mt-2 subsection"> 
116										<#list 0..grandchildrenJSONArray.length()-1 as j> 
117											<#assign grandchildJSONObject = grandchildrenJSONArray.getJSONObject(j)! /> 
118 
119											<#if grandchildJSONObject?? && grandchildJSONObject["title"]?has_content && grandchildJSONObject["url"]?has_content> 
120												<a href="${grandchildJSONObject["url"]!}"> 
121													${grandchildJSONObject["title"]!} 
122												</a> 
123											</#if> 
124										</#list> 
125									</div> 
126								</#if> 
127							</div> 
128						</#list> 
129					</div> 
130				<#else> 
131					<div class="learn-article-categories-tags"> 
132						<#list taxonomyVocabularies as vocabulary> 
133							<div class="align-items-baseline d-flex mt-2"> 
134								<div class="learn-article-category-title mr-2"> 
135									${vocabulary}: 
136								</div> 
137								<#list taxonomyCategoriesMap[vocabulary]?sort_by("categoryName") as taxonomyCategory> 
138									<div class="learn-article-category-tag mr-2"> 
139										<a 
140											class="label tag-container" 
141											href="/search?${vocabulary?lower_case?replace(" ", "-", "r")}=${taxonomyCategory.categoryId}" 
142
143											<span>${taxonomyCategory.categoryName}</span> 
144										</a> 
145									</div> 
146								</#list> 
147							</div> 
148						</#list> 
149					</div> 
150 
151					<div class="article-related-how-to"> 
152						<#setting url_escaping_charset='UTF-8' /> 
153 
154						<#if (structuredContent.keywords?has_content && structuredContent.keywords?size > 0)> 
155							<#assign 
156								queryParams = { 
157									"fields": "dateModified,id,title", 
158									"filter": "(knowledgeArticleType eq 'howTo') and (status eq 0) and (sourceTeam eq 'Enablement')", 
159									"pageSize": "3", 
160									"search": structuredContent.keywords[0], 
161									"sort": "dateModified:desc" 
162
163								queryParts = [] 
164							/> 
165 
166							<#list queryParams?keys as key> 
167								<#assign 
168									value = queryParams[key] 
169 
170									queryParts = queryParts + ["${key?url}=${value?url}"] 
171								/> 
172							</#list> 
173 
174							<#assign knowledgeArticles = restClient.get("/c/p2s3knowledgearticles/?" + queryParts?join('&')) /> 
175 
176							<#if (knowledgeArticles.totalCount)?has_content && (knowledgeArticles.totalCount > 0)> 
177								<div class="how-to-container"> 
178									<div class="how-to-container-header"> 
179										${languageUtil.get(locale, 'how-to-related-to-this-article')} 
180									</div> 
181 
182									<div class="how-to-cards-container" id="how-to-cards-container"> 
183										<#list knowledgeArticles.items as knowledgeArticle> 
184											<a class="how-to-card" href="${themeDisplay.getCanonicalURL()}/l/${knowledgeArticle.id}/"> 
185												<div class="how-to-card-header"> 
186													${knowledgeArticle.title} 
187												</div> 
188 
189												<div class="how-to-card-date-published"> 
190													<#assign date = knowledgeArticle.dateModified?datetime("MMM dd, yy hh:mm")?string /> 
191 
192													${languageUtil.get(locale, 'published-date')}: ${date} 
193												</div> 
194											</a> 
195										</#list> 
196									</div> 
197								</div> 
198							</#if> 
199						</#if> 
200					</div> 
201				</#if> 
202			</div> 
203		</div> 
204	</div> 
205</article> 
206 
207<style> 
208	.how-to-card { 
209		align-items: flex-start; 
210		background: var(--color-brand-primary-lighten-6, #FBFCFE); 
211		border: 1px solid var(--color-brand-primary-lighten-5, #E7EFFF); 
212		border-radius: 0.75rem; 
213		box-sizing: border-box; 
214		cursor: pointer; 
215		display: flex; 
216		flex-direction: column; 
217		gap: 0.5rem; 
218		isolation: isolate; 
219		justify-content: space-between; 
220		order: 0; 
221		padding: 1rem; 
222		width: 100%; 
223
224 
225	.how-to-card:hover { 
226		background: var(--color-action-primary-hover-10, #EDF3FE); 
227		border: 1px solid var(--color-action-primary-hover, #0053F0); 
228		border-radius: 0.625rem; 
229
230 
231	.how-to-card-date-published { 
232		align-items: center; 
233		align-self: stretch; 
234		color: var(--color-neutral-8, #54555F); 
235		display: flex; 
236		flex: none; 
237		flex-grow: 0; 
238		font-family: 'Source Sans 3'; 
239		font-size: 0.75rem; 
240		font-style: normal; 
241		font-weight: 400; 
242		line-height: 1rem; 
243
244 
245	.how-to-card-header { 
246		align-items: center; 
247		align-self: stretch; 
248		color: var(--color-brand-primary, #0B5FFF); 
249		display: flex; 
250		flex: none; 
251		flex-grow: 0; 
252		font-family: 'Source Sans 3'; 
253		font-size: 1rem; 
254		font-style: normal; 
255		font-weight: 600; 
256		line-height: 1.5rem; 
257
258 
259	.how-to-cards-container { 
260		display: flex; 
261		flex-direction: row; 
262		gap: 1rem; 
263		width: 100%; 
264
265 
266	.how-to-container { 
267		align-items: flex-start; 
268		align-self: stretch; 
269		background: var(--color-neutral-1, #F7F7F8); 
270		border-radius: 0.75rem; 
271		display: flex; 
272		flex: none; 
273		flex-direction: column; 
274		flex-grow: 0; 
275		gap: 1.5rem; 
276		isolation: isolate; 
277		margin: 1.5rem 0px; 
278		order: 0; 
279		padding: 1.5rem; 
280		width: 100%; 
281
282 
283	.how-to-container-header { 
284		align-items: center; 
285		color: var(--color-neutral-10, #282934); 
286		display: flex; 
287		flex: none; 
288		flex-grow: 0; 
289		font-family: 'Source Sans 3'; 
290		font-size: 1.5rem; 
291		font-style: normal; 
292		font-weight: 700; 
293		line-height: 1.75rem; 
294
295 
296	.learn-article { 
297		max-width: 900px !important; 
298
299 
300	@media only screen and (max-width: 1200px) { 
301		.how-to-cards-container { 
302			flex-direction: column; 
303
304
305 
306	@media (max-width: 1024px) { 
307		.learn-article { 
308			margin-top: 2.5rem; 
309
310
311</style>