
sitecore-search
by jorsisu
Reusable AI coding skills for daily workflows
SKILL.md
name: sitecore-search description: Implements Sitecore Search in Next.js with facets, URL synchronization, and SearchUrlManager singleton. Detects anti-patterns like using facetValue.text instead of .id. Use when user mentions Sitecore Search, facets not filtering, search widgets, SearchUrlManager, or URL state management. version: 1.0.0 last_updated: 2024-12-03 source: Shriners XMCloud Next.js v15.3.1
Sitecore Search Expert
Production-tested patterns for implementing Sitecore Search in Next.js with proper URL synchronization, facet handling, and anti-pattern prevention.
When to Invoke
Trigger keywords:
- "Sitecore Search" (implementation, setup, configuration)
- "facets" or "filters" (not filtering, not working)
- "SearchUrlManager" (singleton, URL sync)
- "search widget" (implementation, debugging)
- "URL state" (synchronization, back button, shareability)
- "facetValue" (using .id vs .text)
- Code review for search implementations
Quick Decision Tree
🚀 Implementing from Scratch?
→ Read QUICK-START.md for step-by-step setup
🐛 Debugging Issues?
- Facets not filtering → Read
ANTI-PATTERNS.md#1-2 - URL not updating → Read
ANTI-PATTERNS.md#3, #8 - Back button broken → Read
TROUBLESHOOTING.md"Back button" - Results not appearing → Read
TROUBLESHOOTING.md"No results" - Any search issue → Read
TROUBLESHOOTING.mdfirst
🔍 Code Review?
→ Read ANTI-PATTERNS.md + run scripts/validate-search-code.sh
🏗️ Need Specific Component?
- SearchProvider →
templates/SearchProvider.tsx - SearchUrlManager →
SEARCHURLMANAGER.md+templates/SearchUrlManager.ts - Basic widget →
templates/BasicSearchWidget.tsx - Widget with facets →
templates/SearchWithFacets.tsx - Custom hook →
templates/CustomSearchHook.ts - Load more pagination →
LOAD-MORE-PAGINATION.md
📚 Need Reference?
→ Read REFERENCE.md for TypeScript interfaces and API signatures
Critical Rules
1. Use facetValue.id NOT .text
// ❌ facetValueId: facetValue.text
// ✅ facetValueId: facetValue.id
2. All 5 onFacetClick Parameters Required
actions.onFacetClick({
facetId, facetValueId, type: 'valueId', checked, facetIndex
});
3. Sync SDK → URL
actions.onKeyphraseChange({ keyphrase: term });
if (router.isReady) await searchUrlManager.setSearchTerm(router, term);
Implementation Workflow
- Setup - Install packages, env vars, SearchProvider →
QUICK-START.md - SearchUrlManager - Create singleton with queue/debounce →
SEARCHURLMANAGER.md - Basic Widget - useSearchResults + controlled input + widget() HOC →
templates/BasicSearchWidget.tsx - Add Facets - Extract data, render UI, use
.id, sync URL →FACETS.md - Pagination - Calculate pages, handlePageChange, auto-reset verifies
- Validate - Run
scripts/validate-search-code.sh, test checklist
Common Tasks & File References
| Task | Primary File | Supporting Files |
|---|---|---|
| Setup from scratch | QUICK-START.md | templates/SearchProvider.tsx |
| Implement URL sync | SEARCHURLMANAGER.md | templates/SearchUrlManager.ts |
| Add facets | FACETS.md | templates/SearchWithFacets.tsx |
| Debug facet issues | ANTI-PATTERNS.md #1-2 | scripts/validate-search-code.sh |
| Fix URL sync | ANTI-PATTERNS.md #3, #8 | TROUBLESHOOTING.md |
| Code review | ANTI-PATTERNS.md (all 10) | scripts/validate-search-code.sh |
| TypeScript types | REFERENCE.md | - |
| Custom search hook | templates/CustomSearchHook.ts | - |
Anti-Pattern Quick Reference
Run validation: bash scripts/validate-search-code.sh <file.tsx>
Top 5 bugs (90% of issues):
- ❌ Using
facetValue.textinstead of.id - ❌ Missing required
onFacetClickparameters - ❌ Skipping URL synchronization
- ❌ Not checking
router.isReady - ❌ Client-side filtering of results
Full list: ANTI-PATTERNS.md
SearchUrlManager Auto-Behaviors
These methods auto-reset pagination to page 1:
setSearchTerm(router, term)addFacet(router, facetId, valueId)removeFacet(router, facetId, valueId)setTab(router, tabId)clearAllFacets(router)clearAllFilters(router)
This method does NOT reset:
setPage(router, page)- Only updates page number
Don't manually reset pagination - SearchUrlManager handles it automatically.
Load More / Cumulative Results Pattern
Implementation Strategy:
- State: Maintain
accumulatedResultsstate in the widget. - Effect: Update state in
useEffectwhenresultschange. - Append: If
offset > previousOffset, append new results ([...prev, ...new]). - Reset: If
offset === 0, replace results ([...new]). - Deduplicate: Use
new Set(prev.map(i => i.id))to prevent duplicates.
Critical: Preventing Infinite Loops When resetting to page 1 (facet change), React can cycle infinitely if not guarded.
// ✅ Correct Guard Pattern
if (offset === 0 && previousOffsetRef.current !== 0) {
// Only reset when GOING TO page 1 from another page
setAccumulatedResults(results);
} else if (offset === 0 && results.length !== prevLenRef.current) {
// Or if content changed while staying on page 1
setAccumulatedResults(results);
}
Deep Linking Support (Page > 1)
When a user lands on ?p=3:
- Initial Load: Set
limit = 3 * itemsPerPageto fetch pages 1-3 at once. - Subsequent: On next "Load More", switch back to
limit = itemsPerPage.
Display Component Use a specialized summary component that understands the difference:
- Standard: "Showing 21-30 of 100"
- Cumulative: "Showing 1-30 of 100" (Pass
accumulatedCountprop)
Facets not filtering?
// Check 1: Using .id?
console.log('Facet value:', facetValue.id); // Should use this
// Check 2: All 5 params?
actions.onFacetClick({
facetId, facetValueId, type, checked, facetIndex // All present?
});
// Check 3: URL updating?
console.log('URL facets:', router.query.facets);
URL not updating?
// Check 1: Router ready?
console.log('Router ready:', router.isReady); // Must be true
// Check 2: SearchUrlManager called?
await searchUrlManager.setSearchTerm(router, term); // After actions
// Check 3: Shallow routing?
router.push({ ... }, undefined, { shallow: true }); // Required
Back button broken?
// Check: Syncing on URL change?
useEffect(() => {
if (!router.isReady) return;
searchUrlManager.syncFromUrl(router);
}, [router.query, router.isReady]); // Must listen to router.query
File Organization Reference
~/.claude/skills/sitecore-search/
├── SKILL.md # This file - Start here
├── QUICK-START.md # Step-by-step setup guide
├── SEARCHURLMANAGER.md # URL sync implementation
├── FACETS.md # Facet pattern library
├── ANTI-PATTERNS.md # 10 critical anti-patterns
├── TROUBLESHOOTING.md # Issue → solution mappings
├── REFERENCE.md # TypeScript interfaces & APIs
├── templates/
│ ├── SearchProvider.tsx # Provider setup
│ ├── SearchUrlManager.ts # Singleton implementation
│ ├── BasicSearchWidget.tsx # Simple search widget
│ ├── SearchWithFacets.tsx # Widget with facets
│ └── CustomSearchHook.ts # Custom hook pattern
└── scripts/
└── validate-search-code.sh # Anti-pattern checker
Success Criteria
Implementation is correct when:
- ✅ Search returns results
- ✅ Facets filter (using
facetValue.id) - ✅ Pagination works and auto-resets
- ✅ URL updates on all state changes
- ✅ Browser back/forward works
- ✅ Page refresh maintains state
- ✅ Shareable URLs work
- ✅ No console errors
- ✅ No client-side filtering
- ✅ Clear filters resets all 3 layers
Validation: Run scripts/validate-search-code.sh - should pass all checks.
Next Steps
- First time implementing? → Read
QUICK-START.md - Have an issue? → Read
TROUBLESHOOTING.md - Need code review? → Read
ANTI-PATTERNS.md - Need a template? → Check
templates/directory - Need reference? → Read
REFERENCE.md
Remember: The 3 critical rules prevent 80% of bugs. Use facetValue.id, include all 5 parameters, sync SDK → URL.
スコア
総合スコア
リポジトリの品質指標に基づく評価
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
レビュー
レビュー機能は近日公開予定です