[{"data":1,"prerenderedAt":5156},["ShallowReactive",2],{"navigation":3,"search":709,"\u002Flibraries\u002Fquery-api-next\u002Fmiddleware\u002Fmiddleware-surround":4221,"\u002Flibraries\u002Fquery-api-next\u002Fmiddleware\u002Fmiddleware":4225},[4],{"title":5,"path":6,"stem":7,"children":8,"page":32},"Libraries","\u002Flibraries","2.libraries",[9,97,113,149,206,241,264,354,377,401,489,581,650],{"title":10,"path":11,"stem":12,"children":13,"badge":96},"CoPilot","\u002Flibraries\u002Fcraft-co-pilot","2.libraries\u002Fcraft-co-pilot\u002Findex",[14,33,58,67],{"title":15,"path":16,"stem":17,"children":18,"page":32},"Get Started","\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started","2.libraries\u002Fcraft-co-pilot\u002F1.get-started",[19,24,28],{"title":20,"path":21,"stem":22,"badge":23},"Installation & Setup","\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Finstallation","2.libraries\u002Fcraft-co-pilot\u002F1.get-started\u002F1.installation",null,{"title":25,"path":26,"stem":27,"badge":23},"AI Providers","\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fai-provider","2.libraries\u002Fcraft-co-pilot\u002F1.get-started\u002F2.ai-provider",{"title":29,"path":30,"stem":31,"badge":23},"Configuration","\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration","2.libraries\u002Fcraft-co-pilot\u002F1.get-started\u002F3.configuration",false,{"title":34,"path":35,"stem":36,"children":37,"page":32},"Usage","\u002Flibraries\u002Fcraft-co-pilot\u002Fusage","2.libraries\u002Fcraft-co-pilot\u002F2.usage",[38,42,46,50,54],{"title":39,"path":40,"stem":41,"badge":23},"Chat","\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fchat","2.libraries\u002Fcraft-co-pilot\u002F2.usage\u002F1.chat",{"title":43,"path":44,"stem":45,"badge":23},"Brand Voice","\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fbrand-voice","2.libraries\u002Fcraft-co-pilot\u002F2.usage\u002F2.brand-voice",{"title":47,"path":48,"stem":49,"badge":23},"Tools","\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Ftools","2.libraries\u002Fcraft-co-pilot\u002F2.usage\u002F3.tools",{"title":51,"path":52,"stem":53,"badge":23},"Permissions","\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fpermissions","2.libraries\u002Fcraft-co-pilot\u002F2.usage\u002F4.permissions",{"title":55,"path":56,"stem":57,"badge":23},"Audit Log","\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Faudit-log","2.libraries\u002Fcraft-co-pilot\u002F2.usage\u002F5.audit-log",{"title":59,"path":60,"stem":61,"children":62,"page":32},"Integrations","\u002Flibraries\u002Fcraft-co-pilot\u002Fintegrations","2.libraries\u002Fcraft-co-pilot\u002F3.integrations",[63],{"title":64,"path":65,"stem":66,"badge":23},"Third Party Fields","\u002Flibraries\u002Fcraft-co-pilot\u002Fintegrations\u002Fthird-party-fields","2.libraries\u002Fcraft-co-pilot\u002F3.integrations\u002F1.third-party-fields",{"title":68,"path":69,"stem":70,"children":71,"page":32},"Developers","\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers","2.libraries\u002Fcraft-co-pilot\u002F4.developers",[72,76,80,84,88,92],{"title":73,"path":74,"stem":75,"badge":23},"Custom Commands","\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-commands","2.libraries\u002Fcraft-co-pilot\u002F4.developers\u002Fcustom-commands",{"title":77,"path":78,"stem":79,"badge":23},"Custom Elements","\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-elements","2.libraries\u002Fcraft-co-pilot\u002F4.developers\u002Fcustom-elements",{"title":81,"path":82,"stem":83,"badge":23},"Custom Fields","\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-fields","2.libraries\u002Fcraft-co-pilot\u002F4.developers\u002Fcustom-fields",{"title":85,"path":86,"stem":87,"badge":23},"Custom Providers","\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-providers","2.libraries\u002Fcraft-co-pilot\u002F4.developers\u002Fcustom-providers",{"title":89,"path":90,"stem":91,"badge":23},"Custom Tools","\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-tools","2.libraries\u002Fcraft-co-pilot\u002F4.developers\u002Fcustom-tools",{"title":93,"path":94,"stem":95,"badge":23},"System Prompt","\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fsystem-prompt","2.libraries\u002Fcraft-co-pilot\u002F4.developers\u002Fsystem-prompt","New",{"title":98,"path":99,"stem":100,"children":101,"badge":96},"Custom Queue Manager","\u002Flibraries\u002Fcraft-custom-queue-manager","2.libraries\u002Fcraft-custom-queue-manager\u002Findex",[102],{"title":15,"path":103,"stem":104,"children":105,"page":32},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started","2.libraries\u002Fcraft-custom-queue-manager\u002F1.get-started",[106,110],{"title":107,"path":108,"stem":109,"badge":23},"Installation","\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Finstallation","2.libraries\u002Fcraft-custom-queue-manager\u002F1.get-started\u002F1.installation",{"title":29,"path":111,"stem":112,"badge":23},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Fconfiguration","2.libraries\u002Fcraft-custom-queue-manager\u002F1.get-started\u002F2.configuration",{"title":114,"path":115,"stem":116,"children":117,"badge":23},"Genesis","\u002Flibraries\u002Fcraft-genesis","2.libraries\u002Fcraft-genesis\u002Findex",[118,125],{"title":15,"path":119,"stem":120,"children":121,"page":32},"\u002Flibraries\u002Fcraft-genesis\u002Fget-started","2.libraries\u002Fcraft-genesis\u002F1.get-started",[122],{"title":107,"path":123,"stem":124,"badge":23},"\u002Flibraries\u002Fcraft-genesis\u002Fget-started\u002Finstallation","2.libraries\u002Fcraft-genesis\u002F1.get-started\u002Finstallation",{"title":34,"path":126,"stem":127,"children":128,"page":32},"\u002Flibraries\u002Fcraft-genesis\u002Fusage","2.libraries\u002Fcraft-genesis\u002F2.usage",[129,133,137,141,145],{"title":130,"path":131,"stem":132,"badge":23},"Sites Import","\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsites","2.libraries\u002Fcraft-genesis\u002F2.usage\u002F1.sites",{"title":134,"path":135,"stem":136,"badge":23},"Entry Types Import","\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fentry-types","2.libraries\u002Fcraft-genesis\u002F2.usage\u002F2.entry-types",{"title":138,"path":139,"stem":140,"badge":23},"Sections Import","\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsections","2.libraries\u002Fcraft-genesis\u002F2.usage\u002F3.sections",{"title":142,"path":143,"stem":144,"badge":23},"Filesystems Import","\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Ffilesystems","2.libraries\u002Fcraft-genesis\u002F2.usage\u002F4.filesystems",{"title":146,"path":147,"stem":148,"badge":23},"Assets Import","\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fassets","2.libraries\u002Fcraft-genesis\u002F2.usage\u002F5.assets",{"title":150,"path":151,"stem":152,"children":153,"badge":96},"Insights","\u002Flibraries\u002Fcraft-insights","2.libraries\u002Fcraft-insights\u002Findex",[154,164,185],{"title":15,"path":155,"stem":156,"children":157,"page":32},"\u002Flibraries\u002Fcraft-insights\u002Fget-started","2.libraries\u002Fcraft-insights\u002F1.get-started",[158,161],{"title":107,"path":159,"stem":160,"badge":23},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Finstallation","2.libraries\u002Fcraft-insights\u002F1.get-started\u002F1.installation",{"title":29,"path":162,"stem":163,"badge":23},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration","2.libraries\u002Fcraft-insights\u002F1.get-started\u002F2.configuration",{"title":165,"path":166,"stem":167,"children":168,"page":32},"Knowledge","\u002Flibraries\u002Fcraft-insights\u002Fknowledge","2.libraries\u002Fcraft-insights\u002F2.knowledge",[169,173,177,181],{"title":170,"path":171,"stem":172,"badge":23},"Overview","\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Foverview","2.libraries\u002Fcraft-insights\u002F2.knowledge\u002F1.overview",{"title":174,"path":175,"stem":176,"badge":23},"Feature Tour","\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour","2.libraries\u002Fcraft-insights\u002F2.knowledge\u002F2.feature-tour",{"title":178,"path":179,"stem":180,"badge":23},"Privacy & GDPR","\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy","2.libraries\u002Fcraft-insights\u002F2.knowledge\u002F3.privacy",{"title":182,"path":183,"stem":184,"badge":23},"Metrics Reference","\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works","2.libraries\u002Fcraft-insights\u002F2.knowledge\u002F4.how-tracking-works",{"title":34,"path":186,"stem":187,"children":188,"page":32},"\u002Flibraries\u002Fcraft-insights\u002Fusage","2.libraries\u002Fcraft-insights\u002F3.usage",[189,193,198,202],{"title":190,"path":191,"stem":192,"badge":23},"Twig Functions","\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Ftwig-api","2.libraries\u002Fcraft-insights\u002F3.usage\u002F1.twig-api",{"title":194,"path":195,"stem":196,"badge":197},"User Events","\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fuser-events","2.libraries\u002Fcraft-insights\u002F3.usage\u002F2.user-events","Pro",{"title":199,"path":200,"stem":201,"badge":197},"Outbound Link Tracking","\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Foutbound-tracking","2.libraries\u002Fcraft-insights\u002F3.usage\u002F3.outbound-tracking",{"title":203,"path":204,"stem":205,"badge":197},"Search Tracking","\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking","2.libraries\u002Fcraft-insights\u002F3.usage\u002F4.search-tracking",{"title":207,"path":208,"stem":209,"children":210,"badge":23},"LLMify","\u002Flibraries\u002Fcraft-llmify","2.libraries\u002Fcraft-llmify\u002Findex",[211,221],{"title":15,"path":212,"stem":213,"children":214,"page":32},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started","2.libraries\u002Fcraft-llmify\u002F1.get-started",[215,218],{"title":20,"path":216,"stem":217,"badge":23},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Finstallation","2.libraries\u002Fcraft-llmify\u002F1.get-started\u002F1.installation",{"title":29,"path":219,"stem":220,"badge":23},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig","2.libraries\u002Fcraft-llmify\u002F1.get-started\u002F2.config",{"title":34,"path":222,"stem":223,"children":224,"page":32},"\u002Flibraries\u002Fcraft-llmify\u002Fusage","2.libraries\u002Fcraft-llmify\u002F2.usage",[225,229,233,237],{"title":226,"path":227,"stem":228,"badge":23},"Basic Overview","\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fbasic-overview","2.libraries\u002Fcraft-llmify\u002F2.usage\u002F1.basic-overview",{"title":230,"path":231,"stem":232,"badge":23},"Content Control","\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fcontent-control","2.libraries\u002Fcraft-llmify\u002F2.usage\u002F2.content-control",{"title":234,"path":235,"stem":236,"badge":23},"Content Delivery","\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fauto-serve","2.libraries\u002Fcraft-llmify\u002F2.usage\u002F3.auto-serve",{"title":238,"path":239,"stem":240,"badge":23},"Console Commands","\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fconsole-commands","2.libraries\u002Fcraft-llmify\u002F2.usage\u002F4.console-commands",{"title":242,"path":243,"stem":244,"children":245,"badge":23},"Loanwords","\u002Flibraries\u002Fcraft-loanwords","2.libraries\u002Fcraft-loanwords\u002Findex",[246,256],{"title":15,"path":247,"stem":248,"children":249,"page":32},"\u002Flibraries\u002Fcraft-loanwords\u002Fget-started","2.libraries\u002Fcraft-loanwords\u002F1.get-started",[250,253],{"title":107,"path":251,"stem":252,"badge":23},"\u002Flibraries\u002Fcraft-loanwords\u002Fget-started\u002Finstallation","2.libraries\u002Fcraft-loanwords\u002F1.get-started\u002F1.installation",{"title":34,"path":254,"stem":255,"badge":23},"\u002Flibraries\u002Fcraft-loanwords\u002Fget-started\u002Fusage","2.libraries\u002Fcraft-loanwords\u002F1.get-started\u002F2.usage",{"title":29,"path":257,"stem":258,"children":259,"page":32},"\u002Flibraries\u002Fcraft-loanwords\u002Fconfiguration","2.libraries\u002Fcraft-loanwords\u002F2.configuration",[260],{"title":261,"path":262,"stem":263,"badge":23},"Config","\u002Flibraries\u002Fcraft-loanwords\u002Fconfiguration\u002Fconfig","2.libraries\u002Fcraft-loanwords\u002F2.configuration\u002F1.config",{"title":265,"path":266,"stem":267,"children":268,"badge":23},"Query API","\u002Flibraries\u002Fcraft-query-api","2.libraries\u002Fcraft-query-api\u002F1.index",[269,284,296,315,328,345],{"title":15,"path":270,"stem":271,"children":272,"page":32},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started","2.libraries\u002Fcraft-query-api\u002F2.get-started",[273,277,280],{"title":274,"path":275,"stem":276,"badge":23},"Introduction","\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Fintroduction","2.libraries\u002Fcraft-query-api\u002F2.get-started\u002F1.introduction",{"title":107,"path":278,"stem":279,"badge":23},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Finstall","2.libraries\u002Fcraft-query-api\u002F2.get-started\u002F2.install",{"title":281,"path":282,"stem":283,"badge":23},"First Steps","\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Ffirst-steps","2.libraries\u002Fcraft-query-api\u002F2.get-started\u002F3.first-steps",{"title":59,"path":285,"stem":286,"children":287,"page":32},"\u002Flibraries\u002Fcraft-query-api\u002Fintegrations","2.libraries\u002Fcraft-query-api\u002F3.integrations",[288,292],{"title":289,"path":290,"stem":291,"badge":23},"ImagerX","\u002Flibraries\u002Fcraft-query-api\u002Fintegrations\u002Fimager-x","2.libraries\u002Fcraft-query-api\u002F3.integrations\u002Fimager-x",{"title":293,"path":294,"stem":295,"badge":23},"SEOmatic","\u002Flibraries\u002Fcraft-query-api\u002Fintegrations\u002Fseo-matic","2.libraries\u002Fcraft-query-api\u002F3.integrations\u002Fseo-matic",{"title":34,"path":297,"stem":298,"children":299,"page":32},"\u002Flibraries\u002Fcraft-query-api\u002Fusage","2.libraries\u002Fcraft-query-api\u002F4.usage",[300,303,307,311],{"title":34,"path":301,"stem":302,"badge":23},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fusage","2.libraries\u002Fcraft-query-api\u002F4.usage\u002F1.usage",{"title":304,"path":305,"stem":306,"badge":23},"Caching","\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fcaching","2.libraries\u002Fcraft-query-api\u002F4.usage\u002F2.caching",{"title":308,"path":309,"stem":310,"badge":23},"Settings","\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fsettings","2.libraries\u002Fcraft-query-api\u002F4.usage\u002F3.settings",{"title":312,"path":313,"stem":314,"badge":23},"Commands","\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fcommands","2.libraries\u002Fcraft-query-api\u002F4.usage\u002F4.commands",{"title":316,"path":317,"stem":318,"children":319,"page":32},"Endpoints","\u002Flibraries\u002Fcraft-query-api\u002Fendpoints","2.libraries\u002Fcraft-query-api\u002F5.endpoints",[320,324],{"title":321,"path":322,"stem":323,"badge":23},"customQuery","\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fcustom-query","2.libraries\u002Fcraft-query-api\u002F5.endpoints\u002F1.custom-query",{"title":325,"path":326,"stem":327,"badge":23},"allRoutes","\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fall-routes","2.libraries\u002Fcraft-query-api\u002F5.endpoints\u002F2.all-routes",{"title":329,"path":330,"stem":331,"children":332,"page":32},"Events","\u002Flibraries\u002Fcraft-query-api\u002Fevents","2.libraries\u002Fcraft-query-api\u002F6.events",[333,337,341],{"title":334,"path":335,"stem":336,"badge":23},"Custom Transformers","\u002Flibraries\u002Fcraft-query-api\u002Fevents\u002Fadd-custom-transformer","2.libraries\u002Fcraft-query-api\u002F6.events\u002F1.add-custom-transformer",{"title":338,"path":339,"stem":340,"badge":23},"Custom Element Types","\u002Flibraries\u002Fcraft-query-api\u002Fevents\u002Fadd-custom-element-type","2.libraries\u002Fcraft-query-api\u002F6.events\u002F2.add-custom-element-type",{"title":342,"path":343,"stem":344,"badge":23},"Custom Typescript Types","\u002Flibraries\u002Fcraft-query-api\u002Fevents\u002Fadd-custom-ts-types","2.libraries\u002Fcraft-query-api\u002F6.events\u002F3.add-custom-ts-types",{"title":346,"path":347,"stem":348,"children":349,"page":32},"Deployment","\u002Flibraries\u002Fcraft-query-api\u002Fdeployment","2.libraries\u002Fcraft-query-api\u002F7.deployment",[350],{"title":351,"path":352,"stem":353,"badge":23},"Nuxt","\u002Flibraries\u002Fcraft-query-api\u002Fdeployment\u002Fnuxt","2.libraries\u002Fcraft-query-api\u002F7.deployment\u002F1.nuxt",{"title":355,"path":356,"stem":357,"children":358,"badge":23},"Quick Edit","\u002Flibraries\u002Fcraft-quick-edit","2.libraries\u002Fcraft-quick-edit\u002Findex",[359,369],{"title":15,"path":360,"stem":361,"children":362,"page":32},"\u002Flibraries\u002Fcraft-quick-edit\u002Fget-started","2.libraries\u002Fcraft-quick-edit\u002F1.get-started",[363,366],{"title":107,"path":364,"stem":365,"badge":23},"\u002Flibraries\u002Fcraft-quick-edit\u002Fget-started\u002Finstallation","2.libraries\u002Fcraft-quick-edit\u002F1.get-started\u002F1.installation",{"title":34,"path":367,"stem":368,"badge":23},"\u002Flibraries\u002Fcraft-quick-edit\u002Fget-started\u002Fusage","2.libraries\u002Fcraft-quick-edit\u002F1.get-started\u002F2.usage",{"title":370,"path":371,"stem":372,"children":373,"page":32},"Cofiguration","\u002Flibraries\u002Fcraft-quick-edit\u002Fcofiguration","2.libraries\u002Fcraft-quick-edit\u002F2.cofiguration",[374],{"title":261,"path":375,"stem":376,"badge":23},"\u002Flibraries\u002Fcraft-quick-edit\u002Fcofiguration\u002Fconfig","2.libraries\u002Fcraft-quick-edit\u002F2.cofiguration\u002F1.config",{"title":378,"path":379,"stem":380,"children":381,"badge":23},"@query-api\u002Fjs","\u002Flibraries\u002Fjs-craftcms-api","2.libraries\u002Fjs-craftcms-api\u002F1.index",[382,385,389],{"title":107,"path":383,"stem":384,"badge":23},"\u002Flibraries\u002Fjs-craftcms-api\u002Finstall","2.libraries\u002Fjs-craftcms-api\u002F2.install",{"title":386,"path":387,"stem":388,"badge":23},"Methods","\u002Flibraries\u002Fjs-craftcms-api\u002Fmethods","2.libraries\u002Fjs-craftcms-api\u002F3.methods",{"title":34,"path":390,"stem":391,"children":392,"page":32},"\u002Flibraries\u002Fjs-craftcms-api\u002Fusage","2.libraries\u002Fjs-craftcms-api\u002F4.usage",[393,397],{"title":394,"path":395,"stem":396,"badge":23},"Basic Usage","\u002Flibraries\u002Fjs-craftcms-api\u002Fusage\u002Fusage","2.libraries\u002Fjs-craftcms-api\u002F4.usage\u002F1.usage",{"title":398,"path":399,"stem":400,"badge":23},"Advanced Usage","\u002Flibraries\u002Fjs-craftcms-api\u002Fusage\u002Fadvanced-usage","2.libraries\u002Fjs-craftcms-api\u002F4.usage\u002F2.advanced-usage",{"title":402,"path":403,"stem":404,"children":405,"badge":23},"@query-api\u002Fnuxt","\u002Flibraries\u002Fnuxt-craftcms","2.libraries\u002Fnuxt-craftcms\u002F1.index",[406,424,443,472],{"title":15,"path":407,"stem":408,"children":409,"page":32},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started","2.libraries\u002Fnuxt-craftcms\u002F2.get-started",[410,413,417,421],{"title":274,"path":411,"stem":412,"badge":23},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fintroduction","2.libraries\u002Fnuxt-craftcms\u002F2.get-started\u002F1.introduction",{"title":414,"path":415,"stem":416,"badge":23},"Quick Start","\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fquick-start","2.libraries\u002Fnuxt-craftcms\u002F2.get-started\u002F2.quick-start",{"title":418,"path":419,"stem":420,"badge":23},"Manual Setup","\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fmanual-setup","2.libraries\u002Fnuxt-craftcms\u002F2.get-started\u002F3.manual-setup",{"title":29,"path":422,"stem":423,"badge":23},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fconfiguration","2.libraries\u002Fnuxt-craftcms\u002F2.get-started\u002F4.configuration",{"title":34,"path":425,"stem":426,"children":427,"page":32},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage","2.libraries\u002Fnuxt-craftcms\u002F3.usage",[428,431,435,439],{"title":394,"path":429,"stem":430,"badge":23},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fbasic-usage","2.libraries\u002Fnuxt-craftcms\u002F3.usage\u002F1.basic-usage",{"title":432,"path":433,"stem":434,"badge":23},"Content Driven Components","\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fconnect-components","2.libraries\u002Fnuxt-craftcms\u002F3.usage\u002F2.connect-components",{"title":436,"path":437,"stem":438,"badge":23},"Manual Queries","\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fmanuel-queries","2.libraries\u002Fnuxt-craftcms\u002F3.usage\u002F3.manuel-queries",{"title":440,"path":441,"stem":442,"badge":23},"Examples","\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fexamples","2.libraries\u002Fnuxt-craftcms\u002F3.usage\u002F4.examples",{"title":444,"path":445,"stem":446,"children":447,"page":32},"Composables","\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables","2.libraries\u002Fnuxt-craftcms\u002F4.composables",[448,452,456,460,464,468],{"title":449,"path":450,"stem":451,"badge":23},"useCraftQuery","\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-query","2.libraries\u002Fnuxt-craftcms\u002F4.composables\u002F1.use-craft-query",{"title":453,"path":454,"stem":455,"badge":23},"useCraftCurrentSite","\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-current-site","2.libraries\u002Fnuxt-craftcms\u002F4.composables\u002F2.use-craft-current-site",{"title":457,"path":458,"stem":459,"badge":23},"useCraftUri","\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-uri","2.libraries\u002Fnuxt-craftcms\u002F4.composables\u002F3.use-craft-uri",{"title":461,"path":462,"stem":463,"badge":23},"useCraftFetch","\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-fetch","2.libraries\u002Fnuxt-craftcms\u002F4.composables\u002F4.use-craft-fetch",{"title":465,"path":466,"stem":467,"badge":23},"useCraftSeoMatic","\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-seo-matic","2.libraries\u002Fnuxt-craftcms\u002F4.composables\u002F5.use-craft-seo-matic",{"title":469,"path":470,"stem":471,"badge":23},"useCraftAuthToken","\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-auth-token","2.libraries\u002Fnuxt-craftcms\u002F4.composables\u002F6.use-craft-auth-token",{"title":473,"path":474,"stem":475,"children":476,"page":32},"Components","\u002Flibraries\u002Fnuxt-craftcms\u002Fcomponents","2.libraries\u002Fnuxt-craftcms\u002F5.components",[477,481,485],{"title":478,"path":479,"stem":480,"badge":23},"CraftPage","\u002Flibraries\u002Fnuxt-craftcms\u002Fcomponents\u002Fcraft-page","2.libraries\u002Fnuxt-craftcms\u002F5.components\u002F1.craft-page",{"title":482,"path":483,"stem":484,"badge":23},"CraftArea","\u002Flibraries\u002Fnuxt-craftcms\u002Fcomponents\u002Fcraft-area","2.libraries\u002Fnuxt-craftcms\u002F5.components\u002F2.craft-area",{"title":486,"path":487,"stem":488,"badge":23},"CraftNotImplemented","\u002Flibraries\u002Fnuxt-craftcms\u002Fcomponents\u002Fcraft-not-implemented","2.libraries\u002Fnuxt-craftcms\u002F5.components\u002F3.craft-not-implemented",{"title":490,"path":491,"stem":492,"children":493,"badge":23},"@query-api\u002Fnext","\u002Flibraries\u002Fquery-api-next","2.libraries\u002Fquery-api-next\u002F1.index",[494,514,539,560,573],{"title":15,"path":495,"stem":496,"children":497,"page":32},"\u002Flibraries\u002Fquery-api-next\u002Fget-started","2.libraries\u002Fquery-api-next\u002F2.get-started",[498,501,504,507,510],{"title":274,"path":499,"stem":500,"badge":23},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fintroduction","2.libraries\u002Fquery-api-next\u002F2.get-started\u002F1.introduction",{"title":414,"path":502,"stem":503,"badge":23},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fquick-start","2.libraries\u002Fquery-api-next\u002F2.get-started\u002F2.quick-start",{"title":418,"path":505,"stem":506,"badge":23},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fmanual-setup","2.libraries\u002Fquery-api-next\u002F2.get-started\u002F3.manual-setup",{"title":29,"path":508,"stem":509,"badge":23},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fconfiguration","2.libraries\u002Fquery-api-next\u002F2.get-started\u002F4.configuration",{"title":511,"path":512,"stem":513,"badge":23},"Implementation Details","\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fimplementation-details","2.libraries\u002Fquery-api-next\u002F2.get-started\u002F5.implementation-details",{"title":515,"path":516,"stem":517,"children":518,"page":32},"Functions","\u002Flibraries\u002Fquery-api-next\u002Ffunctions","2.libraries\u002Fquery-api-next\u002F3.functions",[519,523,527,531,535],{"title":520,"path":521,"stem":522,"badge":23},"getCraftQuery","\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-query","2.libraries\u002Fquery-api-next\u002F3.functions\u002F1.get-craft-query",{"title":524,"path":525,"stem":526,"badge":23},"getCraftData","\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-data","2.libraries\u002Fquery-api-next\u002F3.functions\u002F2.get-craft-data",{"title":528,"path":529,"stem":530,"badge":23},"getCraftCurrentSite","\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-current-site","2.libraries\u002Fquery-api-next\u002F3.functions\u002F3.get-craft-current-site",{"title":532,"path":533,"stem":534,"badge":23},"getCraftUri","\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-uri","2.libraries\u002Fquery-api-next\u002F3.functions\u002F4.get-craft-uri",{"title":536,"path":537,"stem":538,"badge":23},"getCraftAuthToken","\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-auth-token","2.libraries\u002Fquery-api-next\u002F3.functions\u002F5.get-craft-auth-token",{"title":540,"path":541,"stem":542,"children":543,"page":32},"Hooks","\u002Flibraries\u002Fquery-api-next\u002Fhooks","2.libraries\u002Fquery-api-next\u002F4.hooks",[544,547,551,554,557],{"title":449,"path":545,"stem":546,"badge":23},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-query","2.libraries\u002Fquery-api-next\u002F4.hooks\u002F1.use-craft-query",{"title":548,"path":549,"stem":550,"badge":23},"useCraftData","\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-data","2.libraries\u002Fquery-api-next\u002F4.hooks\u002F2.use-craft-data",{"title":453,"path":552,"stem":553,"badge":23},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-current-site","2.libraries\u002Fquery-api-next\u002F4.hooks\u002F3.use-craft-current-site",{"title":457,"path":555,"stem":556,"badge":23},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-uri","2.libraries\u002Fquery-api-next\u002F4.hooks\u002F4.use-craft-uri",{"title":469,"path":558,"stem":559,"badge":23},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-auth-token","2.libraries\u002Fquery-api-next\u002F4.hooks\u002F5.use-craft-auth-token",{"title":473,"path":561,"stem":562,"children":563,"page":32},"\u002Flibraries\u002Fquery-api-next\u002Fcomponents","2.libraries\u002Fquery-api-next\u002F5.components",[564,567,570],{"title":478,"path":565,"stem":566,"badge":23},"\u002Flibraries\u002Fquery-api-next\u002Fcomponents\u002Fcraft-page","2.libraries\u002Fquery-api-next\u002F5.components\u002F1.craft-page",{"title":482,"path":568,"stem":569,"badge":23},"\u002Flibraries\u002Fquery-api-next\u002Fcomponents\u002Fcraft-area","2.libraries\u002Fquery-api-next\u002F5.components\u002F2.craft-area",{"title":486,"path":571,"stem":572,"badge":23},"\u002Flibraries\u002Fquery-api-next\u002Fcomponents\u002Fcraft-not-implemented","2.libraries\u002Fquery-api-next\u002F5.components\u002F3.craft-not-implemented",{"title":574,"path":575,"stem":576,"children":577,"page":32},"Middleware","\u002Flibraries\u002Fquery-api-next\u002Fmiddleware","2.libraries\u002Fquery-api-next\u002F6.middleware",[578],{"title":574,"path":579,"stem":580,"badge":23},"\u002Flibraries\u002Fquery-api-next\u002Fmiddleware\u002Fmiddleware","2.libraries\u002Fquery-api-next\u002F6.middleware\u002Fmiddleware",{"title":582,"path":583,"stem":584,"children":585,"badge":23},"@query-api\u002Freact","\u002Flibraries\u002Fquery-api-react","2.libraries\u002Fquery-api-react\u002F1.index",[586,602,621,634],{"title":15,"path":587,"stem":588,"children":589,"page":32},"\u002Flibraries\u002Fquery-api-react\u002Fget-started","2.libraries\u002Fquery-api-react\u002F2.get-started",[590,593,596,599],{"title":274,"path":591,"stem":592,"badge":23},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fintroduction","2.libraries\u002Fquery-api-react\u002F2.get-started\u002F1.introduction",{"title":414,"path":594,"stem":595,"badge":23},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fquick-start","2.libraries\u002Fquery-api-react\u002F2.get-started\u002F2.quick-start",{"title":418,"path":597,"stem":598,"badge":23},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fmanual-setup","2.libraries\u002Fquery-api-react\u002F2.get-started\u002F3.manual-setup",{"title":29,"path":600,"stem":601,"badge":23},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fconfiguration","2.libraries\u002Fquery-api-react\u002F2.get-started\u002F4.configuration",{"title":540,"path":603,"stem":604,"children":605,"page":32},"\u002Flibraries\u002Fquery-api-react\u002Fhooks","2.libraries\u002Fquery-api-react\u002F3.hooks",[606,609,612,615,618],{"title":449,"path":607,"stem":608,"badge":23},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-query","2.libraries\u002Fquery-api-react\u002F3.hooks\u002F1.use-craft-query",{"title":548,"path":610,"stem":611,"badge":23},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-data","2.libraries\u002Fquery-api-react\u002F3.hooks\u002F2.use-craft-data",{"title":453,"path":613,"stem":614,"badge":23},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-current-site","2.libraries\u002Fquery-api-react\u002F3.hooks\u002F3.use-craft-current-site",{"title":457,"path":616,"stem":617,"badge":23},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-uri","2.libraries\u002Fquery-api-react\u002F3.hooks\u002F4.use-craft-uri",{"title":469,"path":619,"stem":620,"badge":23},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-auth-token","2.libraries\u002Fquery-api-react\u002F3.hooks\u002F5.use-craft-auth-token",{"title":473,"path":622,"stem":623,"children":624,"page":32},"\u002Flibraries\u002Fquery-api-react\u002Fcomponents","2.libraries\u002Fquery-api-react\u002F4.components",[625,628,631],{"title":478,"path":626,"stem":627,"badge":23},"\u002Flibraries\u002Fquery-api-react\u002Fcomponents\u002Fcraft-page","2.libraries\u002Fquery-api-react\u002F4.components\u002F1.craft-page",{"title":482,"path":629,"stem":630,"badge":23},"\u002Flibraries\u002Fquery-api-react\u002Fcomponents\u002Fcraft-area","2.libraries\u002Fquery-api-react\u002F4.components\u002F2.craft-area",{"title":486,"path":632,"stem":633,"badge":23},"\u002Flibraries\u002Fquery-api-react\u002Fcomponents\u002Fcraft-not-implemented","2.libraries\u002Fquery-api-react\u002F4.components\u002F3.craft-not-implemented",{"title":515,"path":635,"stem":636,"children":637,"page":32},"\u002Flibraries\u002Fquery-api-react\u002Ffunctions","2.libraries\u002Fquery-api-react\u002F5.functions",[638,642,646],{"title":639,"path":640,"stem":641,"badge":23},"getCraftLocation","\u002Flibraries\u002Fquery-api-react\u002Ffunctions\u002Fget-craft-location","2.libraries\u002Fquery-api-react\u002F5.functions\u002F1.get-craft-location",{"title":643,"path":644,"stem":645,"badge":23},"getCraftInstance","\u002Flibraries\u002Fquery-api-react\u002Ffunctions\u002Fget-craft-instance","2.libraries\u002Fquery-api-react\u002F5.functions\u002F2.get-craft-instance",{"title":647,"path":648,"stem":649,"badge":23},"getCraftContentMapping","\u002Flibraries\u002Fquery-api-react\u002Ffunctions\u002Fget-craft-content-mapping","2.libraries\u002Fquery-api-react\u002F5.functions\u002F3.get-craft-content-mapping",{"title":651,"path":652,"stem":653,"children":654,"badge":23},"@query-api\u002Fvue","\u002Flibraries\u002Fvue-craftcms","2.libraries\u002Fvue-craftcms\u002F1.index",[655,665,684,696],{"title":15,"path":656,"stem":657,"children":658,"page":32},"\u002Flibraries\u002Fvue-craftcms\u002Fget-started","2.libraries\u002Fvue-craftcms\u002F2.get-started",[659,662],{"title":274,"path":660,"stem":661,"badge":23},"\u002Flibraries\u002Fvue-craftcms\u002Fget-started\u002Fintroduction","2.libraries\u002Fvue-craftcms\u002F2.get-started\u002F1.introduction",{"title":107,"path":663,"stem":664,"badge":23},"\u002Flibraries\u002Fvue-craftcms\u002Fget-started\u002Finstall","2.libraries\u002Fvue-craftcms\u002F2.get-started\u002F2.install",{"title":34,"path":666,"stem":667,"children":668,"page":32},"\u002Flibraries\u002Fvue-craftcms\u002Fusage","2.libraries\u002Fvue-craftcms\u002F3.usage",[669,672,676,680],{"title":394,"path":670,"stem":671,"badge":23},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fbasic-usage","2.libraries\u002Fvue-craftcms\u002F3.usage\u002F1.basic-usage",{"title":673,"path":674,"stem":675,"badge":23},"Build Query URLs","\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fbuild-query-urls","2.libraries\u002Fvue-craftcms\u002F3.usage\u002F2.build-query-urls",{"title":677,"path":678,"stem":679,"badge":23},"Connect Components","\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fconnect-components","2.libraries\u002Fvue-craftcms\u002F3.usage\u002F3.connect-components",{"title":681,"path":682,"stem":683,"badge":23},"Example","\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fexample","2.libraries\u002Fvue-craftcms\u002F3.usage\u002F4.example",{"title":444,"path":685,"stem":686,"children":687,"page":32},"\u002Flibraries\u002Fvue-craftcms\u002Fcomposables","2.libraries\u002Fvue-craftcms\u002F4.composables",[688,692],{"title":689,"path":690,"stem":691,"badge":23},"useCraftUrlBuilder","\u002Flibraries\u002Fvue-craftcms\u002Fcomposables\u002Fuse-craft-url-builder","2.libraries\u002Fvue-craftcms\u002F4.composables\u002F1.use-craft-url-builder",{"title":693,"path":694,"stem":695,"badge":23},"useCraft","\u002Flibraries\u002Fvue-craftcms\u002Fcomposables\u002Fuse-craft","2.libraries\u002Fvue-craftcms\u002F4.composables\u002F2.use-craft",{"title":473,"path":697,"stem":698,"children":699,"page":32},"\u002Flibraries\u002Fvue-craftcms\u002Fcomponents","2.libraries\u002Fvue-craftcms\u002F5.components",[700,703,706],{"title":478,"path":701,"stem":702,"badge":23},"\u002Flibraries\u002Fvue-craftcms\u002Fcomponents\u002Fcraft-page","2.libraries\u002Fvue-craftcms\u002F5.components\u002F1.craft-page",{"title":482,"path":704,"stem":705,"badge":23},"\u002Flibraries\u002Fvue-craftcms\u002Fcomponents\u002Fcraft-area","2.libraries\u002Fvue-craftcms\u002F5.components\u002F2.craft-area",{"title":486,"path":707,"stem":708,"badge":23},"\u002Flibraries\u002Fvue-craftcms\u002Fcomponents\u002Fcraft-not-implemented","2.libraries\u002Fvue-craftcms\u002F5.components\u002F3.craft-not-implemented",[710,714,720,725,730,735,741,746,751,756,761,764,769,774,779,784,789,794,799,803,806,811,815,820,825,830,835,840,845,850,855,860,865,870,875,880,885,890,895,900,905,910,913,918,923,928,933,938,943,948,952,956,959,964,969,974,979,984,987,992,997,1002,1007,1012,1017,1021,1024,1029,1034,1039,1044,1047,1052,1057,1062,1065,1070,1075,1080,1083,1087,1092,1095,1099,1104,1109,1112,1116,1121,1126,1129,1134,1139,1142,1146,1151,1154,1158,1163,1166,1171,1176,1181,1184,1188,1192,1196,1201,1206,1211,1214,1218,1222,1227,1232,1237,1242,1245,1249,1253,1257,1260,1264,1268,1272,1277,1282,1285,1290,1294,1299,1304,1307,1311,1315,1320,1325,1328,1332,1336,1341,1346,1351,1356,1361,1366,1369,1373,1377,1380,1384,1388,1393,1398,1402,1405,1410,1414,1419,1423,1426,1429,1433,1437,1442,1447,1450,1454,1458,1463,1468,1473,1478,1483,1488,1493,1498,1503,1508,1513,1518,1523,1528,1533,1538,1543,1548,1553,1557,1562,1566,1569,1574,1579,1584,1589,1594,1597,1602,1607,1612,1617,1622,1627,1631,1636,1641,1646,1651,1655,1660,1665,1670,1673,1678,1683,1688,1693,1698,1703,1708,1713,1718,1723,1728,1733,1738,1742,1747,1752,1757,1762,1767,1770,1774,1779,1784,1789,1794,1799,1803,1808,1813,1817,1822,1827,1832,1835,1839,1844,1848,1852,1855,1860,1864,1867,1872,1876,1879,1884,1888,1891,1896,1901,1905,1910,1915,1920,1925,1930,1933,1938,1943,1946,1951,1956,1960,1965,1970,1975,1980,1985,1988,1993,1998,2003,2008,2013,2017,2022,2027,2032,2035,2040,2044,2049,2054,2059,2064,2068,2073,2078,2081,2086,2091,2096,2099,2104,2108,2113,2118,2122,2125,2128,2133,2137,2141,2145,2149,2152,2156,2160,2165,2170,2175,2180,2185,2190,2195,2200,2205,2210,2215,2220,2224,2227,2231,2236,2241,2246,2251,2256,2261,2266,2270,2273,2278,2283,2288,2293,2298,2302,2307,2310,2315,2320,2325,2329,2334,2339,2344,2349,2352,2357,2362,2367,2370,2375,2378,2383,2388,2393,2397,2401,2406,2411,2416,2419,2423,2427,2431,2434,2439,2444,2447,2451,2455,2458,2462,2467,2472,2477,2480,2484,2489,2494,2499,2503,2508,2513,2518,2521,2526,2530,2535,2540,2543,2548,2553,2558,2563,2568,2571,2576,2581,2586,2591,2596,2601,2606,2611,2616,2619,2624,2629,2632,2637,2640,2645,2648,2653,2658,2661,2666,2671,2676,2681,2686,2691,2696,2701,2704,2709,2714,2719,2724,2729,2734,2738,2741,2746,2751,2756,2760,2765,2770,2775,2780,2783,2787,2791,2795,2801,2804,2809,2814,2819,2824,2827,2831,2835,2839,2842,2846,2850,2853,2858,2863,2867,2872,2877,2882,2887,2892,2897,2902,2905,2909,2913,2917,2920,2925,2930,2934,2937,2941,2945,2948,2952,2957,2961,2964,2968,2972,2977,2980,2984,2988,2991,2995,3000,3005,3010,3015,3020,3023,3028,3033,3038,3041,3046,3051,3054,3058,3062,3066,3069,3073,3077,3081,3084,3087,3091,3096,3099,3103,3108,3113,3118,3122,3127,3131,3136,3141,3146,3149,3154,3158,3163,3168,3173,3177,3182,3187,3192,3197,3200,3204,3209,3212,3217,3222,3227,3232,3237,3242,3245,3250,3253,3258,3263,3267,3272,3277,3280,3285,3290,3295,3299,3304,3307,3311,3316,3321,3326,3331,3334,3338,3342,3346,3350,3353,3357,3361,3364,3368,3373,3378,3383,3387,3390,3394,3398,3401,3404,3407,3410,3414,3418,3422,3425,3429,3433,3436,3439,3442,3446,3450,3453,3456,3461,3465,3469,3472,3476,3481,3485,3490,3494,3498,3501,3505,3508,3511,3514,3519,3524,3527,3530,3533,3536,3540,3543,3548,3552,3557,3562,3567,3572,3575,3579,3583,3587,3591,3595,3598,3602,3606,3609,3613,3617,3621,3624,3628,3631,3635,3639,3643,3647,3650,3654,3658,3661,3665,3669,3673,3677,3681,3684,3688,3692,3695,3699,3703,3707,3710,3714,3717,3721,3725,3729,3733,3736,3739,3742,3745,3749,3754,3757,3761,3764,3768,3771,3776,3781,3786,3791,3796,3801,3805,3810,3814,3817,3821,3825,3829,3832,3836,3840,3843,3846,3849,3853,3857,3860,3863,3868,3873,3877,3880,3884,3888,3893,3898,3903,3907,3910,3913,3916,3919,3922,3926,3930,3933,3936,3939,3942,3946,3949,3952,3955,3958,3962,3965,3967,3970,3973,3975,3978,3981,3984,3987,3990,3992,3995,3998,4001,4004,4006,4009,4012,4015,4019,4023,4026,4030,4032,4036,4039,4043,4046,4051,4054,4058,4061,4065,4069,4073,4076,4080,4083,4086,4089,4092,4096,4099,4103,4107,4110,4115,4120,4123,4128,4132,4137,4141,4145,4149,4153,4156,4161,4164,4168,4173,4177,4181,4184,4187,4192,4196,4201,4204,4208,4213,4216],{"id":21,"title":20,"titles":711,"content":712,"level":713},[],"Learn how to install and setup the CoPilot Craft CMS plugin.",1,{"id":715,"title":716,"titles":717,"content":718,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Finstallation#requirements","Requirements",[20],"Supports Craft CMS > 5PHP 8.2 or later",2,{"id":721,"title":722,"titles":723,"content":724,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Finstallation#craft-plugin-store","Craft Plugin Store",[20],"To install CoPilot, go to the Plugin Store in your Craft control panel, search for \"CoPilot,\" and click the Try button.",{"id":726,"title":727,"titles":728,"content":729,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Finstallation#composer","Composer",[20],"ddev composer require samuelreichor\u002Fcraft-co-pilot &&\nddev craft plugin\u002Finstall co-pilot\ncomposer require samuelreichor\u002Fcraft-co-pilot &&\nphp craft plugin\u002Finstall co-pilot",{"id":731,"title":732,"titles":733,"content":734,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Finstallation#setup","Setup",[20],"",{"id":736,"title":737,"titles":738,"content":739,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Finstallation#add-providers","Add Providers",[20,732],"To get started you need to pick one or more AI providers and generate an API key. If you choose more than one you can switch the provider in the chat. OpenAI offers the best cost-performance balance, Anthropic has the highest quality but is slower and pricier and Gemini is the cheapest but least reliable for complex tasks. \nHead over to the provider overview, if you are unsure what provider you should pick. To set the api key, first create new environment variables in .env: OPENAI_API_KEY=XXXXXXXX\nANTHROPIC_API_KEY=XXXXXXXX\nGEMINI_API_KEY=XXXXXXXX After that, you can set them in the control panel settings. For that you can go to Settings -> CoPilot -> Providers: Only use set the API key as enviroment variable. Settings get saved in the project.yaml and that file will be commited to git. Therefore you would leak your API Key if you save them directly in the settings.",3,{"id":742,"title":743,"titles":744,"content":745,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Finstallation#set-permissions","Set Permissions",[20,732],"It's recommended that you check the current craft site and adjust permissions for the CoPilot if needed.\nYou can give the Agent access to Sections, Volumes and Categories.\nThese permissions have higher priority than user permissions. For example admin users can't edit entries if they are in sections that are blocked or read only. Learn more about how permissions work in the Permissions guide.",{"id":747,"title":748,"titles":749,"content":750,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Finstallation#done","Done",[20,732],"You can now safely use the Copilot 🚀",{"id":752,"title":753,"titles":754,"content":755,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Finstallation#support","Support",[20],"If you encounter bugs or have feature requests, please submit an issue or use the \u002Fbug-report command in the chat window. Your feedback helps improve the plugin!",{"id":757,"title":758,"titles":759,"content":760,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Finstallation#licensing","Licensing",[20],"You can try CoPilot in a development environment for as long as you like. Once your site goes live, you are required to purchase a license for the plugin. For more information, see Craft's Commercial Plugin Licensing. html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}",{"id":26,"title":25,"titles":762,"content":763,"level":713},[],"An overview of all supported AI providers, their models, and capabilities. CoPilot supports multiple AI providers out of the box. Each provider has different strengths, pricing, and model options. You can switch between providers at any time in the chat. ProviderModelsWeb SearchBest ForOpenAI6YesCost-performance balanceAnthropic2YesHighest quality outputGoogle Gemini5NoBudget-friendly usage",{"id":765,"title":766,"titles":767,"content":768,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fai-provider#openai","OpenAI",[25],"OpenAI is the most widely used provider and offers a good balance between quality, speed, and cost. To get started, create an account at platform.openai.com and generate an API key. gpt-5.4 · gpt-5.4-mini · gpt-5.4-nano · gpt-4o · o3 · o4-miniYesFast responses, reliable tool calling, good all-rounder for content tasksCan be less creative than Anthropic for nuanced writing",{"id":770,"title":771,"titles":772,"content":773,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fai-provider#anthropic","Anthropic",[25],"Anthropic builds Claude, known for high-quality, nuanced text generation. Create an account at console.anthropic.com and generate an API key. claude-opus-4-6 · claude-sonnet-4-6YesBest writing quality, strong at following complex instructions, excellent for brand voice tasksSlower response times and higher cost per token compared to OpenAI and Gemini",{"id":775,"title":776,"titles":777,"content":778,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fai-provider#google-gemini","Google Gemini",[25],"Google Gemini is the most affordable option with generous free tiers. Create an account at aistudio.google.com and generate an API key. gemini-3.1-pro-preview · gemini-3-flash-preview · gemini-3.1-flash-lite-preview · gemini-2.5-pro · gemini-2.5-flashNoLowest cost, fast response times, good for simple content tasksLess reliable for complex tool calling, no web search support",{"id":780,"title":781,"titles":782,"content":783,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fai-provider#langdock","Langdock",[25],"Langdock is a DSGVO-compliant AI platform that routes requests to OpenAI, Anthropic, and Google Gemini through a single unified API. By installing the Langdock Provider Plugin, all CoPilot AI requests are routed through Langdock instead of directly to the providers. This gives you a single API key, EU or US data residency, and DSGVO-compliant usage of LLMs. ddev composer require samuelreichor\u002Fcraft-co-pilot-landock &&\nddev craft plugin\u002Finstall co-pilot-landock\ncomposer require samuelreichor\u002Fcraft-co-pilot-landock &&\nphp craft plugin\u002Finstall co-pilot-landock\nAll models from OpenAI, Anthropic, and Google Gemini available in your Langdock workspaceEU or USSingle API key for all providers, DSGVO-compliant, centralized model management",{"id":785,"title":786,"titles":787,"content":788,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fai-provider#benchmark","Benchmark",[25],"We ran 9 real-world content scenarios (field editing, nested matrix, translations, entry creation, batch operations, multi-site, propagation, and search) against each provider. Here are the results:",{"id":790,"title":791,"titles":792,"content":793,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fai-provider#premium-models","Premium Models",[25,786],"Provider \u002F ModelAvg. ScoreAvg. DurationOpenAI (gpt-5.4)100%27.4sAnthropic (claude-opus-4-6)100%52.5sGemini (gemini-3.1-pro-preview)96.3%58.0s",{"id":795,"title":796,"titles":797,"content":798,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fai-provider#budget-models","Budget Models",[25,786],"Provider \u002F ModelAvg. ScoreAvg. DurationOpenAI (o4-mini)87.8%149.8sAnthropic (claude-sonnet-4-6)95.6%40.8sGemini (gemini-2.5-flash)91.9%23.3s Anthropic uses significantly fewer tokens per request due to prompt caching, which makes it very cost-efficient despite higher per-token pricing. Gemini's budget models offer the fastest response times. Scores reflect correctness of the final result across all scenarios.",{"id":800,"title":85,"titles":801,"content":802,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fai-provider#custom-providers",[25],"You can add your own AI provider by implementing the ProviderInterface. Head over to the Custom Providers guide for a full walkthrough. html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":30,"title":29,"titles":804,"content":805,"level":713},[],"Learn about all available configuration options for the CoPilot plugin.",{"id":807,"title":808,"titles":809,"content":810,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#control-panel","Control Panel",[29],"You can manage configuration settings through the Control Panel by visiting Settings → CoPilot.",{"id":812,"title":308,"titles":813,"content":814,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#settings",[29],"You can define a multi environment aware config in \u002Fconfig\u002Fco-pilot.php. Settings defined in the config file override control panel settings.",{"id":816,"title":817,"titles":818,"content":819,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#defaultprovider","defaultProvider",[29,308],"The default AI provider used for new conversations. Available values: openai, anthropic, gemini. return [\n  '*' => [\n    'defaultProvider' => 'openai', \u002F\u002F default\n  ],\n]",{"id":821,"title":822,"titles":823,"content":824,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#providersettings","providerSettings",[29,308],"Per-provider configuration including API key environment variable and model selection. return [\n  '*' => [\n    'providerSettings' => [\n      'openai' => [\n        'apiKeyEnvVar' => '$OPENAI_API_KEY',\n        'model' => 'gpt-5.4',\n      ],\n      'anthropic' => [\n        'apiKeyEnvVar' => '$ANTHROPIC_API_KEY',\n        'model' => 'claude-sonnet-4-6',\n      ],\n      'gemini' => [\n        'apiKeyEnvVar' => '$GEMINI_API_KEY',\n        'model' => 'gemini-2.5-flash',\n      ],\n    ],\n  ],\n] Only reference API keys as environment variables. Settings are saved in project.yaml which is committed to git. Storing keys directly would leak them.",{"id":826,"title":827,"titles":828,"content":829,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#sectionaccess","sectionAccess",[29,308],"Control the agent's access level per section. Maps section UIDs to access levels: blocked, readOnly, readWrite. return [\n  '*' => [\n    'sectionAccess' => [\n      'section-uid-here' => 'readOnly',\n      'another-section-uid' => 'blocked',\n    ],\n  ],\n] These permissions take priority over user permissions. Even admin users cannot edit entries in sections that are blocked or read-only. See Permissions for details on how both layers interact.",{"id":831,"title":832,"titles":833,"content":834,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#volumeaccess","volumeAccess",[29,308],"Control the agent's access level per asset volume. Same access levels as sectionAccess. return [\n  '*' => [\n    'volumeAccess' => [\n      'volume-uid-here' => 'readOnly',\n    ],\n  ],\n]",{"id":836,"title":837,"titles":838,"content":839,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#categorygroupaccess","categoryGroupAccess",[29,308],"Control the agent's access level per category group. Same access levels as sectionAccess. return [\n  '*' => [\n    'categoryGroupAccess' => [\n      'category-group-uid-here' => 'readWrite',\n    ],\n  ],\n]",{"id":841,"title":842,"titles":843,"content":844,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#blockedelementtypes","blockedElementTypes",[29,308],"List of element type classes the agent cannot interact with. Commerce Orders are blocked by default. return [\n  '*' => [\n    'blockedElementTypes' => [\n      'craft\\commerce\\elements\\Order', \u002F\u002F default\n    ],\n  ],\n]",{"id":846,"title":847,"titles":848,"content":849,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#websearchenabled","webSearchEnabled",[29,308],"Allow the agent to search the web for information. Check out the provider docs to see if your configured provider has access to web search tools. return [\n  '*' => [\n    'webSearchEnabled' => false, \u002F\u002F default\n  ],\n]",{"id":851,"title":852,"titles":853,"content":854,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#agentexecutionmode","agentExecutionMode",[29,308],"How the agent executes tool calls. Available values: supervised (requires user approval), autonomous (auto-execute). return [\n  '*' => [\n    'agentExecutionMode' => 'supervised', \u002F\u002F default\n  ],\n  'dev' => [\n    'agentExecutionMode' => 'autonomous',\n  ],\n]",{"id":856,"title":857,"titles":858,"content":859,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#maxagentiterations","maxAgentIterations",[29,308],"Maximum number of tool-calling loops per message. Valid range: 1–200. return [\n  '*' => [\n    'maxAgentIterations' => 50, \u002F\u002F default\n  ],\n]",{"id":861,"title":862,"titles":863,"content":864,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#defaultserializationdepth","defaultSerializationDepth",[29,308],"Default nesting depth when serializing entries to JSON for the agent. Valid range: 1–10. return [\n  '*' => [\n    'defaultSerializationDepth' => 3, \u002F\u002F default\n  ],\n]",{"id":866,"title":867,"titles":868,"content":869,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#maxserializationdepth","maxSerializationDepth",[29,308],"Maximum allowed nesting depth for entry serialization. Valid range: 1–10. return [\n  '*' => [\n    'maxSerializationDepth' => 4, \u002F\u002F default\n  ],\n]",{"id":871,"title":872,"titles":873,"content":874,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#maxcontexttokens","maxContextTokens",[29,308],"Maximum number of tokens in the agent's context window. Valid range: 1,000–1,000,000. return [\n  '*' => [\n    'maxContextTokens' => 200000, \u002F\u002F default\n  ],\n]",{"id":876,"title":877,"titles":878,"content":879,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#defaultsearchlimit","defaultSearchLimit",[29,308],"Default number of results returned by search tools. Valid range: 1–200. return [\n  '*' => [\n    'defaultSearchLimit' => 50, \u002F\u002F default\n  ],\n]",{"id":881,"title":882,"titles":883,"content":884,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#elementupdatebehavior","elementUpdateBehavior",[29,308],"How entry updates are persisted. provisionalDraft: Saves changes as a provisional draft. The original entry stays unchanged until an editor reviews and applies the draft. Best for production environments where content changes should be reviewed.draft: reates a new draft for each update. Similar to provisional drafts but creates a separate named draft.directSave: Saves changes directly to the live entry. No draft or review step. Use with caution in production. return [\n  '*' => [\n    'elementUpdateBehavior' => 'provisionalDraft', \u002F\u002F default\n  ],\n]",{"id":886,"title":887,"titles":888,"content":889,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#elementcreationbehavior","elementCreationBehavior",[29,308],"How new entries are created. `draft: Creates new entries as unpublished drafts. An editor must review and publish them manually. Recommended for most setups.directSave: Creates new entries as published and immediately live. Use with caution.disabled: Creates new entries in a disabled state. Useful when entries need to be reviewed and manually enabled before going live. return [\n  '*' => [\n    'elementCreationBehavior' => 'draft', \u002F\u002F default\n  ],\n]",{"id":891,"title":892,"titles":893,"content":894,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#pluginname","pluginName",[29,308],"Custom display name for the plugin in the control panel sidebar. Max 50 characters. return [\n  '*' => [\n    'pluginName' => 'CoPilot', \u002F\u002F default\n  ],\n]",{"id":896,"title":897,"titles":898,"content":899,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#auditlogretentiondays","auditLogRetentionDays",[29,308],"Number of days to retain audit log entries. Cleanup runs via Craft's garbage collection. Valid range: 1–365. return [\n  '*' => [\n    'auditLogRetentionDays' => 30, \u002F\u002F default\n  ],\n]",{"id":901,"title":902,"titles":903,"content":904,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#debug","debug",[29,308],"Enable debug mode for additional logging and diagnostic information. return [\n  '*' => [\n    'debug' => false, \u002F\u002F default\n  ],\n  'dev' => [\n    'debug' => true,\n  ],\n]",{"id":906,"title":907,"titles":908,"content":909,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fget-started\u002Fconfiguration#multi-environment-example","Multi-Environment Example",[29],"A complete example showing environment-specific configuration: \u003C?php\n\u002F\u002F config\u002Fco-pilot.php\n\nreturn [\n  '*' => [\n    'defaultProvider' => 'anthropic',\n    'providerSettings' => [\n      'anthropic' => [\n        'apiKeyEnvVar' => '$ANTHROPIC_API_KEY',\n        'model' => 'claude-sonnet-4-6',\n      ],\n      'openai' => [\n        'apiKeyEnvVar' => '$OPENAI_API_KEY',\n        'model' => 'gpt-5.4',\n      ],\n    ],\n    'agentExecutionMode' => 'supervised',\n    'webSearchEnabled' => true,\n    'elementCreationBehavior' => 'draft',\n    'elementUpdateBehavior' => 'provisionalDraft',\n    'auditLogRetentionDays' => 90,\n  ],\n  'dev' => [\n    'agentExecutionMode' => 'autonomous',\n    'debug' => true,\n  ],\n  'production' => [\n    'maxAgentIterations' => 30,\n  ],\n]; html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}",{"id":40,"title":39,"titles":911,"content":912,"level":713},[],"Learn how to use the CoPilot chat interface to create, edit, and manage your content. The chat is the main interface to interact with CoPilot. You can open it from the control panel sidebar or directly from an entry editor.",{"id":914,"title":915,"titles":916,"content":917,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fchat#main-chat","Main Chat",[39],"The main chat is accessible from the control panel sidebar under the CoPilot menu item. Use it for general content tasks like creating entries, searching content, or translating across sites.",{"id":919,"title":920,"titles":921,"content":922,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fchat#entry-slideout","Entry Slideout",[39],"When editing an entry, click the CoPilot button in the toolbar to open a chat slideout. The slideout automatically loads the current entry as context, so the agent knows exactly what you're working on. Conversations started from the slideout are linked to that specific entry.",{"id":924,"title":925,"titles":926,"content":927,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fchat#chat-features","Chat Features",[39],"The chat interface offers several features to help you work efficiently with the agent. Here's an overview of the available options.",{"id":929,"title":930,"titles":931,"content":932,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fchat#add-context","Add Context",[39,925],"You can attach entries, assets, or files to your message to give the agent additional context. Click the attachment button next to the input field to browse and select content. This is useful when you want the agent to reference or compare specific entries.",{"id":934,"title":935,"titles":936,"content":937,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fchat#execution-mode","Execution Mode",[39,925],"The execution mode controls how the agent handles write operations: Supervised (default): The agent asks for your approval before making any changes. Recommended for production environments.Autonomous : The agent executes all operations without asking for confirmation. Useful for development or repetitive bulk tasks. You can switch between modes at any time using the dropdown in the chat input area. Admins can restrict this per user group via Permissions. In autonomous mode, the agent will create, update, and publish entries without confirmation. Use with caution.",{"id":939,"title":940,"titles":941,"content":942,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fchat#multiple-providers","Multiple Providers",[39,925],"If you've configured more than one AI provider, you can switch between them in the chat header. Each provider has different strengths – check the AI Providers overview for a comparison.",{"id":944,"title":945,"titles":946,"content":947,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fchat#model-selection","Model Selection",[39,925],"Within each provider, you can choose a specific model. Smaller models are faster and cheaper, while larger models produce higher quality results. The model can be changed per conversation via the chat header.",{"id":949,"title":312,"titles":950,"content":951,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fchat#commands",[39,925],"Commands are predefined prompts that you can trigger by typing \u002F in the chat input. They provide shortcuts for common tasks and workflows. Some commands accept a parameter to make them more flexible. A parameter can be an entry, asset, file, or free text that gets injected into the command's prompt. For example, a \u002Ftranslate command could ask you to select an entry, then automatically translate it. CoPilot ships without built-in commands, but your team can register custom commands tailored to your content workflows. See the Custom Commands guide for instructions on how to create your own.",{"id":953,"title":47,"titles":954,"content":955,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fchat#tools",[39,925],"Tools are the actions the agent can perform on your behalf. They include searching entries, reading content, creating and updating entries, managing assets and categories, and more. For a full list of available tools and what each one does, see the Tools overview. Developers can also extend the agent with custom tools – see the Custom Tools guide.",{"id":44,"title":43,"titles":957,"content":958,"level":713},[],"Define your brands tone, terminology, and writing rules so the AI stays on-brand. Brand Voice lets you define how the AI writes content. You can set guidelines for tone, terminology, forbidden words, and language-specific instructions. These settings are applied per site, so each site can have its own voice. You can manage Brand Voice in the control panel under CoPilot → Brand Voice.",{"id":960,"title":961,"titles":962,"content":963,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fbrand-voice#voice-style-guidelines","Voice & Style Guidelines",[43],"Describe your brand's tone and writing style. This is the main instruction the AI follows when generating or editing content. Be as specific as you like — the more detail you provide, the more consistent the output. Examples: \"Write in a friendly, professional tone. Use short sentences. Avoid jargon.\"\"Our voice is bold and direct. We use active voice and speak to the reader as 'you'.\"\"Keep it casual but informative. Think blog post, not white paper.\"",{"id":965,"title":966,"titles":967,"content":968,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fbrand-voice#glossary","Glossary",[43],"Define terms and their correct usage. The AI will use these exact terms when writing content instead of coming up with its own variations. Examples: \"CoPilot (not Co-Pilot, Copilot, or co-pilot)\"\"Craft CMS (not CraftCMS or just Craft)\"\"content editor (not admin, user, or backend user)\"",{"id":970,"title":971,"titles":972,"content":973,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fbrand-voice#forbidden-words","Forbidden Words",[43],"List words or phrases the AI should never use, along with suggested alternatives. This is useful for avoiding off-brand language, outdated terms, or competitor names. Examples: \"cheap → affordable\"\"simple → straightforward\"\"users → customers\"",{"id":975,"title":976,"titles":977,"content":978,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fbrand-voice#language-instructions","Language Instructions",[43],"Add language-specific writing rules. This is especially useful for multi-site setups where each site targets a different language or region. Examples: \"Use formal German (Sie, not du).\"\"Use British English spelling (colour, organisation).\"\"For the French site, use inclusive writing.\"",{"id":980,"title":981,"titles":982,"content":983,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fbrand-voice#per-site-configuration","Per-Site Configuration",[43],"Brand Voice settings are stored per site. If you run a multi-site setup, switch between sites using the site switcher in the Brand Voice editor to configure each site individually. If no Brand Voice is configured for a site, the AI will use its default writing style without any specific guidelines.",{"id":48,"title":47,"titles":985,"content":986,"level":713},[],"A complete list of all built-in tools the CoPilot agent can use to manage your content. Tools are the actions the agent performs on your behalf. When you ask the agent to do something like \"create a blog post\" or \"translate this entry\" it uses one or more tools behind the scenes. You can see which tools are being called in the chat as they execute.",{"id":988,"title":989,"titles":990,"content":991,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Ftools#discovery-schema","Discovery & Schema",[47],"These tools help the agent understand your content structure before making changes. ToolDescriptionlistSectionsLists all sections the current user can access, with entry type handles.listSitesLists all configured sites with their handles, names, and languages.describeSectionReturns field definitions, value formats, and hints for a section. Called before creating or updating entries.describeEntryTypeReturns full field definitions for a specific entry type or Matrix block type.describeCategoryGroupReturns field definitions for a category group.describeVolumeReturns field definitions for an asset volume.",{"id":993,"title":994,"titles":995,"content":996,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Ftools#search","Search",[47],"Search tools let the agent find existing content. They return summaries with IDs that can be used in create or update operations. ToolDescriptionsearchEntriesSearches or lists entries in allowed sections. Can filter by section, status, author, and site.searchAssetsSearches for assets (images, files) across allowed volumes.searchCategoriesSearches for categories by title.searchTagsSearches for tags by title.searchUsersSearches for users by name or email.searchFormieFormsSearches Formie forms by title. Returns form handles. Only available when Formie is installed.",{"id":998,"title":999,"titles":1000,"content":1001,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Ftools#read","Read",[47],"Read tools retrieve detailed information about specific content. ToolDescriptionreadEntryReads a single entry. Summary mode shows metadata and which fields are filled. Full mode returns complete field values.readEntriesBatch-reads multiple entries by ID. Use instead of reading entries one by one.readAssetReads asset metadata and URL.",{"id":1003,"title":1004,"titles":1005,"content":1006,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Ftools#create","Create",[47],"ToolDescriptioncreateEntryCreates a new entry in a section. Save behavior depends on your configuration.createCategoryCreates a new category in a category group.",{"id":1008,"title":1009,"titles":1010,"content":1011,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Ftools#update","Update",[47],"ToolDescriptionupdateEntryUpdates one or more fields of an existing entry in a single save. Save behavior depends on your configuration.updateAssetUpdates asset metadata like title, alt text, and custom fields.updateCategoryUpdates an existing category's title, slug, and custom fields.publishEntryPublishes an entry by enabling it and saving directly. Only used when explicitly asked to publish or go live.",{"id":1013,"title":1014,"titles":1015,"content":1016,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Ftools#how-tools-work-together","How Tools Work Together",[47],"The agent typically follows this workflow when making content changes: Discover: listSections to find the right sectionDescribe: describeSection to learn the field structureSearch\u002FRead: searchEntries or readEntry to find or inspect existing contentWrite: createEntry or updateEntry to make changesVerify: readEntry to confirm the changes were applied correctly All tools respect the access control settings. If a section is set to read-only, the agent can read but not modify entries in that section.",{"id":1018,"title":89,"titles":1019,"content":1020,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Ftools#custom-tools",[47],"Developers can extend the agent with custom tools to add new capabilities. See the Custom Tools guide for a full walkthrough.",{"id":52,"title":51,"titles":1022,"content":1023,"level":713},[],"Understand how CoPilot permissions work together with Craft user permissions to control access. CoPilot uses a two-layer permission system. Both layers must allow an action for it to succeed. Plugin settings: Control what the agent can access (sections, volumes, categories)Native user permissions: Control what the logged-in user can do",{"id":1025,"title":1026,"titles":1027,"content":1028,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fpermissions#how-they-work-together","How They Work Together",[51],"When the agent tries to read or write content, both layers are checked: Plugin settingCraft user permissionResultReadWriteUser has view + saveAllowedReadWriteUser has view onlyRead onlyReadOnlyUser has view + saveRead onlyBlockedUser has view + saveDeniedReadWriteUser has no accessDenied In short: the agent can never do more than what both the plugin settings and the user's Craft permissions allow. Admin users bypass Craft's native permission checks but are still restricted by the plugin's access settings. If a section is set to read-only or blocked in the plugin, even admins cannot write to it through the agent.",{"id":1030,"title":1031,"titles":1032,"content":1033,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fpermissions#plugin-access-settings","Plugin Access Settings",[51],"These are configured in Settings → CoPilot → Permissions and control what the agent is allowed to do per section, volume, and category group.",{"id":1035,"title":1036,"titles":1037,"content":1038,"level":740},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fpermissions#blocked-element-types","Blocked Element Types",[51,1031],"You can block entire element types from the agent. By default, Commerce Orders are blocked. This is useful for preventing the agent from interacting with sensitive element types entirely. \u002F\u002F config\u002Fco-pilot.php\nreturn [\n  '*' => [\n    'blockedElementTypes' => [\n      'craft\\commerce\\elements\\Order',\n    ],\n  ],\n] Blocked element types are checked first, they take priority over all other access settings and user permissions.",{"id":1040,"title":1041,"titles":1042,"content":1043,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Fpermissions#craft-user-permissions","Craft User Permissions",[51],"CoPilot registers its own set of user permissions in Craft. You can assign them to user groups under Settings → Users → User Groups. With that you can restrict users to only see there own chats or prevent them to edit the brand voice. html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":56,"title":55,"titles":1045,"content":1046,"level":713},[],"Track every action the AI agent performs with field-level diffs and full traceability. The Audit Log records tool call the agent makes, reads, creates, and updates. It gives you full traceability of what the agent did, when, and for which entry. You can access the Audit Log in the control panel under CoPilot → Audit Log.",{"id":1048,"title":1049,"titles":1050,"content":1051,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Faudit-log#what-gets-logged","What Gets Logged",[55],"Every tool execution is logged automatically with the following information: User: Who triggered the actionTool: Which tool was called (e.g. updateEntry, createEntry, searchEntries)Action: The type of operation (read, create, update)Element: The affected element with a direct link to the editorConversation: Link back to the conversation where the action happenedStatus: Whether the action succeeded or was deniedDate: When the action was performedDiff: What has changed during update operations",{"id":1053,"title":1054,"titles":1055,"content":1056,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Faudit-log#field-level-diffs","Field-Level Diffs",[55],"For update operations, the audit log tracks exactly which fields changed and shows a before\u002Fafter comparison. This makes it easy to review what the agent modified without having to check the element itself.",{"id":1058,"title":1059,"titles":1060,"content":1061,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fusage\u002Faudit-log#data-retention","Data Retention",[55],"Old audit log entries are automatically cleaned up via Craft's garbage collection. By default, entries are kept for 30 days. You can adjust this in the configuration. Cleanup is irreversible. Once audit log entries are deleted, they cannot be recovered.",{"id":65,"title":64,"titles":1063,"content":1064,"level":713},[],"Learn which third-party field types CoPilot supports and what is coming soon. CoPilot supports all native Craft field types out of the box. For third-party fields, dedicated transformers are needed to teach the agent how to read and write these fields correctly.",{"id":1066,"title":1067,"titles":1068,"content":1069,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fintegrations\u002Fthird-party-fields#supported-plugins","Supported Plugins",[64],"PluginStatusCKEditorSupportedRedactorSupportedLLMifySupportedFormieSupported When Formie is installed, CoPilot automatically registers a searchFormieForms tool that lets the agent find forms by title and set them on Formie fields.",{"id":1071,"title":1072,"titles":1073,"content":1074,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fintegrations\u002Fthird-party-fields#coming-soon","Coming Soon",[64],"We're working on built-in support for these plugins: PluginStatusFreeformIn developmentSEOmaticIn developmentSEOMatePlannedHyperPlanned",{"id":1076,"title":1077,"titles":1078,"content":1079,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fintegrations\u002Fthird-party-fields#custom-field-support","Custom Field Support",[64],"If you use a field type that isn't supported yet, you can add your own transformer. See the Custom Fields guide for a walkthrough. Plugin developers can also submit a feature request on GitHub to add native support for their field types.",{"id":74,"title":73,"titles":1081,"content":1082,"level":713},[],"Register custom slash commands for the CoPilot chat interface. Commands are predefined prompts triggered via \u002F in the chat input. CoPilot ships without built-in commands, but you can register your own via events.",{"id":1084,"title":681,"titles":1085,"content":1086,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-commands#example",[73],"A \u002Ftranslate command that lets the user pick an entry and translates it to all sites: \u003C?php\n\nnamespace modules\\mymodule\\commands;\n\nuse samuelreichor\\coPilot\\commands\\CommandInterface;\n\nclass TranslateCommand implements CommandInterface\n{\n    public function getName(): string\n    {\n        return 'translate';\n    }\n\n    public function getDescription(): string\n    {\n        return 'Translate an entry to all configured sites';\n    }\n\n    public function getPrompt(): string\n    {\n        return 'Translate the entry with ID {entry} to all available sites. '\n            . 'Call listSites to find the target sites and their languages. '\n            . 'Read the entry first, then update each site version with translated content. '\n            . 'Keep the tone and formatting consistent across all translations.';\n    }\n\n    public function getParam(): ?array\n    {\n        return ['type' => 'entry', 'label' => 'Select entry to translate'];\n    }\n}\n\u003C?php\n\nnamespace modules\\mymodule;\n\nuse modules\\mymodule\\commands\\TranslateCommand;\nuse samuelreichor\\coPilot\\events\\RegisterCommandsEvent;\nuse samuelreichor\\coPilot\\services\\CommandService;\nuse yii\\base\\Event;\nuse yii\\base\\Module;\n\nclass MyModule extends Module\n{\n    public function init(): void\n    {\n        parent::init();\n\n        Event::on(\n            CommandService::class,\n            CommandService::EVENT_REGISTER_COMMANDS,\n            function(RegisterCommandsEvent $event) {\n                $event->commands[] = new TranslateCommand();\n            },\n        );\n    }\n}",{"id":1088,"title":1089,"titles":1090,"content":1091,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-commands#parameter-types","Parameter Types",[73],"getParam() returns null for no parameter, or an array with type and label: TypeResolves toUIentryEntry IDEntry selection modalassetAsset IDAsset selection modalfileFile contentFile upload dialogtextFree textText input field The resolved value replaces {paramName} placeholders in the prompt. Return null from getParam() if the command needs no parameter — these work best from the entry slideout, where the current entry is already loaded as context. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":78,"title":77,"titles":1093,"content":1094,"level":713},[],"Register custom element transformers to teach CoPilot how to serialize third-party element types. Element transformers control how element types are serialized for the AI context. CoPilot ships with transformers for Entries and Assets. For third-party element types (e.g. Commerce Products), register your own via events.",{"id":1096,"title":681,"titles":1097,"content":1098,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-elements#example",[77],"This is the built-in AssetTransformer, it serializes native properties and custom fields: \u003C?php\n\nnamespace samuelreichor\\coPilot\\transformers\\elements;\n\nuse craft\\base\\ElementInterface;\nuse craft\\elements\\Asset;\nuse samuelreichor\\coPilot\\transformers\\SerializeFallbackTrait;\n\nclass AssetTransformer implements ElementTransformerInterface\n{\n    use SerializeFallbackTrait;\n\n    public function getSupportedElementClasses(): array\n    {\n        return [\n            Asset::class,\n        ];\n    }\n\n    public function serializeElement(\n        ElementInterface $element,\n        int $depth = 2,\n        ?array $fieldHandles = null,\n    ): ?array {\n        if (!$element instanceof Asset) {\n            return null;\n        }\n\n        $data = [\n            '_type' => 'asset',\n            'id' => $element->id,\n            'filename' => $element->filename,\n            'url' => $element->url,\n            'alt' => $element->alt ?? '',\n            'kind' => $element->kind,\n            'size' => $element->size,\n            'width' => $element->width,\n            'height' => $element->height,\n        ];\n\n        $fields = $this->serializeCustomFields($element, $depth);\n        if ($fields !== []) {\n            $data['fields'] = $fields;\n        }\n\n        return $data;\n    }\n\n    public function getElementTypeLabel(): string\n    {\n        return 'Asset';\n    }\n}\n\u003C?php\n\nnamespace modules\\mymodule;\n\nuse modules\\mymodule\\transformers\\ProductTransformer;\nuse samuelreichor\\coPilot\\events\\RegisterElementTransformersEvent;\nuse samuelreichor\\coPilot\\services\\TransformerRegistry;\nuse yii\\base\\Event;\nuse yii\\base\\Module;\n\nclass MyModule extends Module\n{\n    public function init(): void\n    {\n        parent::init();\n\n        Event::on(\n            TransformerRegistry::class,\n            TransformerRegistry::EVENT_REGISTER_ELEMENT_TRANSFORMERS,\n            function(RegisterElementTransformersEvent $event) {\n                $event->transformers[] = new ProductTransformer();\n            },\n        );\n    }\n}",{"id":1100,"title":1101,"titles":1102,"content":1103,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-elements#elementtransformerinterface","ElementTransformerInterface",[77],"MethodReturnsDescriptiongetSupportedElementClasses()string[]FQCNs of element classes this transformer handles.serializeElement()array|nullSerialize the element to a JSON-safe array for the AI context. Return null to skip.getElementTypeLabel()stringHuman-readable label used in schema context (e.g. \"Product\").",{"id":1105,"title":1106,"titles":1107,"content":1108,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-elements#serializefallbacktrait","SerializeFallbackTrait",[77],"Use SerializeFallbackTrait to get access to serializeCustomFields(), it resolves all custom fields from the element's field layout and serializes them using the registered field transformers. This avoids duplicating the field serialization logic in every element transformer. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":82,"title":81,"titles":1110,"content":1111,"level":713},[],"Register custom field transformers to teach CoPilot how to read and write third-party field types. Field transformers tell the agent how to describe, read, and write a field type. CoPilot covers all native Craft fields. For third-party fields, register your own transformer via events.",{"id":1113,"title":681,"titles":1114,"content":1115,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-fields#example",[81],"A transformer for Formie form selection fields. Combined with a custom tool like searchFormieForms, the agent can find a form by name and set it on an entry. \u003C?php\n\nnamespace modules\\mymodule\\transformers;\n\nuse craft\\base\\Element;\nuse craft\\base\\FieldInterface;\nuse samuelreichor\\coPilot\\helpers\\PluginHelper;\nuse samuelreichor\\coPilot\\transformers\\fields\\FieldTransformerInterface;\n\nclass FormieFieldTransformer implements FieldTransformerInterface\n{\n    public function getSupportedFieldClasses(): array\n    {\n        return [];\n    }\n\n    public function matchesField(FieldInterface $field): ?bool\n    {\n        if (!PluginHelper::isPluginInstalledAndEnabled('formie')) {\n            return null;\n        }\n\n        return get_class($field) === 'verbb\\formie\\fields\\Forms' ? true : null;\n    }\n\n    public function describeField(\n        FieldInterface $field,\n        array $fieldInfo,\n    ): array {\n        $fieldInfo['valueFormat'] = 'form handle (string)';\n        $fieldInfo['hint'] = 'Use searchFormieForms to find the correct handle.';\n\n        return $fieldInfo;\n    }\n\n    public function serializeValue(\n        FieldInterface $field,\n        mixed $value,\n        int $depth,\n    ): mixed {\n        if ($value === null) {\n            return null;\n        }\n\n        \u002F\u002F Formie returns a Form element query\n        $form = is_object($value) && method_exists($value, 'one')\n            ? $value->one()\n            : $value;\n\n        if ($form === null) {\n            return null;\n        }\n\n        return [\n            'id' => $form->id,\n            'title' => $form->title,\n            'handle' => $form->handle,\n        ];\n    }\n\n    public function normalizeValue(\n        FieldInterface $field,\n        mixed $value,\n        ?Element $element = null,\n    ): mixed {\n        \u002F\u002F Accept a handle string and resolve it to a form ID\n        if (is_string($value)) {\n            $form = \\verbb\\formie\\elements\\Form::find()\n                ->handle($value)\n                ->one();\n\n            return $form ? [$form->id] : null;\n        }\n\n        return null;\n    }\n}\n\u003C?php\n\nnamespace modules\\mymodule;\n\nuse modules\\mymodule\\transformers\\FormieFieldTransformer;\nuse samuelreichor\\coPilot\\events\\RegisterFieldTransformersEvent;\nuse samuelreichor\\coPilot\\services\\TransformerRegistry;\nuse yii\\base\\Event;\nuse yii\\base\\Module;\n\nclass MyModule extends Module\n{\n    public function init(): void\n    {\n        parent::init();\n\n        Event::on(\n            TransformerRegistry::class,\n            TransformerRegistry::EVENT_REGISTER_FIELD_TRANSFORMERS,\n            function(RegisterFieldTransformersEvent $event) {\n                $event->transformers[] = new FormieFieldTransformer();\n            },\n        );\n    }\n}",{"id":1117,"title":1118,"titles":1119,"content":1120,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-fields#fieldtransformerinterface","FieldTransformerInterface",[81],"MethodDescriptiongetSupportedFieldClasses()Return FQCNs of field classes this transformer handles.matchesField()Custom matching logic. Return true to claim, false to skip, null to fall through to class matching.describeField()Enrich the field info array with valueFormat, hint, and other metadata for the AI.serializeValue()Convert a field value into a JSON-serializable format for the AI context.normalizeValue()Convert an AI-provided value back into Craft's expected format. Return null if no normalization is needed.",{"id":1122,"title":1123,"titles":1124,"content":1125,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-fields#matching","Matching",[81],"Transformers are checked in order. For each field, the registry calls matchesField() first. If it returns null, class matching via getSupportedFieldClasses() is used as fallback. Event-registered transformers are checked before built-in ones, so you can override default behavior for any field type. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":86,"title":85,"titles":1127,"content":1128,"level":713},[],"Register a custom AI provider for CoPilot. CoPilot ships with OpenAI, Anthropic, and Gemini providers. You can add your own by implementing ProviderInterface and registering it via events.",{"id":1130,"title":1131,"titles":1132,"content":1133,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-providers#registration","Registration",[85],"use samuelreichor\\coPilot\\events\\RegisterProvidersEvent;\nuse samuelreichor\\coPilot\\services\\ProviderService;\nuse yii\\base\\Event;\n\nEvent::on(\n    ProviderService::class,\n    ProviderService::EVENT_REGISTER_PROVIDERS,\n    function(RegisterProvidersEvent $event) {\n        $event->providers['myProvider'] = new MyCustomProvider();\n    },\n); The key in $event->providers is the provider handle used in configuration.",{"id":1135,"title":1136,"titles":1137,"content":1138,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-providers#providerinterface","ProviderInterface",[85],"Your provider must implement samuelreichor\\coPilot\\providers\\ProviderInterface. The interface requires methods for configuration, model selection, chat completion, and streaming. Use one of the built-in providers as a reference implementation: OpenAIProviderAnthropicProviderGeminiProvider html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":90,"title":89,"titles":1140,"content":1141,"level":713},[],"Register custom tools that the CoPilot agent can use. Tools are actions the agent can call during a conversation. CoPilot ships with built-in tools for reading, searching, and editing content. You can add your own via events.",{"id":1143,"title":681,"titles":1144,"content":1145,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-tools#example",[89],"A searchFormieForms tool that lets the agent find Formie form handles: \u003C?php\n\nnamespace modules\\mymodule\\tools;\n\nuse samuelreichor\\coPilot\\enums\\AuditAction;\nuse samuelreichor\\coPilot\\helpers\\PluginHelper;\nuse samuelreichor\\coPilot\\tools\\ToolInterface;\n\nclass SearchFormieFormsTool implements ToolInterface\n{\n    public function getName(): string\n    {\n        return 'searchFormieForms';\n    }\n\n    public function getLabel(): string\n    {\n        return 'Search Formie Forms';\n    }\n\n    public function getAction(): AuditAction\n    {\n        return AuditAction::Search;\n    }\n\n    public function getDescription(): string\n    {\n        return 'Searches Formie forms by title. Returns form handles '\n            . 'that can be used in Formie fields. Call this to find '\n            . 'the correct form handle before setting a Formie field value.';\n    }\n\n    public function getParameters(): array\n    {\n        return [\n            'type' => 'object',\n            'properties' => [\n                'query' => [\n                    'type' => 'string',\n                    'description' => 'Optional search query to filter forms by title.',\n                ],\n            ],\n            'required' => [],\n        ];\n    }\n\n    public function execute(array $arguments): array\n    {\n        if (!PluginHelper::isPluginInstalledAndEnabled('formie')) {\n            return ['error' => 'Formie plugin is not installed.'];\n        }\n\n        $formsQuery = \\verbb\\formie\\elements\\Form::find();\n\n        $query = $arguments['query'] ?? null;\n        if ($query) {\n            $formsQuery->title('*' . $query . '*');\n        }\n\n        $forms = $formsQuery->all();\n\n        if (empty($forms)) {\n            return ['results' => [], 'message' => 'No forms found.'];\n        }\n\n        $results = array_map(fn($form) => [\n            'id' => $form->id,\n            'title' => $form->title,\n            'handle' => $form->handle,\n        ], $forms);\n\n        return [\n            'results' => $results,\n            'total' => count($results),\n        ];\n    }\n}\n\u003C?php\n\nnamespace modules\\mymodule;\n\nuse modules\\mymodule\\tools\\SearchFormieFormsTool;\nuse samuelreichor\\coPilot\\events\\RegisterToolsEvent;\nuse samuelreichor\\coPilot\\services\\AgentService;\nuse yii\\base\\Event;\nuse yii\\base\\Module;\n\nclass MyModule extends Module\n{\n    public function init(): void\n    {\n        parent::init();\n\n        Event::on(\n            AgentService::class,\n            AgentService::EVENT_REGISTER_TOOLS,\n            function(RegisterToolsEvent $event) {\n                $event->tools[] = new SearchFormieFormsTool();\n            },\n        );\n    }\n}",{"id":1147,"title":1148,"titles":1149,"content":1150,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fcustom-tools#toolinterface","ToolInterface",[89],"MethodReturnsDescriptiongetName()stringUnique tool name for AI function calling.getDescription()stringDescription the AI uses to decide when to call this tool.getParameters()arrayJSON Schema defining the tool's input parameters.getLabel()stringHuman-readable label for the audit log.getAction()AuditActionAudit action type: Read, Search, Create, or Update.execute()arrayRuns the tool and returns a result array. The execute() return value is sent directly to the AI as the tool result. Return an error key to signal failure. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":94,"title":93,"titles":1152,"content":1153,"level":713},[],"Add custom instructions to the CoPilot system prompt. The system prompt controls how the agent behaves — its tone, rules, and domain knowledge. You can append custom sections via the EVENT_BUILD_PROMPT event.",{"id":1155,"title":681,"titles":1156,"content":1157,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fsystem-prompt#example",[93],"Add project-specific workflow rules that the agent should always follow: \u003C?php\n\nnamespace modules\\mymodule;\n\nuse samuelreichor\\coPilot\\events\\BuildPromptEvent;\nuse samuelreichor\\coPilot\\services\\SystemPromptBuilder;\nuse yii\\base\\Event;\nuse yii\\base\\Module;\n\nclass MyModule extends Module\n{\n    public function init(): void\n    {\n        parent::init();\n\n        Event::on(\n            SystemPromptBuilder::class,\n            SystemPromptBuilder::EVENT_BUILD_PROMPT,\n            function(BuildPromptEvent $event) {\n                $event->sections[] = implode(\"\\n\", [\n                    '## Content Workflow Rules',\n                    'Entries in the \"products\" section are synced to Shopify — never change their slug or status.',\n                    'Every blog post must have at least one category and a featured image before publishing.',\n                    'When creating entries in the \"legal\" section, always set the \"reviewRequired\" lightswitch to true.',\n                ]);\n            },\n        );\n    }\n}",{"id":1159,"title":1160,"titles":1161,"content":1162,"level":719},"\u002Flibraries\u002Fcraft-co-pilot\u002Fdevelopers\u002Fsystem-prompt#how-it-works","How It Works",[93],"The $event->sections array contains all prompt sections as strings. They are joined with double newlines to form the final system prompt. Your sections are appended after the built-in ones. Use Markdown headings (##) to structure your sections — this helps the AI parse and follow the instructions. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":11,"title":10,"titles":1164,"content":1165,"level":713},[],"AI agent plugin for Craft CMS that creates, edits, translates, and publishes content through natural language. An AI agent that lives in your Craft CMS control panel. It reads your content structure, writes in your brand voice, and handles everything from single field edits to full multi-site translations.",{"id":1167,"title":1168,"titles":1169,"content":1170,"level":719},"\u002Flibraries\u002Fcraft-co-pilot#features","Features",[10],"AI Chat in the Control Panel: A full chat interface and an entry slideoutRead, Write & Publish: Create entries, fill fields, update content, and publish it directlyMulti-Site Translation: Translate entries across sites and languages with automatic propagation handlingMulti-Provider Support: Use Langdock, Anthropic, OpenAI, or Google GeminiGranular Permissions: Control read, write, or block access per section, volume, and category groupBrand Voice & Glossary: Define tone, terminology, and forbidden words to keep content on brandCustom Commands & Tools: Register your own slash commands and tools via events to extend the agent with project-specific capabilitiesAudit Log: Full traceability of every read, create, and update the agent performs (with field-level diffs)Web Search: Let the agent browse the web to research and enrich your content",{"id":1172,"title":1173,"titles":1174,"content":1175,"level":719},"\u002Flibraries\u002Fcraft-co-pilot#why-copilot","Why CoPilot?",[10],"If you've worked on a Craft project with 10+ languages, you know the drill. Creating a single entry means clicking through dozens of fields. Translating it to five languages means doing that five more times. Keeping everything consistent across sites is tedious, repetitive work that nobody enjoys. We've been building and maintaining large Craft sites for years, and this has always been the part that slows teams down the most. To that point that developing the website from scatch was faster than the actual conent creation. CoPilot started as an experiment: what if an AI agent actually understood Craft's content model? Not a generic chatbot bolted onto the CP, but an agent that knows your sections, reads your field layouts, respects your permissions, and writes content the way your brand voice demands. After weeks of real-world testing with complex multi-site setups, we're confident it delivers on that promise. But we'll let you be the judge and we are looking forward for Feedback!",{"id":1177,"title":1178,"titles":1179,"content":1180,"level":719},"\u002Flibraries\u002Fcraft-co-pilot#getting-started","Getting Started",[10],"Install via Composer and configure your AI provider.Compare providers and pick the right model.Permissions, agent behavior, and content settings.",{"id":108,"title":107,"titles":1182,"content":1183,"level":713},[],"Learn how to install the Custom Queue Manager plugin for Craft CMS.",{"id":1185,"title":716,"titles":1186,"content":1187,"level":719},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Finstallation#requirements",[107],"Craft CMS 5.0.0 or laterPHP 8.2 or later",{"id":1189,"title":722,"titles":1190,"content":1191,"level":719},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Finstallation#craft-plugin-store",[107],"To install Custom Queue Manager, navigate to the Plugin Store in your Craft control panel, search for \"Custom Queue Manager,\" and click Install.",{"id":1193,"title":727,"titles":1194,"content":1195,"level":719},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Finstallation#composer",[107],"ddev composer require samuelreichor\u002Fcraft-custom-queue-manager &&\nddev craft plugin\u002Finstall custom-queue-manager\ncomposer require samuelreichor\u002Fcraft-custom-queue-manager &&\nphp craft plugin\u002Finstall custom-queue-manager",{"id":1197,"title":1198,"titles":1199,"content":1200,"level":719},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Finstallation#register-custom-queues","Register Custom Queues",[107],"Custom Queue Manager only monitors custom queues. You need to register at least one custom queue in your config\u002Fapp.php: \u003C?php\n\u002F\u002F config\u002Fapp.php\n\nreturn [\n    'bootstrap' => ['emailQueue'],\n    'components' => [\n        'emailQueue' => [\n            'class' => \\craft\\queue\\Queue::class,\n        ],\n    ],\n]; After registering a custom queue, the \"Custom Queues\" utility will appear under Utilities in the control panel.",{"id":1202,"title":1203,"titles":1204,"content":1205,"level":719},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Finstallation#running-custom-queues","Running Custom Queues",[107],"Custom queues need to be run separately from Craft's default queue. Each registered queue component gets its own console command using the kebab-case version of the component ID (e.g., emailQueue becomes email-queue): # Run once\nphp craft email-queue\u002Frun --verbose\n\n# Run as daemon\nphp craft email-queue\u002Flisten --verbose",{"id":1207,"title":1208,"titles":1209,"content":1210,"level":740},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Finstallation#ddev-queue-runner","DDEV Queue Runner",[107,1203],"To run custom queues automatically in DDEV, add web_extra_daemons to your .ddev\u002Fconfig.yaml. Each daemon runs as a separate supervisor process that automatically restarts on failure: web_extra_daemons:\n  - name: \"queue-default\"\n    command: \"php \u002Fvar\u002Fwww\u002Fhtml\u002Fcraft queue\u002Flisten --verbose\"\n    directory: \u002Fvar\u002Fwww\u002Fhtml\n  - name: \"queue-email\"\n    command: \"php \u002Fvar\u002Fwww\u002Fhtml\u002Fcraft email-queue\u002Flisten --verbose\"\n    directory: \u002Fvar\u002Fwww\u002Fhtml After updating the config, restart DDEV: ddev restart html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}",{"id":111,"title":29,"titles":1212,"content":1213,"level":713},[],"Learn about all available configuration options for the Custom Queue Manager plugin.",{"id":1215,"title":808,"titles":1216,"content":1217,"level":719},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Fconfiguration#control-panel",[29],"You can manage configuration settings through the Control Panel by visiting Settings → Custom Queue Manager.",{"id":1219,"title":308,"titles":1220,"content":1221,"level":719},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Fconfiguration#settings",[29],"You can define a multi environment aware config in \u002Fconfig\u002Fcustom-queue-manager.php. Settings defined in the config file override control panel settings.",{"id":1223,"title":1224,"titles":1225,"content":1226,"level":740},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Fconfiguration#refreshinterval","refreshInterval",[29,308],"Auto-refresh interval for the queue monitor dashboard in milliseconds. return [\n  '*' => [\n    'refreshInterval' => 2000, \u002F\u002F default\n  ],\n]",{"id":1228,"title":1229,"titles":1230,"content":1231,"level":740},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Fconfiguration#jobsperpage","jobsPerPage",[29,308],"Maximum number of jobs to display per queue. return [\n  '*' => [\n    'jobsPerPage' => 50, \u002F\u002F default\n  ],\n]",{"id":1233,"title":1234,"titles":1235,"content":1236,"level":740},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Fconfiguration#enableemailnotifications","enableEmailNotifications",[29,308],"When enabled, Custom Queue Manager sends an email on the first failure attempt of any queue job. The email includes the job description, queue name, and error message with a link to the control panel. return [\n  '*' => [\n    'enableEmailNotifications' => false, \u002F\u002F default\n  ],\n] You can customize the email template by going to Settings → Email → System Messages and editing the \"When a queue job fails\" message.",{"id":1238,"title":1239,"titles":1240,"content":1241,"level":740},"\u002Flibraries\u002Fcraft-custom-queue-manager\u002Fget-started\u002Fconfiguration#notificationemail","notificationEmail",[29,308],"The email address to send failure notifications to. Required when enableEmailNotifications is enabled. return [\n  '*' => [\n    'notificationEmail' => 'admin@example.com',\n  ],\n] html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":99,"title":98,"titles":1243,"content":1244,"level":713},[],"Manage custom queues in the Craft CMS control panel. Custom Queue Manager adds a utility to the Craft CMS control panel for monitoring and managing custom queue jobs. It auto-discovers all custom queues registered in your app config and provides a real-time dashboard with job management capabilities.",{"id":1246,"title":1168,"titles":1247,"content":1248,"level":719},"\u002Flibraries\u002Fcraft-custom-queue-manager#features",[98],"Custom Queue Discovery: Automatically finds all custom queues registered in your Craft app configReal-time Monitoring: Auto-refreshing dashboard shows job status, progress, and statisticsJob Management: Retry failed jobs or release jobs directly from the control panelBulk Actions: Retry all failed jobs or release all jobs across one or all queuesJob Details: Inspect individual jobs including class, status, progress, and error messagesEmail Notifications: Get notified via email when a queue job failsCustomizable System Messages: Edit the failure notification email template via Craft's System Messages",{"id":1250,"title":1160,"titles":1251,"content":1252,"level":719},"\u002Flibraries\u002Fcraft-custom-queue-manager#how-it-works",[98],"Register custom queues in your config\u002Fapp.phpThe plugin auto-discovers them and adds a utility to the control panelMonitor and manage jobs through the dashboard The utility only appears when at least one custom queue is configured. The plugin does not manage Craft's default queue.",{"id":1254,"title":1178,"titles":1255,"content":1256,"level":719},"\u002Flibraries\u002Fcraft-custom-queue-manager#getting-started",[98],"Install via Composer or the Craft Plugin Store.Set up custom queues and configure plugin settings.",{"id":123,"title":107,"titles":1258,"content":1259,"level":713},[],"Learn how to install the Genesis Craft CMS plugin.",{"id":1261,"title":716,"titles":1262,"content":1263,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fget-started\u002Finstallation#requirements",[107],"Supports Craft CMS > 5PHP 8.2 or later.",{"id":1265,"title":722,"titles":1266,"content":1267,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fget-started\u002Finstallation#craft-plugin-store",[107],"To install Genesis, go to the Plugin Store in your Craft control panel, search for \"Genesis,\" and click the Install button.",{"id":1269,"title":727,"titles":1270,"content":1271,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fget-started\u002Finstallation#composer",[107],"ddev composer require samuelreichor\u002Fcraft-genesis &&\nddev craft plugin\u002Finstall genesis\ncomposer require samuelreichor\u002Fcraft-genesis &&\nphp craft plugin\u002Finstall genesis Or install it from the Craft Plugin Store in your control panel.",{"id":1273,"title":1274,"titles":1275,"content":1276,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fget-started\u002Finstallation#next-steps","Next Steps",[107],"After installation, navigate to Utilities > Genesis Import in your control panel to start importing elements.",{"id":1278,"title":1279,"titles":1280,"content":1281,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fget-started\u002Finstallation#example-config-file","Example Config File",[107],"To get started quickly, use this example config file and get begin to configure it. You can use Title Case or camelCase for the column header. html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":131,"title":130,"titles":1283,"content":1284,"level":713},[],"Import sites to set up your multi-site configuration.",{"id":1286,"title":1287,"titles":1288,"content":1289,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsites#columns","Columns",[130],"ColumnRequiredDescriptionhandleYesUnique identifier for the sitenameYesDisplay namelanguageYesLanguage code (e.g., en, de, de-AT)baseUrlNoSite URL, supports aliases like @webprimaryNoSet as primary site (true\u002Ffalse)hasUrlsNoSite has public URLs (true\u002Ffalse)enabledNoSite is enabled (true\u002Ffalse)groupNoSite group Label",{"id":1291,"title":681,"titles":1292,"content":1293,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsites#example",[130],"handle,name,language,baseUrl,primary,hasUrls,enabled,group\nen,English,en,$PRIMARY_URL_EN,TRUE,TRUE,TRUE,Default\nde,Deutsch,de,$PRIMARY_URL_DE,FALSE,TRUE,TRUE,Default",{"id":1295,"title":1296,"titles":1297,"content":1298,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsites#language-codes","Language Codes",[130],"Use valid BCP 47 language tags: en - Englishde - Germande-AT - Austrian Germanzh-Hans - Simplified Chinesept-BR - Brazilian Portuguese",{"id":1300,"title":1301,"titles":1302,"content":1303,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsites#boolean-values","Boolean Values",[130],"These values are accepted for boolean fields: True: true, TRUE, 1, yes, onFalse: false, FALSE, 0, no, off html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":135,"title":134,"titles":1305,"content":1306,"level":713},[],"Import entry types to define your content structures.",{"id":1308,"title":1287,"titles":1309,"content":1310,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fentry-types#columns",[134],"ColumnRequiredDescriptionhandleYesUnique identifiernameYesDisplay namedescriptionNoDescription texttitleTranslationMethodNoHow titles are translatedtitleTranslationKeyFormatNoCustom translation key formatshowSlugNoShow slug field (true\u002Ffalse)slugTranslationMethodNoHow slugs are translatedslugTranslationKeyFormatNoCustom slug translation key formatshowStatusFieldNoShow status field (true\u002Ffalse)",{"id":1312,"title":681,"titles":1313,"content":1314,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fentry-types#example",[134],"handle,name,description,titleTranslationMethod,titleTranslationKeyFormat,showSlug,slugTranslationMethod,slugTranslationKeyFormat,showStatusField\ndefault_pagebuilder,Default Pagebuilder,Build pages with this entry type,Translate for each language,,TRUE,Not translatable,,TRUE\ndefault_contentbuilder,Default Contentbuilder,Build parts of pages with this entry type,Custom…,{{include('global\u002Fsite.twig')}},FALSE,Not translatable,,TRUE",{"id":1316,"title":1317,"titles":1318,"content":1319,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fentry-types#translation-methods","Translation Methods",[134],"ValueLabelDescriptionnoneNot translatableSame value across all sitessiteTranslate for each siteDifferent value per sitesiteGroupTranslate for each site groupDifferent value per site grouplanguageTranslate for each languageDifferent value per languagecustomCustom...Use custom key format When using custom, you must provide the corresponding KeyFormat column.",{"id":1321,"title":1322,"titles":1323,"content":1324,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fentry-types#custom-translation-example","Custom Translation Example",[134],"handle,name,titleTranslationMethod,titleTranslationKeyFormat\nshared,Shared Content,custom,{section.handle} html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":139,"title":138,"titles":1326,"content":1327,"level":713},[],"Import sections to organize your content structure.",{"id":1329,"title":1287,"titles":1330,"content":1331,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsections#columns",[138],"ColumnRequiredDescriptionhandleYesUnique identifiernameYesDisplay nametypeYesSection type: single, channel, structureentryTypesYesComma-separated entry type handlesenableVersioningNoIf versioning should be enabledsiteNoSite handle for site-specific settingssiteUriNoURI pattern (e.g., blog\u002F{slug})siteTemplateNoTemplate pathsiteHomeNoIs homepage (true\u002Ffalse, singles only)siteDefaultStatusNoDefault status: true\u002FfalsepropagationMethodNoHow entries propagate across sitesmaxAuthorsNoMaximum number of authorsmaxLevelsNoMaximum nesting levels (structures only)defaultPlacementNoNew entry placement (structures only)enablePreviewTargetsNoIf preview targets existpreviewTargetLabelNoPreview Target labelpreviewTargetUrlFormatNoPreview Target url formatpreviewTargetAutoRefreshNoIf Preview Target should auto refresh",{"id":1333,"title":681,"titles":1334,"content":1335,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsections#example",[138],"handle,name,type,site,siteUri,siteTemplate,siteHome,siteDefaultStatus,entryTypes,propagationMethod,maxAuthors,maxLevels,defaultPlacement\nblog,Blog,channel,en,{slug},\u002Fpages\u002F_entry.twig,,TRUE,\"default_pagebuilder, default_contentbuilder\",Only save entries to the site they were created in,2,,\nblog,,,de,{slug},\u002Fpages\u002F_entry.twig,,FALSE,,,,,\nhome,Home,single,en,,\u002Fpages\u002F_entry.twig,TRUE,TRUE,default_pagebuilder,Save entries to other sites in the same site group,,,\npages,Pages,structure,en,{slug},\u002Fpages\u002F_entry.twig,,TRUE,default_contentbuilder,Save entries to other sites with the same language,10,4,Before other entries",{"id":1337,"title":1338,"titles":1339,"content":1340,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsections#section-types","Section Types",[138],"TypeDescriptionsingleOne entry only, typically for homepage or about pagechannelMultiple entries in chronological orderstructureHierarchical entries with parent-child relationships",{"id":1342,"title":1343,"titles":1344,"content":1345,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsections#propagation-methods","Propagation Methods",[138],"ValueLabelDescriptionallSave to all sitesEntry exists in all sitessiteGroupSave to site groupEntry exists in same site grouplanguageSave to sites with same languageEntry exists in same-language sitesnoneOnly save to this siteEntry is site-specificcustomCustom...Use custom propagation rules",{"id":1347,"title":1348,"titles":1349,"content":1350,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsections#default-placement","Default Placement",[138],"For structures you can use the defaultPlacement. ValueLabelDescriptionbeginningBefore other entriesPlace new entries at the beginningendAfter other entriesPlace new entries at the end",{"id":1352,"title":1353,"titles":1354,"content":1355,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsections#multiple-entry-types","Multiple Entry Types",[138],"Separate multiple entry type handles with commas: handle,name,type,entryTypes\nnews,News,channel,\"article, event,announcement\" Use quotes when the value contains commas.",{"id":1357,"title":1358,"titles":1359,"content":1360,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsections#multiple-site-settings","Multiple Site Settings",[138],"For multiple site settings, use different rows with the same section handle.",{"id":1362,"title":1363,"titles":1364,"content":1365,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fsections#multiple-preview-targets","Multiple Preview Targets",[138],"For multiple preview targets, use different rows with the same section handle. html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":143,"title":142,"titles":1367,"content":1368,"level":713},[],"Import local filesystems for asset storage.",{"id":1370,"title":1287,"titles":1371,"content":1372,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Ffilesystems#columns",[142],"ColumnRequiredDescriptionhandleYesUnique identifiernameYesDisplay namebasePathYesStorage pathpublicUrlsNoHas public URLs (true\u002Ffalse)baseUrlNoPublic URL (required when publicUrls is true)",{"id":1374,"title":681,"titles":1375,"content":1376,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Ffilesystems#example",[142],"handle,name,publicUrls,baseUrl,basePath\nimages,Images,FALSE,,@webroot\u002Fassets\u002Fimages\ngraphics,Graphics,TRUE,@web\u002Fassets\u002Fgraphics,@webroot\u002Fassets\u002Fgraphics html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":147,"title":146,"titles":1378,"content":1379,"level":713},[],"Import asset volumes to organize your media files.",{"id":1381,"title":1287,"titles":1382,"content":1383,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fassets#columns",[146],"ColumnRequiredDescriptionhandleYesUnique identifiernameYesDisplay namefsHandleYesFilesystem handle (must exist)subpathNoSubpath within filesystemtransformFsHandleNoFilesystem for image transforms (must exist)transformSubpathNoSubpath for transformstitleTranslationMethodNoHow titles are translatedtitleTranslationKeyFormatNoCustom title translation keyaltTranslationMethodNoHow alt text is translatedaltTranslationKeyFormatNoCustom alt translation key",{"id":1385,"title":681,"titles":1386,"content":1387,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fassets#example",[146],"handle,name,fsHandle,subpath,transformFsHandle,transformSubpath,titleTranslationMethod,titleTranslationKeyFormat,altTranslationMethod,altTranslationKeyFormat\nimages,Images,images,images,images,\u002Fimages\u002Ftransforms,Translate for each site,,Custom…,{{include('global\u002Fsite.twig')}}\ngraphics,Graphics,graphics,,,,Custom…,{{include('global\u002Fsite.twig')}},,",{"id":1389,"title":1390,"titles":1391,"content":1392,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fassets#prerequisites","Prerequisites",[146],"The filesystem referenced by fsHandle must exist before importing asset volumes. Import filesystems first, then assets.",{"id":1394,"title":1395,"titles":1396,"content":1397,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fassets#transform-filesystem","Transform Filesystem",[146],"Use a separate filesystem for image transforms to keep originals and transforms organized: handle,name,fsHandle,subpath,transformFsHandle,transformSubpath\nimages,Images,assets,images,assets,_transforms\u002Fimages",{"id":1399,"title":1317,"titles":1400,"content":1401,"level":719},"\u002Flibraries\u002Fcraft-genesis\u002Fusage\u002Fassets#translation-methods",[146],"Same as entry types: ValueDescriptionnoneNot translatablesiteTranslate per sitesiteGroupTranslate per site grouplanguageTranslate per languagecustomUse custom key format html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":115,"title":114,"titles":1403,"content":1404,"level":713},[],"Bulk import Craft elements by csv files.",{"id":1406,"title":1407,"titles":1408,"content":1409,"level":719},"\u002Flibraries\u002Fcraft-genesis#what-can-you-import","What Can You Import?",[114],"Sites - Multi-site setup with language and URL configurationEntry Types - Define content types with translation settingsSections - Channels, structures, and singles with URI patternsFilesystems - Local storage paths for assetsAsset Volumes - Configure where your assets live",{"id":1411,"title":1160,"titles":1412,"content":1413,"level":719},"\u002Flibraries\u002Fcraft-genesis#how-it-works",[114],"Download the CSV template or create a google \u002F excel sheet.Fill in your dataUpload and validate to catch errors before importingImport, Genesis handles the rest via queue jobs",{"id":1415,"title":1416,"titles":1417,"content":1418,"level":719},"\u002Flibraries\u002Fcraft-genesis#validation","Validation",[114],"Genesis validates your CSV before importing: Checks for required columnsValidates column names against allowed fieldsVerifies data types (booleans, language codes, etc.)Ensures referenced elements exist (sites, entry types, filesystems) This catches mistakes early so you don't end up with partial imports.",{"id":1420,"title":1279,"titles":1421,"content":1422,"level":719},"\u002Flibraries\u002Fcraft-genesis#example-config-file",[114],"To get started quickly, use this example config file and get begin to configure it.",{"id":159,"title":107,"titles":1424,"content":1425,"level":713},[],"Learn how to install the Insights analytics plugin for Craft CMS.",{"id":1427,"title":716,"titles":1428,"content":1187,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Finstallation#requirements",[107],{"id":1430,"title":722,"titles":1431,"content":1432,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Finstallation#craft-plugin-store",[107],"To install Insights, navigate to the Plugin Store in your Craft control panel, search for \"Insights,\" and click Install.",{"id":1434,"title":727,"titles":1435,"content":1436,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Finstallation#composer",[107],"ddev composer require samuelreichor\u002Fcraft-insights &&\nddev craft plugin\u002Finstall insights\ncomposer require samuelreichor\u002Fcraft-insights &&\nphp craft plugin\u002Finstall insights",{"id":1438,"title":1439,"titles":1440,"content":1441,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Finstallation#add-the-tracking-script","Add the Tracking Script",[107],"After installation, add the tracking script to your base template (usually _layouts\u002Fbase.twig or similar): {{ craft.insights.trackingScript() }} Technically it's not important where you add the script on your page as it always injects the script at the end of the body. That's it! Insights will now track pageviews automatically.",{"id":1443,"title":1444,"titles":1445,"content":1446,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Finstallation#geoip-database","GeoIP Database",[107],"To enable country tracking, you need to download the free MaxMind GeoLite2-Country database: Create a free account at MaxMindDownload the GeoLite2 Country database (.mmdb format)Place the file at storage\u002Fgeoip\u002FGeoLite2-Country.mmdb Or configure a custom path in your settings: \u002F\u002F config\u002Finsights.php\nreturn [\n    'geoIpDatabasePath' => '@storage\u002Fgeoip\u002FGeoLite2-Country.mmdb',\n]; Country data is collected for all editions. Lite users who upgrade to Pro will have historical country data available. The country tracking dashboard is a Pro feature, but setting up the GeoIP database early ensures you have data when you upgrade. Without the database, country tracking is silently skipped. html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}",{"id":162,"title":29,"titles":1448,"content":1449,"level":713},[],"Learn about all available configuration options for the Insights plugin.",{"id":1451,"title":808,"titles":1452,"content":1453,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#control-panel",[29],"You can manage configuration settings through the Control Panel by visiting Settings → Insights.",{"id":1455,"title":308,"titles":1456,"content":1457,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#settings",[29],"You can define a multi environment aware config in \u002Fconfig\u002Finsights.php. Settings defined in the config file override control panel settings.",{"id":1459,"title":1460,"titles":1461,"content":1462,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#enabled","enabled",[29,308],"Enable or disable all tracking globally. return [\n  '*' => [\n    'enabled' => true,\n  ],\n  'staging' => [\n    'enabled' => false, \u002F\u002F disable tracking on staging\n  ],\n]",{"id":1464,"title":1465,"titles":1466,"content":1467,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#respectdonottrack","respectDoNotTrack",[29,308],"Honor the browser's Do Not Track (DNT) header. When enabled, requests with DNT: 1 header are not tracked. return [\n  '*' => [\n    'respectDoNotTrack' => true, \u002F\u002F default\n  ],\n]",{"id":1469,"title":1470,"titles":1471,"content":1472,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#excludeloggedinusers","excludeLoggedInUsers",[29,308],"Skip tracking for authenticated Craft users. Useful to exclude your own team from analytics. return [\n  '*' => [\n    'excludeLoggedInUsers' => false, \u002F\u002F default\n  ],\n  'production' => [\n    'excludeLoggedInUsers' => true, \u002F\u002F don't track logged in users in production\n  ],\n]",{"id":1474,"title":1475,"titles":1476,"content":1477,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#excludedipranges","excludedIpRanges",[29,308],"IP addresses or CIDR ranges to exclude from tracking. return [\n  '*' => [\n    'excludedIpRanges' => [\n      '192.168.1.1',       \u002F\u002F single IP\n      '10.0.0.0\u002F8',        \u002F\u002F CIDR range\n      '172.16.0.0\u002F12',     \u002F\u002F private network\n    ],\n  ],\n]",{"id":1479,"title":1480,"titles":1481,"content":1482,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#excludedpaths","excludedPaths",[29,308],"URL paths to exclude from tracking. Uses prefix matching. return [\n  '*' => [\n    'excludedPaths' => [\n      '\u002Fadmin',       \u002F\u002F matches \u002Fadmin, \u002Fadmin\u002F*, etc.\n      '\u002Fcpresources',\n      '\u002Factions',\n      '\u002Fapi',         \u002F\u002F exclude API endpoints\n      '\u002Fpreview',     \u002F\u002F exclude preview pages\n    ],\n  ],\n]",{"id":1484,"title":1485,"titles":1486,"content":1487,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#geoipdatabasepath","geoIpDatabasePath",[29,308],"Path to the MaxMind GeoLite2-Country database for country tracking. return [\n  '*' => [\n    'geoIpDatabasePath' => '@storage\u002Fgeoip\u002FGeoLite2-Country.mmdb', \u002F\u002F default\n  ],\n] Country data is collected for all editions. Lite users who upgrade to Pro will have historical data available. Without the GeoIP database, country tracking will be silently skipped. See Installation for setup instructions.",{"id":1489,"title":1490,"titles":1491,"content":1492,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#dataretentiondays","dataRetentionDays",[29,308],"Number of days to retain analytics data. Valid range: 1-730 days. return [\n  '*' => [\n    'dataRetentionDays' => 365, \u002F\u002F default: keep data for 1 year\n  ],\n]",{"id":1494,"title":1495,"titles":1496,"content":1497,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#autocleanup","autoCleanup",[29,308],"Automatically delete data older than dataRetentionDays. Cleanup runs daily via Craft's garbage collection. return [\n  '*' => [\n    'autoCleanup' => true, \u002F\u002F default\n  ],\n] Cleanup is irreversible. Old data is permanently deleted.",{"id":1499,"title":1500,"titles":1501,"content":1502,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#usequeue","useQueue",[29,308],"Process tracking events asynchronously via Craft's queue system. Recommended for production to minimize page load impact. return [\n  '*' => [\n    'useQueue' => true, \u002F\u002F default\n  ],\n  'dev' => [\n    'useQueue' => false, \u002F\u002F process synchronously in development\n  ],\n]",{"id":1504,"title":1505,"titles":1506,"content":1507,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#queuejobttr","queueJobTtr",[29,308],"Time to reserve (TTR) for queue jobs in seconds. This is the maximum time a job can run before being considered stalled. Valid range: 60-3600 seconds. return [\n  '*' => [\n    'queueJobTtr' => 300, \u002F\u002F default: 5 minutes\n  ],\n]",{"id":1509,"title":1510,"titles":1511,"content":1512,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#processtrackingjobpriority","processTrackingJobPriority",[29,308],"Priority for tracking queue jobs. Lower number = higher priority. Craft's default priority is 1024. return [\n  '*' => [\n    'processTrackingJobPriority' => 20, \u002F\u002F default\n  ],\n]",{"id":1514,"title":1515,"titles":1516,"content":1517,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#maxretryattempts","maxRetryAttempts",[29,308],"Maximum number of retry attempts for failed queue jobs. Valid range: 0-10. return [\n  '*' => [\n    'maxRetryAttempts' => 3, \u002F\u002F default\n  ],\n]",{"id":1519,"title":1520,"titles":1521,"content":1522,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#realtimettl","realtimeTtl",[29,308],"How long (in seconds) a visitor is considered \"active\" for real-time tracking. Valid range: 60-900 seconds. return [\n  '*' => [\n    'realtimeTtl' => 300, \u002F\u002F default: 5 minutes\n  ],\n]",{"id":1524,"title":1525,"titles":1526,"content":1527,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#defaultdaterange","defaultDateRange",[29,308],"Default date range for the analytics dashboard. Available values: today, 7d, 30d, 90d, 12m. return [\n  '*' => [\n    'defaultDateRange' => '30d', \u002F\u002F default\n  ],\n]",{"id":1529,"title":1530,"titles":1531,"content":1532,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#showrealtimewidget","showRealtimeWidget",[29,308],"Show the real-time visitors widget on the dashboard. return [\n  '*' => [\n    'showRealtimeWidget' => true, \u002F\u002F default\n  ],\n]",{"id":1534,"title":1535,"titles":1536,"content":1537,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#showentrysidebar","showEntrySidebar",[29,308],"Display analytics statistics in the entry editor sidebar. return [\n  '*' => [\n    'showEntrySidebar' => true, \u002F\u002F default\n  ],\n]",{"id":1539,"title":1540,"titles":1541,"content":1542,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#loglevel","logLevel",[29,308],"Control the verbosity of plugin logging. Available values: default, debug. return [\n  '*' => [\n    'logLevel' => 'default',\n  ],\n  'dev' => [\n    'logLevel' => 'debug', \u002F\u002F more detailed logs in development\n  ],\n]",{"id":1544,"title":1545,"titles":1546,"content":1547,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#custom-queue","Custom Queue",[29],"By default, Insights uses Craft's main queue. For high-traffic sites, you can configure a separate queue to prevent analytics jobs from blocking other important jobs. Add the insightsQueue component to your config\u002Fapp.php: \u003C?php\n\u002F\u002F config\u002Fapp.php\n\nreturn [\n    'bootstrap' => ['insightsQueue'],\n    'components' => [\n        'insightsQueue' => [\n            'class' => \\craft\\queue\\Queue::class,\n        ],\n    ],\n]; Then run the custom queue separately: # Run once\nphp craft insights-queue\u002Frun\n\n# Run as daemon\nphp craft insights-queue\u002Flisten --verbose If insightsQueue is not configured, Insights automatically falls back to Craft's default queue. No additional configuration required.",{"id":1549,"title":1550,"titles":1551,"content":1552,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#external-database","External Database",[29],"Store analytics data in a separate database to keep your main Craft database lean. This is useful for high-traffic sites or when you want to isolate analytics data.",{"id":1554,"title":29,"titles":1555,"content":1556,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#configuration",[29,1550],"Add the insightsDb component to your config\u002Fapp.php: \u003C?php\n\u002F\u002F config\u002Fapp.php\n\nuse craft\\helpers\\App;\n\nreturn [\n    'components' => [\n        'insightsDb' => [\n            'class' => \\craft\\db\\Connection::class,\n            'dsn' => App::env('INSIGHTS_DB_DSN'),\n            'username' => App::env('INSIGHTS_DB_USER'),\n            'password' => App::env('INSIGHTS_DB_PASSWORD'),\n            'tablePrefix' => App::env('INSIGHTS_DB_TABLE_PREFIX') ?: '',\n        ],\n    ],\n]; Add environment variables to your .env: INSIGHTS_DB_DSN=\"mysql:host=localhost;port=3306;dbname=insights\"\nINSIGHTS_DB_USER=\"insights_user\"\nINSIGHTS_DB_PASSWORD=\"secret\"\nINSIGHTS_DB_TABLE_PREFIX=\"\" Enable external database in config\u002Finsights.php: return [\n  '*' => [\n    'useExternalDatabase' => true,\n  ],\n]",{"id":1558,"title":1559,"titles":1560,"content":1561,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#database-commands","Database Commands",[29,1550],"# Test connection\nphp craft insights\u002Fdatabase\u002Ftest\n\n# Show connection status\nphp craft insights\u002Fdatabase\u002Fstatus\n\n# Create tables in external database\nphp craft insights\u002Fdatabase\u002Fmigrate\n\n# Migrate existing data from Craft DB to external DB\nphp craft insights\u002Fdatabase\u002Fmigrate-data\nphp craft insights\u002Fdatabase\u002Fmigrate-data --force        # Clear target first\nphp craft insights\u002Fdatabase\u002Fmigrate-data --delete-source # Remove from Craft DB after External database is a Pro feature. The insightsDb component must be configured before enabling useExternalDatabase.",{"id":1563,"title":907,"titles":1564,"content":1565,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fget-started\u002Fconfiguration#multi-environment-example",[29],"A complete example showing environment-specific configuration: \u003C?php\n\u002F\u002F config\u002Finsights.php\n\nuse craft\\helpers\\App;\n\nreturn [\n  '*' => [\n    'enabled' => true,\n    'respectDoNotTrack' => true,\n    'excludeLoggedInUsers' => false,\n    'excludedPaths' => ['\u002Fadmin', '\u002Fcpresources', '\u002Factions'],\n    'dataRetentionDays' => 365,\n    'autoCleanup' => true,\n    'useQueue' => true,\n    'defaultDateRange' => '30d',\n  ],\n  'dev' => [\n    'useQueue' => false,\n    'logLevel' => 'debug',\n  ],\n  'staging' => [\n    'enabled' => App::env('INSIGHTS_ENABLED') ?? false,\n  ],\n  'production' => [\n    'excludeLoggedInUsers' => true,\n  ],\n]; html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}",{"id":171,"title":170,"titles":1567,"content":1568,"level":713},[],"Learn how Insights works and if it fits your needs. Insights is a privacy-first analytics plugin for Craft CMS. It tracks pageviews, referrers and devices without storing personal data or requiring cookie consent banners.",{"id":1570,"title":1571,"titles":1572,"content":1573,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Foverview#what-its-not","What It's Not",[170],"Insights is intentionally limited compared to full-featured analytics platforms. It's designed for content-focused websites that need basic traffic insights without complexity. Insights is NOT: A Google Analytics replacement for marketing teamsAn A\u002FB testing or conversion optimization platformA heat mapping or session recording toolA real-time user journey trackerAn advertising or retargeting platform Insights IS: A simple way to see what content performs wellA privacy-respecting alternative to invasive trackersA tool that works without cookie bannersA lightweight script that won't slow down your site",{"id":1575,"title":1576,"titles":1577,"content":1578,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Foverview#who-should-use-insights","Who Should Use Insights?",[170],"Insights is ideal for: Content websites that want basic traffic metricsAgency clients who need simple, understandable statsGDPR-conscious sites that want to avoid cookie consent issuesPerformance-focused developers who want minimal tracking overhead Consider a different tool if you need: New vs returning visitor trackingUser-level tracking and segmentationE-commerce conversion funnelsMarketing attribution modelingIntegration with advertising platforms",{"id":1580,"title":1581,"titles":1582,"content":1583,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Foverview#feature-comparison","Feature Comparison",[170],"FeatureInsightsGoogle AnalyticsMatomoPlausiblePrivacyCookie-freeYesNoOptionalYesNo fingerprintingYesNoOptionalYesIP anonymizationDiscardedAnonymizedConfigurableDiscardedGDPR consent requiredNoYesDependsNoDataPageviewsYesYesYesYesUnique visitorsDaily hashCookiesCookiesDaily hashReferrersYesYesYesYesUTM campaignsProYesYesYesDevice\u002FbrowserYesYesYesYesCountryProYesYesYesUser eventsProYesYesYesScroll depthProYesPluginYesEntry\u002Fexit pagesProYesYesYesOutbound linksProYesPluginYesSite searchProYesYesNoReturning visitorsNoYesYesNoUser flowsNoYesYesNoHostingSelf-hostedYesNoYesOptionalData locationYour serverGoogleYour serverEU\u002FUSIntegrationCraft CMS WidgetsYesNoNoNoEntry sidebar statsYesNoNoNoTwig APIYesNoNoNo",{"id":1585,"title":1586,"titles":1587,"content":1588,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Foverview#how-data-is-stored","How Data Is Stored",[170],"Unlike traditional analytics that store individual events, Insights aggregates data immediately: Pageview → UPDATE pageviews SET views = views + 1 WHERE url = '\u002Fabout' This means: Smaller database - No individual event logsFaster queries - Pre-aggregated dataBetter privacy - No way to reconstruct user sessionsGDPR compliant - No personal data stored",{"id":1590,"title":1591,"titles":1592,"content":1593,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Foverview#script-size","Script Size",[170],"The tracking script is approximately 3KB (gzipped) and loads asynchronously. It has zero dependencies and won't block page rendering. For comparison: ScriptSize (gzipped)Insights~3 KBGoogle Analytics~45 KBMatomo~22 KBPlausible~1 KB",{"id":175,"title":174,"titles":1595,"content":1596,"level":713},[],"See what Insights can do for your website analytics. A visual walkthrough of everything Insights offers - from basic traffic metrics to advanced marketing analytics.",{"id":1598,"title":1599,"titles":1600,"content":1601,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#dashboard","Dashboard",[174],"Everything you need, one screen. No clutter, no complexity. Your key metrics front and center: Pageviews, Unique Visitors, Bounce Rate, Time on Page, and Real-time Visitors. Trend indicators show growth or decline compared to the previous period.",{"id":1603,"title":1604,"titles":1605,"content":1606,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#know-your-content","Know Your Content",[174],"See which pages resonate with your audience.",{"id":1608,"title":1609,"titles":1610,"content":1611,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#track-traffic-sources","Track Traffic Sources",[174],"Understand where your visitors come from - automatically classified into Direct, Search, Social, and Referral. How referrers are classified →",{"id":1613,"title":1614,"titles":1615,"content":1616,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#device-insights","Device Insights",[174],"Know your audience: Desktop, Mobile, or Tablet. Optimize for what matters.",{"id":1618,"title":1619,"titles":1620,"content":1621,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#campaign-tracking","Campaign Tracking",[174],"Measure your marketing efforts with full UTM support. How campaigns are tracked →",{"id":1623,"title":1624,"titles":1625,"content":1626,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#country-analytics","Country Analytics",[174],"See where your visitors are located - privacy-friendly, no IP storage.",{"id":1628,"title":194,"titles":1629,"content":1630,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#user-events",[174],"Track button clicks, form submissions, downloads - anything that matters to your business. Implementation guide →",{"id":1632,"title":1633,"titles":1634,"content":1635,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#outbound-links","Outbound Links",[174],"Know where users go when they leave. Track affiliate links and external resources. Implementation guide →",{"id":1637,"title":1638,"titles":1639,"content":1640,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#site-searches","Site Searches",[174],"Discover what your visitors are looking for. Find content gaps. Implementation guide →",{"id":1642,"title":1643,"titles":1644,"content":1645,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#scroll-depth","Scroll Depth",[174],"See how far visitors actually read. Optimize content placement. How scroll depth works →",{"id":1647,"title":1648,"titles":1649,"content":1650,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#entry-exit-pages","Entry & Exit Pages",[174],"Find your best landing pages. Identify where users drop off. How sessions work →",{"id":1652,"title":1653,"titles":1654,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#craft-cms-integrations","Craft CMS Integrations",[174],{"id":1656,"title":1657,"titles":1658,"content":1659,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#entry-sidebar","Entry Sidebar",[174,1653],"Stats right where you edit. No context switching.",{"id":1661,"title":1662,"titles":1663,"content":1664,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#dashboard-widgets","Dashboard Widgets",[174,1653],"Key metrics on your Craft dashboard.",{"id":1666,"title":1667,"titles":1668,"content":1669,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Ffeature-tour#export-your-data","Export Your Data",[174],"One-click CSV export for all your data. Take it anywhere.",{"id":179,"title":178,"titles":1671,"content":1672,"level":713},[],"How Insights ensures GDPR\u002FDSGVO compliance and protects user privacy. Insights was built from the ground up with privacy as a core principle. It provides meaningful analytics without compromising user privacy or requiring consent banners.",{"id":1674,"title":1675,"titles":1676,"content":1677,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#no-cookies","No Cookies",[178],"Insights does not use cookies, localStorage, or any other client-side storage mechanism. This means: No cookie consent banner requiredNo \"accept cookies\" popupsCompliant with strict cookie laws (GDPR, ePrivacy, CCPA)",{"id":1679,"title":1680,"titles":1681,"content":1682,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#no-fingerprinting","No Fingerprinting",[178],"Unlike many analytics tools, Insights does not fingerprint users. We don't collect or combine: Canvas fingerprintsWebGL fingerprintsAudio fingerprintsInstalled fonts or pluginsScreen resolution (only category: small\u002Fmedium\u002Flarge)TimezoneHardware characteristics",{"id":1684,"title":1685,"titles":1686,"content":1687,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#visitor-identification","Visitor Identification",[178],"Instead of tracking individuals, Insights uses a daily-rotating hash based on the same approach as Plausible and Fathom: hash = SHA256(salt | date | ip | browser | language | screen)",{"id":1689,"title":1690,"titles":1691,"content":1692,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#hash-attributes","Hash Attributes",[178,1685],"AttributeDescriptionsaltDaily random value (prevents rainbow table attacks)dateCurrent date - hash is only valid for todayipIP address for visitor uniquenessbrowserBrowser family only (e.g., \"Chrome\"), no versionlanguagePrimary browser language (e.g., \"de\")screenScreen category (s\u002Fm\u002Fl) Important: The IP address is used only for generating this hash and is immediately discarded. It is never written to any database, log file, or storage.",{"id":1694,"title":1695,"titles":1696,"content":1697,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#why-this-is-gdpr-compliant","Why This Is GDPR Compliant",[178,1685],"IP is never stored - Only used for hash calculation, then discardedHash is irreversible - SHA256 is a one-way functionDaily rotation - Salt and date change daily, no long-term tracking possibleNo cookies\u002Fstorage - Nothing is stored on the visitor's deviceLegal basis - Legitimate interest (Art. 6(1)(f) GDPR)",{"id":1699,"title":1700,"titles":1701,"content":1702,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#properties","Properties",[178,1685],"PropertyBenefitDaily rotationSame user = new hash tomorrowNo persistenceNothing stored on user's deviceNon-reversibleSHA256 is a one-way hash - cannot recover IPIndustry standardSame approach as Plausible & Fathom",{"id":1704,"title":1705,"titles":1706,"content":1707,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#ip-address-handling","IP Address Handling",[178],"IP addresses are never stored - they are only used transiently for: Visitor hash generation - Combined with salt, date, browser, language, and screen to create an anonymous daily identifierExcluded IP filtering (Pro) - Your configured IP\u002FCIDR exclusionsGeoIP lookup (Pro) - Extracting country code only Bot detection uses User-Agent analysis, not IP addresses. Common bot signatures like \"bot\", \"crawler\", \"spider\", \"lighthouse\", \"pingdom\", \"uptimerobot\" are filtered automatically.",{"id":1709,"title":1710,"titles":1711,"content":1712,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#data-flow","Data Flow",[178,1705],"Browser loads insights.jsJS sends POST to \u002Factions\u002Finsights\u002Ftrack (User-Agent, Accept-Language, IP sent automatically)Server generates hash via VisitorService.generateHash()Database is updated (uniqueVisitors += 1)IP is NOT stored Request arrives with IP + User-Agent + Accept-Language\n    ↓\nBot check (User-Agent only): \"googlebot\" → reject\n    ↓\nIP exclusion check (Pro): 192.168.1.0\u002F24 → reject\n    ↓\nGenerate visitor hash: SHA256(salt | date | ip | browser | language | screen)\n    ↓\nGeoIP lookup (Pro): IP → \"DE\" (country code only)\n    ↓\nIP immediately discarded (never written to disk)\n    ↓\nOnly hash and country code stored",{"id":1714,"title":1715,"titles":1716,"content":1717,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#why-this-is-safe","Why This Is Safe",[178,1705],"ConcernProtectionBrute-force attackDaily salt rotation makes it computationally infeasibleRainbow tablesSalt + date + browser + language + screen creates unique combinationsCross-day trackingNew salt daily = new hash = no correlation",{"id":1719,"title":1720,"titles":1721,"content":1722,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#limitations","Limitations",[178,1705],"ScenarioResultSame visitor, same daySame hash → counted as 1 unique visitorSame visitor, next dayNew hash → counted as new visitorVPN\u002Fproxy changesNew IP → counted as new visitorBrowser changesNew hash → counted as new visitor The daily salt rotation means Insights cannot distinguish between new and returning visitors across days. The same person visiting today and tomorrow generates two unrelated hashes. This is an intentional privacy trade-off.",{"id":1724,"title":1725,"titles":1726,"content":1727,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#static-caching","Static Caching",[178,1705],"Static caching is not a problem since POST requests are not cached. When using a CDN or reverse proxy, ensure trustedProxies is configured in Craft to get the correct visitor IP.",{"id":1729,"title":1730,"titles":1731,"content":1732,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#data-minimization","Data Minimization",[178],"Insights practices strict data minimization: CollectedNot CollectedPage URL pathQuery parametersReferrer domainFull referrer URLBrowser familyBrowser versionOS familyOS versionDevice typeDevice modelScreen categoryExact resolutionPrimary languageFull Accept-LanguageCountry codeCity, region, postal code",{"id":1734,"title":1735,"titles":1736,"content":1737,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#aggregated-storage","Aggregated Storage",[178],"Raw events are never stored. All data is immediately aggregated: Pageview → UPDATE stats SET views = views + 1 WHERE url = '\u002Fpage' This means: No individual user sessionsNo event logsNo user timelinesNo way to reconstruct individual behavior",{"id":1739,"title":1059,"titles":1740,"content":1741,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#data-retention",[178],"Configure automatic data cleanup: \u002F\u002F config\u002Finsights.php\nreturn [\n    'dataRetentionDays' => 365,  \u002F\u002F Delete data older than 1 year\n    'autoCleanup' => true,       \u002F\u002F Run daily cleanup\n]; Cleanup is automatic and irreversible. Old data is permanently deleted.",{"id":1743,"title":1744,"titles":1745,"content":1746,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#do-not-track","Do Not Track",[178],"Insights respects the browser's DNT (Do Not Track) header by default: 'respectDoNotTrack' => true,  \u002F\u002F Default When enabled: Requests with DNT: 1 header are not trackedNo data is collected for these visitors",{"id":1748,"title":1749,"titles":1750,"content":1751,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#user-rights-gdpr","User Rights (GDPR)",[178],"Because Insights doesn't collect personal data: RightApplicabilityRight to accessNo personal data to accessRight to erasureNo personal data to eraseRight to portabilityNo personal data to exportRight to objectSupported via DNT header",{"id":1753,"title":1754,"titles":1755,"content":1756,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#legal-basis","Legal Basis",[178],"Since Insights: Collects no personal dataUses no cookiesPerforms no fingerprintingStores only aggregated statistics It typically falls outside GDPR scope for personal data processing. However, always consult with legal counsel for your specific situation.",{"id":1758,"title":1759,"titles":1760,"content":1761,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#comparison-with-other-tools","Comparison with Other Tools",[178],"FeatureInsightsPlausibleFathomGoogle AnalyticsCookiesNoneNoneNoneMultipleIP in hashYesYesYesN\u002FAIP storedNeverNeverNeverAnonymizedDaily saltYesYesYesNoData locationYour serverEU\u002FUSUSGoogleConsent requiredNoNoNoYesOpen sourceYesYesNoNo",{"id":1763,"title":1764,"titles":1765,"content":1766,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fprivacy#configuration-checklist","Configuration Checklist",[178],"For maximum privacy: return [\n    \u002F\u002F Respect browser privacy preferences\n    'respectDoNotTrack' => true,\n\n    \u002F\u002F Reasonable data retention\n    'dataRetentionDays' => 365,\n    'autoCleanup' => true,\n]; html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":183,"title":182,"titles":1768,"content":1769,"level":713},[],"Understand how every metric in Insights is calculated. This guide explains every metric you see in the Insights dashboard and how it's calculated.",{"id":1771,"title":1772,"titles":1773,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#key-metrics","Key Metrics",[182],{"id":1775,"title":1776,"titles":1777,"content":1778,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#pageviews","Pageviews",[182,1772],"Total number of page loads across your site. Pageviews = SUM(views) from all pages Every time a page loads and the tracking script fires, this counter increments by 1.",{"id":1780,"title":1781,"titles":1782,"content":1783,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#unique-visitors","Unique Visitors",[182,1772],"Number of distinct visitors based on daily visitor hashes. Unique Visitors = COUNT(DISTINCT visitorHash) from sessions A visitor is identified by a daily-rotating hash generated from: hash = SHA256(salt | date | ip | browser | language | screen) AttributeDescriptionsaltDaily random valuedateCurrent dateipIP address (never stored)browserBrowser family onlylanguagePrimary browser languagescreenScreen category (s\u002Fm\u002Fl) The same person visiting on different days counts as different visitors. See Privacy for full details.",{"id":1785,"title":1786,"titles":1787,"content":1788,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#bounce-rate","Bounce Rate",[182,1772],"Percentage of sessions where the visitor viewed only one page. Bounce Rate = (Sessions with 1 pageview \u002F Total sessions) × 100 A \"bounce\" is when someone visits one page and leaves without viewing another page. Lower is generally better, but depends on content type (blog posts naturally have higher bounce rates).",{"id":1790,"title":1791,"titles":1792,"content":1793,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#avg-time-on-page","Avg. Time on Page",[182,1772],"Average time visitors spend on pages, in seconds. Avg. Time = Total time on all pages \u002F Total pageviews Time is measured from page load until the user leaves (navigates away, closes tab, or switches tabs).",{"id":1795,"title":1796,"titles":1797,"content":1798,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#trend-percentages","Trend Percentages",[182,1772],"The percentage change compared to the previous period. Trend = ((Current value - Previous value) \u002F Previous value) × 100 For \"Last 7 Days\", the previous period is the 7 days before that. A positive trend (green) means growth, negative (red) means decline. If the previous period has zero data, the trend shows 0% instead of infinity.",{"id":1800,"title":1801,"titles":1802,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#referrers","Referrers",[182],{"id":1804,"title":1805,"titles":1806,"content":1807,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#visits","Visits",[182,1801],"Number of sessions that came from this referrer source.",{"id":1809,"title":1810,"titles":1811,"content":1812,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#referrer-types","Referrer Types",[182,1801],"TypeDefinitionDirectNo referrer - typed URL, bookmark, or app linkSearchGoogle, Bing, Yahoo, DuckDuckGo, Baidu, Yandex, EcosiaSocialFacebook, Twitter\u002FX, LinkedIn, Instagram, Pinterest, YouTube, TikTok, RedditReferralAny other external website",{"id":1814,"title":1815,"titles":1816,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#devices","Devices",[182],{"id":1818,"title":1819,"titles":1820,"content":1821,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#device-type","Device Type",[182,1815],"Classified from User-Agent based on device form factor: TypeDefinitionDesktopComputers and laptopsMobileSmartphonesTabletTablets like iPad, Android tablets",{"id":1823,"title":1824,"titles":1825,"content":1826,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#browser","Browser",[182,1815],"The browser family (Chrome, Firefox, Safari, Edge, etc.) extracted from User-Agent.",{"id":1828,"title":1829,"titles":1830,"content":1831,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#real-time-visitors","Real-time Visitors",[182],"Number of visitors currently active on your site. Active Visitors = COUNT(visitors) WHERE lastSeen >= (now - realtimeTtl) Default realtimeTtl is 300 seconds (5 minutes). A visitor is considered \"active\" if they've had any activity within this window.",{"id":1833,"title":1619,"titles":1834,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#campaign-tracking",[182],{"id":1836,"title":1805,"titles":1837,"content":1838,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#visits-1",[182,1619],"Number of sessions that arrived with these UTM parameters.",{"id":1840,"title":1841,"titles":1842,"content":1843,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#utm-parameters","UTM Parameters",[182,1619],"ParameterPurposeExampleutm_sourceTraffic sourcenewsletter, googleutm_mediumMarketing mediumemail, cpc, socialutm_campaignCampaign namespring_sale, product_launchutm_termPaid keywordsrunning shoesutm_contentAd variationbanner_a, text_link",{"id":1845,"title":1846,"titles":1847,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#countries","Countries",[182],{"id":1849,"title":1805,"titles":1850,"content":1851,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#visits-2",[182,1846],"Number of sessions from visitors in this country. Country is determined via GeoIP lookup from the visitor's IP address. The IP is immediately discarded after lookup, only the country code is stored.",{"id":1853,"title":194,"titles":1854,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#user-events",[182],{"id":1856,"title":1857,"titles":1858,"content":1859,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#count","Count",[182,194],"Total number of times this event was triggered.",{"id":1861,"title":1781,"titles":1862,"content":1863,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#unique-visitors-1",[182,194],"Number of distinct visitors who triggered this event.",{"id":1865,"title":1633,"titles":1866,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#outbound-links",[182],{"id":1868,"title":1869,"titles":1870,"content":1871,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#clicks","Clicks",[182,1633],"Total number of clicks on external links to this domain.",{"id":1873,"title":1781,"titles":1874,"content":1875,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#unique-visitors-2",[182,1633],"Number of distinct visitors who clicked links to this domain.",{"id":1877,"title":1638,"titles":1878,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#site-searches",[182],{"id":1880,"title":1881,"titles":1882,"content":1883,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#searches","Searches",[182,1638],"Number of times this search term was used.",{"id":1885,"title":1781,"titles":1886,"content":1887,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#unique-visitors-3",[182,1638],"Number of distinct visitors who searched for this term.",{"id":1889,"title":1643,"titles":1890,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#scroll-depth",[182],{"id":1892,"title":1893,"titles":1894,"content":1895,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#milestones","Milestones",[182,1643],"MilestoneMeaning25%Visitor scrolled past the first quarter50%Visitor reached mid-page75%Visitor showed deep engagement100%Visitor scrolled to the bottom Each milestone is counted once per pageview. If a user scrolls down to 75%, then back up, then down to 100%, both 75% and 100% are counted (but 75% only once).",{"id":1897,"title":1898,"titles":1899,"content":1900,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#average-scroll-depth","Average Scroll Depth",[182,1643],"Avg. Scroll Depth = (25% × count_25 + 50% × count_50 + 75% × count_75 + 100% × count_100) \u002F total_milestone_events This weighted average shows how far visitors typically scroll across your site.",{"id":1902,"title":1903,"titles":1904,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#session-insights","Session Insights",[182],{"id":1906,"title":1907,"titles":1908,"content":1909,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#pages-per-session","Pages per Session",[182,1903],"Pages per Session = AVG(pageCount) from all sessions Average number of pages viewed in a single session. Higher values indicate visitors are exploring more content.",{"id":1911,"title":1912,"titles":1913,"content":1914,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#entry-pages","Entry Pages",[182,1903],"The first page a visitor sees when starting a session. High-performing entry pages are good landing pages.",{"id":1916,"title":1917,"titles":1918,"content":1919,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#exit-pages","Exit Pages",[182,1903],"The last page a visitor sees before leaving. Pages with high exit rates might need improvement (or are natural endpoints like \"Thank You\" pages).",{"id":1921,"title":1922,"titles":1923,"content":1924,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#session-definition","Session Definition",[182,1903],"A session groups pageviews from the same visitor. A new session starts when: First visit - Visitor has no previous activityTimeout - More than 30 minutes since last pageview Session timeout = 30 minutes of inactivity",{"id":1926,"title":1927,"titles":1928,"content":1929,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fknowledge\u002Fhow-tracking-works#data-ranges","Data Ranges",[182],"Available date ranges and their definitions: RangePeriodTodayCurrent calendar day (midnight to now)Last 7 DaysToday + previous 6 daysLast 30 DaysToday + previous 29 daysLast 90 DaysToday + previous 89 daysLast 12 MonthsToday + previous 365 days Trend comparisons use the equivalent previous period (e.g., \"Last 7 Days\" compares to the 7 days before that).",{"id":191,"title":190,"titles":1931,"content":1932,"level":713},[],"Use Twig functions to add tracking to your templates.",{"id":1934,"title":1935,"titles":1936,"content":1937,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Ftwig-api#trackingscript","trackingScript()",[190],"Registers the tracking script via Craft's asset bundle system. {{ craft.insights.trackingScript() }} Technically it's not important where you add the script on your page as it always injects the script at the end of the body.",{"id":1939,"title":1940,"titles":1941,"content":1942,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Ftwig-api#trackingscriptinline","trackingScriptInline()",[190],"Outputs the tracking script as inline JavaScript. {{ craft.insights.trackingScriptInline()|raw }} Use this when asset bundles aren't available (e.g., in certain caching scenarios). html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":195,"title":194,"titles":1944,"content":1945,"level":713},[],"Track user events like button clicks, form submissions, and downloads. User events let you track specific user interactions beyond pageviews. Use them to measure conversions, engagement, and feature usage.",{"id":1947,"title":1948,"titles":1949,"content":1950,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fuser-events#data-attributes","Data Attributes",[194],"Track events declaratively using HTML data attributes: \u003C!-- Basic event -->\n\u003Cbutton data-insights-event=\"signup_clicked\">\n    Sign Up\n\u003C\u002Fbutton>\n\n\u003C!-- Event with category -->\n\u003Cbutton\n    data-insights-event=\"download_whitepaper\"\n    data-insights-category=\"conversion\"\n>\n    Download Whitepaper\n\u003C\u002Fbutton> When clicked, these elements automatically trigger the corresponding event. No JavaScript required.",{"id":1952,"title":1953,"titles":1954,"content":1955,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fuser-events#trackevent","trackEvent()",[194],"Track a custom event programmatically: window.insights.trackEvent(name, options) Parameters: ParameterTypeRequiredDescriptionnamestringYesEvent name (max 100 chars)options.categorystringNoEvent category (max 50 chars) Example: \u002F\u002F Track a newsletter signup\nwindow.insights.trackEvent('newsletter_signup', {\n    category: 'conversion'\n});\n\n\u002F\u002F Track a file download\nwindow.insights.trackEvent('download_pdf', {\n    category: 'engagement'\n});\n\n\u002F\u002F Track a button click\ndocument.querySelector('#cta-button').addEventListener('click', function() {\n    window.insights.trackEvent('cta_clicked');\n});",{"id":1957,"title":1958,"titles":1959,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fuser-events#best-practices","Best Practices",[194],{"id":1961,"title":1962,"titles":1963,"content":1964,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fuser-events#naming-conventions","Naming Conventions",[194,1958],"Use consistent, descriptive event names: \u002F\u002F Good - clear and consistent\nwindow.insights.trackEvent('form_submitted', { category: 'contact' });\nwindow.insights.trackEvent('video_played', { category: 'engagement' });\nwindow.insights.trackEvent('pricing_viewed', { category: 'conversion' });\n\n\u002F\u002F Avoid - vague or inconsistent\nwindow.insights.trackEvent('click');\nwindow.insights.trackEvent('btn1');",{"id":1966,"title":1967,"titles":1968,"content":1969,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fuser-events#categories","Categories",[194,1958],"Group related events with categories: CategoryUse ForconversionSignups, purchases, form submissionsengagementVideo plays, scroll depth, time on pagenavigationMenu clicks, search usageerrorForm validation errors, 404 pages",{"id":1971,"title":1972,"titles":1973,"content":1974,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fuser-events#form-tracking","Form Tracking",[194,1958],"Track form submissions: document.querySelector('form').addEventListener('submit', function(e) {\n    window.insights.trackEvent('form_submitted', {\n        category: 'conversion'\n    });\n});",{"id":1976,"title":1977,"titles":1978,"content":1979,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fuser-events#video-tracking","Video Tracking",[194,1958],"Track video engagement: const video = document.querySelector('video');\n\nvideo.addEventListener('play', function() {\n    window.insights.trackEvent('video_started', {\n        category: 'engagement'\n    });\n});\n\nvideo.addEventListener('ended', function() {\n    window.insights.trackEvent('video_completed', {\n        category: 'engagement'\n    });\n});",{"id":1981,"title":1982,"titles":1983,"content":1984,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fuser-events#viewing-events","Viewing Events",[194],"User events appear in: Dashboard - User Events card shows top eventsEvents Page - Full event list with filters html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}",{"id":200,"title":199,"titles":1986,"content":1987,"level":713},[],"Track clicks on external links to understand where users go after visiting your site. Outbound link tracking helps you understand which external resources your visitors find valuable and where they go when leaving your site.",{"id":1989,"title":1990,"titles":1991,"content":1992,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Foutbound-tracking#automatic-tracking","Automatic Tracking",[199],"External links are tracked automatically. When a user clicks a link to a different domain, Insights captures: Target URLTarget domainLink textSource page URL Example: \u003C!-- This click is automatically tracked -->\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fexample\u002Frepo\">View on GitHub\u003C\u002Fa>",{"id":1994,"title":1995,"titles":1996,"content":1997,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Foutbound-tracking#excluding-links","Excluding Links",[199],"Prevent tracking on specific links with the data-insights-no-track attribute: \u003C!-- This click will NOT be tracked -->\n\u003Ca href=\"https:\u002F\u002Fexample.com\" data-insights-no-track>\n    External Link\n\u003C\u002Fa> Use this for: Advertising links (to avoid inflating metrics)Partner links you don't want to trackNavigation to your own external properties",{"id":1999,"title":2000,"titles":2001,"content":2002,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Foutbound-tracking#manual-tracking","Manual Tracking",[199],"Track outbound clicks programmatically: window.insights.trackOutbound(url, text) Parameters: ParameterTypeRequiredDescriptionurlstringYesTarget URLtextstringNoLink text (max 255 chars) Example: \u002F\u002F Track a programmatic redirect\nwindow.insights.trackOutbound('https:\u002F\u002Fpartner.com\u002Foffer', 'Partner Offer');\nwindow.location.href = 'https:\u002F\u002Fpartner.com\u002Foffer';",{"id":2004,"title":2005,"titles":2006,"content":2007,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Foutbound-tracking#what-gets-tracked","What Gets Tracked",[199],"The automatic tracker captures clicks on \u003Ca> elements where: The href points to a different hostnameThe protocol is http: or https:The link doesn't have data-insights-no-track Tracked: \u003Ca href=\"https:\u002F\u002Fgithub.com\">GitHub\u003C\u002Fa>\n\u003Ca href=\"http:\u002F\u002Fexample.com\u002Fpage\">Example\u003C\u002Fa> Not tracked: \u003Ca href=\"\u002Flocal-page\">Internal Link\u003C\u002Fa>\n\u003Ca href=\"mailto:test@example.com\">Email\u003C\u002Fa>\n\u003Ca href=\"tel:+1234567890\">Phone\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fexternal.com\" data-insights-no-track>Excluded\u003C\u002Fa>",{"id":2009,"title":2010,"titles":2011,"content":2012,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Foutbound-tracking#viewing-outbound-data","Viewing Outbound Data",[199],"Outbound link data appears in: Dashboard - Outbound Links card shows top clicked domainsOutbound Page - Full list with URLs, domains, and click counts",{"id":2014,"title":2015,"titles":2016,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Foutbound-tracking#use-cases","Use Cases",[199],{"id":2018,"title":2019,"titles":2020,"content":2021,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Foutbound-tracking#identify-valuable-resources","Identify Valuable Resources",[199,2015],"See which external resources your visitors find most useful: Documentation linksPartner websitesSocial media profilesDownload sources",{"id":2023,"title":2024,"titles":2025,"content":2026,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Foutbound-tracking#optimize-affiliate-links","Optimize Affiliate Links",[199,2015],"Track affiliate link performance: \u003Ca href=\"https:\u002F\u002Faffiliate.com\u002Fproduct?ref=yoursite\"\n   data-insights-event=\"affiliate_click\"\n   data-insights-category=\"conversion\">\n    Buy Now\n\u003C\u002Fa> Combine with user events for detailed conversion tracking.",{"id":2028,"title":2029,"titles":2030,"content":2031,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Foutbound-tracking#monitor-exit-points","Monitor Exit Points",[199,2015],"Identify pages where users commonly leave your site to external destinations. html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}",{"id":204,"title":203,"titles":2033,"content":2034,"level":713},[],"Track site search queries to understand what visitors are looking for. Site search tracking reveals what your visitors are looking for, helping you improve content and navigation.",{"id":2036,"title":2037,"titles":2038,"content":2039,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#tracksearch","trackSearch()",[203],"Track search queries programmatically: window.insights.trackSearch(query, resultsCount) Parameters: ParameterTypeRequiredDescriptionquerystringYesSearch query (max 255 chars)resultsCountnumberNoNumber of results found Example: \u002F\u002F After performing a search\nconst query = searchInput.value;\nconst results = performSearch(query);\n\nwindow.insights.trackSearch(query, results.length);",{"id":2041,"title":2042,"titles":2043,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#integration-examples","Integration Examples",[203],{"id":2045,"title":2046,"titles":2047,"content":2048,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#basic-search-form","Basic Search Form",[203,2042],"document.querySelector('#search-form').addEventListener('submit', function(e) {\n    const query = document.querySelector('#search-input').value;\n\n    \u002F\u002F Track the search\n    window.insights.trackSearch(query);\n});",{"id":2050,"title":2051,"titles":2052,"content":2053,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#craft-search-integration","Craft Search Integration",[203,2042],"Track Craft's native search: {# In your search results template #}\n{% set query = craft.app.request.getParam('q') %}\n{% set results = craft.entries.search(query).all() %}\n\n\u003Cscript>\ndocument.addEventListener('DOMContentLoaded', function() {\n    window.insights.trackSearch(\n        {{ query|json_encode|raw }},\n        {{ results|length }}\n    );\n});\n\u003C\u002Fscript>",{"id":2055,"title":2056,"titles":2057,"content":2058,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#algolia-integration","Algolia Integration",[203,2042],"search.on('render', function() {\n    const query = search.helper.state.query;\n    const hits = search.helper.lastResults.nbHits;\n\n    if (query) {\n        window.insights.trackSearch(query, hits);\n    }\n});",{"id":2060,"title":2061,"titles":2062,"content":2063,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#viewing-search-data","Viewing Search Data",[203],"Search analytics appear in: Dashboard - Site Searches card shows popular queriesSearches Page - Full query list with search counts",{"id":2065,"title":2066,"titles":2067,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#insights-from-search-data","Insights from Search Data",[203],{"id":2069,"title":2070,"titles":2071,"content":2072,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#popular-searches","Popular Searches",[203,2066],"Identify what visitors search for most frequently: QuerySearchesResultspricing2453documentation18912api1568",{"id":2074,"title":2075,"titles":2076,"content":2077,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#zero-result-searches","Zero-Result Searches",[203,2066],"Queries with zero results indicate content gaps: QuerySearchesResultsrefund policy450enterprise320integrations280 Consider creating content for these topics.",{"id":2079,"title":1958,"titles":2080,"content":734,"level":719},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#best-practices",[203],{"id":2082,"title":2083,"titles":2084,"content":2085,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#normalize-queries","Normalize Queries",[203,1958],"Searches should automatically be trimmed. For additional normalization: function trackNormalizedSearch(query, results) {\n    \u002F\u002F Remove extra whitespace\n    const normalized = query.trim().replace(\u002F\\s+\u002Fg, ' ');\n\n    if (normalized) {\n        window.insights.trackSearch(normalized, results);\n    }\n}",{"id":2087,"title":2088,"titles":2089,"content":2090,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#debounce-instant-search","Debounce Instant Search",[203,1958],"For search-as-you-type interfaces, debounce tracking: let searchTimeout;\n\nsearchInput.addEventListener('input', function() {\n    clearTimeout(searchTimeout);\n\n    searchTimeout = setTimeout(function() {\n        const query = searchInput.value;\n        if (query.length >= 3) {\n            performSearch(query);\n            window.insights.trackSearch(query);\n        }\n    }, 500);\n});",{"id":2092,"title":2093,"titles":2094,"content":2095,"level":740},"\u002Flibraries\u002Fcraft-insights\u002Fusage\u002Fsearch-tracking#track-result-clicks","Track Result Clicks",[203,1958],"Combine search tracking with event tracking: function trackResultClick(query, resultUrl) {\n    window.insights.trackEvent('search_result_click', {\n        category: 'search'\n    });\n} html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":151,"title":150,"titles":2097,"content":2098,"level":713},[],"GDPR-compliant, privacy-first analytics for Craft CMS. Insights is a analytics plugin for Craft CMS. All data stays on your server, no third-party services, no cookie banners, fully GDPR-compliant out of the box.",{"id":2100,"title":2101,"titles":2102,"content":2103,"level":719},"\u002Flibraries\u002Fcraft-insights#why-insights","Why Insights?",[150],"InsightsGoogle AnalyticsGDPR-compliant without consent✅❌No cookie banners needed✅❌Data stays on your server✅❌No data shared with third parties✅❌Native Craft CMS integration✅❌Lightweight (~3KB, async)✅❌",{"id":2105,"title":1160,"titles":2106,"content":2107,"level":719},"\u002Flibraries\u002Fcraft-insights#how-it-works",[150],"Add the tracking script to your templatesView your dashboard in the Craft control panel {{ craft.insights.trackingScript() }} That's it. Insights automatically tracks pageviews, referrers, and devices. No configuration required.",{"id":2109,"title":2110,"titles":2111,"content":2112,"level":719},"\u002Flibraries\u002Fcraft-insights#privacy-by-design","Privacy by Design",[150],"Insights doesn't collect personal data: No cookies - Nothing stored on the user's deviceNo fingerprinting - Uses daily-rotating visitor hashesNo IP storage - IPs are used for GeoIP lookup, then immediately discardedAggregated data only - Raw events are never stored This means no consent banners, no privacy policy updates, and no GDPR headaches.",{"id":2114,"title":2115,"titles":2116,"content":2117,"level":719},"\u002Flibraries\u002Fcraft-insights#lite-vs-pro","Lite vs Pro",[150],"Lite covers the essentials-pageviews, referrers, devices, and real-time visitors. Perfect for blogs and smaller sites. Pro adds marketing features: campaign tracking (UTM), country stats, user events, scroll depth, session insights, and more. Built for teams that need deeper insights. FeatureLiteProKey Metrics✅✅Referrer Analysis✅✅Real-time Visitors✅✅Device Breakdown✅✅Entry Sidebar✅✅Data Export (CSV)✅✅Widgets✅✅Custom Queue✅✅Country Tracking❌✅User Events❌✅Scroll Depth Tracking❌✅Session Insights❌✅Entry & Exit Pages❌✅Outbound Link Tracking❌✅Campaign Tracking (UTM)❌✅Site Search Analytics❌✅Custom Database❌✅",{"id":2119,"title":1178,"titles":2120,"content":2121,"level":719},"\u002Flibraries\u002Fcraft-insights#getting-started",[150],"Install via Composer or the Craft Plugin Store.Customize tracking behavior and privacy settings. html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":216,"title":20,"titles":2123,"content":2124,"level":713},[],"Learn how to install and set up the LLMify Craft CMS plugin.",{"id":2126,"title":716,"titles":2127,"content":1187,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Finstallation#requirements",[20],{"id":2129,"title":2130,"titles":2131,"content":2132,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Finstallation#ai-assisted-setup","AI-Assisted Setup",[20],"If you use Claude Code or other AI tools, LLMify ships with a built-in setup skill. To use it paste this markdown into .claude\u002Fskills\u002Finstall-llmify\u002FSKILL.md. ---\nname: install-llmify\ndescription: Install and configure the LLMify Craft CMS plugin step by step\n---\n\n# Install and Configure LLMify for Craft CMS\n\nThis guide tells an AI agent how to install and set up the LLMify plugin in a Craft CMS 5 project.\n\n## Step 1: Install the Plugin\n\nRun the following commands in the Craft project root:\n\n```bash\ncomposer require samuelreichor\u002Fcraft-llmify\nphp craft plugin\u002Finstall llmify\n```\n\nIf the project uses DDEV:\n\n```bash\nddev composer require samuelreichor\u002Fcraft-llmify\nddev craft plugin\u002Finstall llmify\n```\n\n## Step 2: Enable Sections\n\n1. In the Craft control panel, go to **LLMify → Content**.\n2. Enable each section that should produce markdown output using the **Enable for Section** toggle.\n3. Set an **LLM Title** and **LLM Description** for each enabled section — these populate the `llms.txt` file.\n\n## Step 3: Add Template Tags\n\nWrap the content you want converted to markdown with the `{% llmify %}` tag in your Twig templates:\n\n```twig\n{% llmify %}\n  \u003Ch1>{{ entry.title }}\u003C\u002Fh1>\n  \u003Cdiv>{{ entry.bodyContent }}\u003C\u002Fdiv>\n{% endllmify %}\n```\n\nMultiple `{% llmify %}` blocks per template are supported — their content is merged into a single markdown file.\n\nTo exclude specific parts within an llmify block:\n\n```twig\n{% llmify %}\n  \u003Ch1>{{ entry.title }}\u003C\u002Fh1>\n  {% excludellmify %}\n    \u003Cnav>...\u003C\u002Fnav>\n  {% endexcludellmify %}\n  \u003Cdiv>{{ entry.bodyContent }}\u003C\u002Fdiv>\n{% endllmify %}\n```\n\nYou can also exclude content by adding the `exclude-llmify` CSS class to any HTML element. This class name is configurable via the config file.\n\n## Step 4: Generate Markdown\n\nGenerate markdown for all enabled entries using one of these methods:\n\n- **Control Panel**: Go to **Utilities → LLMify** and trigger generation.\n- **Entry Sidebar**: Generate markdown for a single entry from its edit page.\n- **Console Command**:\n  ```bash\n  php craft llmify\u002Fmarkdown\u002Fgenerate\n  ```\n\nTo clear all generated markdown and start fresh:\n\n```bash\nphp craft llmify\u002Fmarkdown\u002Fclear\n```\n\n## Step 5: Check the Dashboard\n\nGo to **LLMify → Dashboard** to see an overview of your setup:\n\n- **Site setup score** — shows how complete your site-level configuration is (LLM title, description, note, front matter fields).\n- **Section statistics** — content-level stats per section showing how many entries have markdown generated.\n\n## Step 6: Verify the Output\n\nAfter generating markdown, verify these URLs are accessible:\n\n- `\u002Fllms.txt` — Summary file listing all enabled entries\n- `\u002Fllms-full.txt` — Full content of all entries\n- `\u002F.well-known\u002Fllms.txt` — RFC 8615 compliant discovery endpoint\n- `\u002Fraw\u002F{entry-uri}.md` — Individual markdown page (if `markdownUrlPrefix` is set)\n\nTest auto-serve markdown with:\n\n```bash\ncurl -H \"Accept: text\u002Fmarkdown\" https:\u002F\u002Fyour-site.com\u002Fyour-entry-url\n```\n\n## Full Documentation\n\nFor detailed configuration options and advanced usage, see the [LLMify documentation](https:\u002F\u002Fsamuelreichor.at\u002Flibraries\u002Fcraft-llmify). Then just run \u002Finstall-llmify in your Craft project directory and the assistant will do the development setup for you. You just need to adjust the content settings for your needs.",{"id":2134,"title":722,"titles":2135,"content":2136,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Finstallation#craft-plugin-store",[20],"To install LLMify, go to the Plugin Store in your Craft control panel, search for \"LLMify,\" and click the Install button.",{"id":2138,"title":727,"titles":2139,"content":2140,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Finstallation#composer",[20],"ddev composer require samuelreichor\u002Fcraft-llmify &&\nddev craft plugin\u002Finstall llmify\ncomposer require samuelreichor\u002Fcraft-llmify &&\nphp craft plugin\u002Finstall llmify",{"id":2142,"title":732,"titles":2143,"content":2144,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Finstallation#setup",[20],"Enable SectionsIn the Craft control panel, go to LLMify > Content and enable each section that should produce Markdown output using the Enable for Section toggle.Set an LLM Title and LLM Description for each enabled section, these populate the llms.txt file.Learn more about Content Settings in the Basic Overview.Add Template TagsWrap the content you want converted to Markdown with the {% llmify %} tag in your Twig templates:{% llmify %}\n  \u003Ch1>{{ entry.title }}\u003C\u002Fh1>\n  \u003Cdiv>{{ entry.bodyContent }}\u003C\u002Fdiv>\n{% endllmify %}\nMultiple {% llmify %} blocks per template are supported, their content is merged into a single Markdown file.Learn more about template tags and other content control options on the Content Control page.Generate MarkdownGenerate Markdown for all enabled entries using one of these methods:Control Panel: Go to Utilities > LLMify and trigger generation.Entry Sidebar: Use the Update button to generate Markdown for a single entry.Console Command:\nphp craft llmify\u002Fmarkdown\u002Fgenerate\nVerify the OutputAfter generating, these URLs should be accessible on your site:\u002Fllms.txt and \u002F.well-known\u002Fllms.txt: list of all URLs with descriptions\u002Fllms-full.txt: full Markdown content of all entries\u002Fraw\u002F{your-uri}.md: Markdown for a single entryYou can also test auto-serve and bot detection:curl -H \"Accept: text\u002Fmarkdown\" https:\u002F\u002Fyour-site.com\u002Fyour-entry-url\ncurl -A \"GPTBot\u002F1.0\" https:\u002F\u002Fyour-site.com\u002Fyour-entry-url You're all set. Head over to the Basic Overview to learn about the Dashboard, Permissions, and other features.",{"id":2146,"title":753,"titles":2147,"content":2148,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Finstallation#support",[20],"If you encounter bugs or have feature requests, please submit an issue. Your feedback helps improve the plugin! html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .s1c8L, html code.shiki .s1c8L{--shiki-light:#005CC5;--shiki-light-font-weight:bold;--shiki-default:#79B8FF;--shiki-default-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .sQELQ, html code.shiki .sQELQ{--shiki-light:#24292E;--shiki-light-font-weight:bold;--shiki-default:#E1E4E8;--shiki-default-font-weight:bold;--shiki-dark:#E1E4E8;--shiki-dark-font-weight:bold}html pre.shiki code .sg6f7, html code.shiki .sg6f7{--shiki-light:#032F62;--shiki-light-text-decoration:underline;--shiki-default:#DBEDFF;--shiki-default-text-decoration:underline;--shiki-dark:#DBEDFF;--shiki-dark-text-decoration:underline}html pre.shiki code .sXueF, html code.shiki .sXueF{--shiki-light:#24292E;--shiki-light-text-decoration:underline;--shiki-default:#E1E4E8;--shiki-default-text-decoration:underline;--shiki-dark:#E1E4E8;--shiki-dark-text-decoration:underline}",{"id":219,"title":29,"titles":2150,"content":2151,"level":713},[],"Learn about all available configuration options for the LLMify plugin.",{"id":2153,"title":808,"titles":2154,"content":2155,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#control-panel",[29],"You can manage configuration settings through the Control Panel by visiting Settings > LLMify.",{"id":2157,"title":308,"titles":2158,"content":2159,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#settings",[29],"You can define a multi-environment aware config in \u002Fconfig\u002Fllmify.php. Settings defined in the config file override control panel settings. Config file settings will overwrite the settings from the control panel.",{"id":2161,"title":2162,"titles":2163,"content":2164,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#isenabled","isEnabled",[29,308],"Master toggle for Markdown creation. When disabled, no Markdown will be generated or served. return [\n    '*' => [\n        'isEnabled' => true, \u002F\u002F default\n    ],\n];",{"id":2166,"title":2167,"titles":2168,"content":2169,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#autoservemarkdown","autoServeMarkdown",[29,308],"Automatically serve Markdown instead of HTML when the request contains an Accept: text\u002Fmarkdown header. return [\n    '*' => [\n        'autoServeMarkdown' => true, \u002F\u002F default\n    ],\n];",{"id":2171,"title":2172,"titles":2173,"content":2174,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#enablebotdetection","enableBotDetection",[29,308],"Detect known AI bots (GPTBot, ClaudeBot, ChatGPT-User, etc.) by their user agent and automatically serve Markdown to them. See Auto-Serve Markdown for the full list of detected bots. return [\n    '*' => [\n        'enableBotDetection' => true, \u002F\u002F default\n    ],\n];",{"id":2176,"title":2177,"titles":2178,"content":2179,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#additionalbotuseragents","additionalBotUserAgents",[29,308],"Add custom bot user agents to detect in addition to the built-in list. return [\n    '*' => [\n        'additionalBotUserAgents' => [\n            ['userAgent' => 'MyCustomBot'],\n            ['userAgent' => 'AnotherBot'],\n        ],\n    ],\n];",{"id":2181,"title":2182,"titles":2183,"content":2184,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#autoinjectdiscoverytag","autoInjectDiscoveryTag",[29,308],"Inject a \u003Clink rel=\"alternate\" type=\"text\u002Fmarkdown\"> discovery tag into the HTML head for every page that has Markdown available. return [\n    '*' => [\n        'autoInjectDiscoveryTag' => true, \u002F\u002F default\n    ],\n];",{"id":2186,"title":2187,"titles":2188,"content":2189,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#isrealurlllm","isRealUrlLlm",[29,308],"Whether to use real page URLs or Markdown URLs in the llms.txt file. Recommended to enable together with autoServeMarkdown. return [\n    '*' => [\n        'isRealUrlLlm' => false, \u002F\u002F default\n    ],\n];",{"id":2191,"title":2192,"titles":2193,"content":2194,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#markdownurlprefix","markdownUrlPrefix",[29,308],"URL prefix for individual Markdown pages (e.g. https:\u002F\u002Fexample.com\u002Fraw\u002Fabout.md). Leave empty to use {url}.md URLs directly. return [\n    '*' => [\n        'markdownUrlPrefix' => 'raw', \u002F\u002F default\n    ],\n];",{"id":2196,"title":2197,"titles":2198,"content":2199,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#excludeclasses","excludeClasses",[29,308],"CSS classes that should be excluded from the Markdown generation. Elements with these classes will be stripped before conversion. return [\n    '*' => [\n        'excludeClasses' => [\n            ['classes' => 'exclude-llmify'], \u002F\u002F default\n        ],\n    ],\n];",{"id":2201,"title":2202,"titles":2203,"content":2204,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#markdownconfig","markdownConfig",[29,308],"Configuration passed to the HTML-to-Markdown converter. See the library docs for all available options. return [\n    '*' => [\n        'markdownConfig' => [\n            'strip_tags' => true,\n            'header_style' => 'atx',\n            'remove_nodes' => 'img picture style form button input select option svg script nav noscript video audio source',\n        ], \u002F\u002F default\n    ],\n];",{"id":2206,"title":2207,"titles":2208,"content":2209,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#concurrentrequests","concurrentRequests",[29,308],"Maximum number of concurrent HTTP requests when batch generating Markdown. Valid range: 1–100. return [\n    '*' => [\n        'concurrentRequests' => 3, \u002F\u002F default\n    ],\n];",{"id":2211,"title":2212,"titles":2213,"content":2214,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#requesttimeout","requestTimeout",[29,308],"Maximum number of seconds each request can take during batch generation. return [\n    '*' => [\n        'requestTimeout' => 100, \u002F\u002F default\n    ],\n];",{"id":2216,"title":2217,"titles":2218,"content":2219,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#frontmatterinfulltxt","frontMatterInFullTxt",[29,308],"Whether front matter should be included for each page in llms-full.txt. return [\n    '*' => [\n        'frontMatterInFullTxt' => false, \u002F\u002F default\n    ],\n];",{"id":2221,"title":907,"titles":2222,"content":2223,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fget-started\u002Fconfig#multi-environment-example",[29],"A complete example showing environment-specific configuration: \u003C?php\n\u002F\u002F config\u002Fllmify.php\n\nreturn [\n    '*' => [\n        'isEnabled' => true,\n        'autoServeMarkdown' => true,\n        'enableBotDetection' => true,\n        'autoInjectDiscoveryTag' => true,\n        'isRealUrlLlm' => true,\n        'markdownUrlPrefix' => 'raw',\n        'concurrentRequests' => 5,\n        'requestTimeout' => 120,\n    ],\n    'dev' => [\n        'isEnabled' => false,\n    ],\n    'production' => [\n        'concurrentRequests' => 10,\n    ],\n]; html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":227,"title":226,"titles":2225,"content":2226,"level":713},[],"Here you can find a basic overview of all core parts of the LLMify plugin",{"id":2228,"title":1599,"titles":2229,"content":2230,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fbasic-overview#dashboard",[226],"The Dashboard gives you an overview of your LLMify setup. It shows a setup score for the current site and section-level content statistics, so you can quickly see which sections are configured and how many entries have been processed.",{"id":2232,"title":2233,"titles":2234,"content":2235,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fbasic-overview#site-settings","Site Settings",[226],"Site Settings is where you set default site-wide settings, on a per-site basis. This includes enabling or disabling LLMify for the site, setting the site title and description for llms.txt, and configuring default front matter fields that are inherited by all sections.",{"id":2237,"title":2238,"titles":2239,"content":2240,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fbasic-overview#content-settings","Content Settings",[226],"Content Settings is where you can set default content settings, on a per-section basis. The list of these content types includes status indicators identifying what's been configured for each one. It is important to set LLM Title and Description for each content type, as they are used in the llms.txt file to provide context for the LLMs. Content Settings also lets you override the site-level front matter fields for a specific section.",{"id":2242,"title":2243,"titles":2244,"content":2245,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fbasic-overview#entry-settings","Entry Settings",[226],"LLMify has an LLMify Settings Field that you can add to your Entry Types. You can use this field to override the content settings for each entry, including title source, description source, and front matter fields. You can also exclude individual entries from Markdown generation entirely.",{"id":2247,"title":2248,"titles":2249,"content":2250,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fbasic-overview#settings-inheritance","Settings Inheritance",[226,2243],"Settings follow a hierarchical inheritance model: Site > Section > Entry. Each level inherits from the one above and can optionally override specific values. For example, front matter fields defined at the site level are inherited by all sections, but a section can override them, and an individual entry can override the section settings.",{"id":2252,"title":2253,"titles":2254,"content":2255,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fbasic-overview#sidebar-panel","Sidebar Panel",[226,2243],"The sidebar panel on entry and product edit pages shows the current LLMify status for that element: If Markdown has been generated, it shows a link to the generated file and the last update timestamp.If LLMify is disabled at the site, section, or entry level, it shows which setting is responsible with a direct link to the relevant settings page.The Update and Clear buttons let you regenerate or remove Markdown for individual entries. Button visibility depends on user permissions. Users need the \"Generate Markdown\" and \"Clear Markdown\" permissions respectively.",{"id":2257,"title":2258,"titles":2259,"content":2260,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fbasic-overview#preview-targets","Preview Targets",[226,2243],"LLMify registers Markdown preview targets for entries and products. This allows content authors to preview the Markdown output directly from the entry editor using Craft's built-in preview system.",{"id":2262,"title":2263,"titles":2264,"content":2265,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fbasic-overview#llmify-utility","LLMify Utility",[226],"The LLMify Utility allows you to manage the Markdown generation process. You can access it in the Craft CMS control panel under Utilities. You can use this to manually trigger the Markdown generation process for all entries that are enabled for Markdown generation and have the llmify tag in their templates.",{"id":2267,"title":51,"titles":2268,"content":2269,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fbasic-overview#permissions",[226],"LLMify provides granular user permissions (available with Craft Pro): PermissionDescriptionView DashboardAccess the LLMify dashboardEdit Content SettingsManage per-section content settingsEdit Site SettingsManage per-site settingsGenerate MarkdownTrigger Markdown generation via the sidebar panel or utilityClear MarkdownClear generated Markdown via the sidebar panel or utilityView Sidebar PanelSee the LLMify sidebar panel on entry and product edit pages You can assign these permissions to user groups under Settings > Users > User Groups in the Craft control panel.",{"id":231,"title":230,"titles":2271,"content":2272,"level":713},[],"Learn how to control the markdown files. LLMify gives you multiple ways to control what ends up in your Markdown output: Twig template tags, CSS class exclusion, and per-entry settings via the LLMify Settings Field.",{"id":2274,"title":2275,"titles":2276,"content":2277,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fcontent-control#template-tags","Template Tags",[230],"To select content for Markdown generation, you can use the llmify and excludeLlmify tags in your templates.\nThese tags allow you to specify which parts of your content should be converted to Markdown and which parts should be excluded.",{"id":2279,"title":2280,"titles":2281,"content":2282,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fcontent-control#llmify","llmify",[230],"The body of llmify tags will be converted to markdown. You can use multiple llmify tags in your templates. They get merged together and the result is saved as a markdown file. {% llmify %}\n    \u003Ch1>My Title\u003C\u002Fh1>\n    \u003Cp>My content\u003C\u002Fp>\n{% endllmify %}\n\n{% llmify %}\n    \u003Cp>More content\u003C\u002Fp>\n{% endllmify %} This will result in a markdown file that looks like this: # My Title\nMy content\nMore content",{"id":2284,"title":2285,"titles":2286,"content":2287,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fcontent-control#excludellmify","excludeLlmify",[230],"In cases where you want to exclude certain content from being converted to markdown, you can use the excludeLlmify tag. This is useful for content that should not be part of the markdown generation. {% llmify %}\n    \u003Ch1>My Title\u003C\u002Fh1>\n    \u003Cp>My content\u003C\u002Fp>\n    {% excludeLlmify %}\n        \u003Cp>This content will not be included in the markdown file.\u003C\u002Fp>\n    {% endexcludeLlmify %}\n{% endllmify %} This will result in a markdown file that looks like this: # My Title\nMy content",{"id":2289,"title":2290,"titles":2291,"content":2292,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fcontent-control#exclude-by-class","Exclude by Class",[230],"If you need even more control about what gets included in the markdown generation, you can use the exclude-llmify class on any HTML.\nIf this class conflicts or you have multiple classes that should be excluded, you can configure them in the llmify.php config file. {% llmify %}\n    \u003Ch1>My Title\u003C\u002Fh1>\n    \u003Cp>My content\u003C\u002Fp>\n    \u003Cp class=\"exclude-llmify\">This content will not be included in the markdown file.\u003C\u002Fp>\n{% endllmify %} This will result in a markdown file that looks like this: # My Title\nMy content",{"id":2294,"title":2295,"titles":2296,"content":2297,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fcontent-control#per-entry-control","Per-Entry Control",[230],"The LLMify Settings Field is a custom Craft field that you can add to any Entry Type or Product Type. It provides per-entry control over: Include\u002FExclude: Toggle whether an individual entry is included in Markdown generation, llms.txt, and llms-full.txt.Title Override: Override the section-level title source with a custom field or static text.Description Override: Override the section-level description source with a custom field or static text.Front Matter Override: Override the inherited front matter fields for this specific entry. To use it, create a new field of type \"LLMify Settings\" in Settings > Fields, and add it to the field layout of your Entry Type.",{"id":2299,"title":2300,"titles":2301,"content":734,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fcontent-control#troubleshooting","Troubleshooting",[230],{"id":2303,"title":2304,"titles":2305,"content":2306,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fcontent-control#empty-markdown","Empty Markdown",[230,2300],"If your Markdown is generated but empty, it usually means the {% llmify %} tags are missing from your template, or they don't wrap any content.\nMake sure your entry template includes at least one {% llmify %} block around the content you want to convert. The sidebar panel in the entry editor will show a warning if Markdown is empty or the entry is deactivated for llmify through settings. html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s1c8L, html code.shiki .s1c8L{--shiki-light:#005CC5;--shiki-light-font-weight:bold;--shiki-default:#79B8FF;--shiki-default-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}",{"id":235,"title":234,"titles":2308,"content":2309,"level":713},[],"Learn how LLMify delivers Markdown to AI agents via content negotiation, bot detection, and discovery tags. LLMify provides two ways to automatically serve Markdown instead of HTML: Content Negotiation (autoServeMarkdown): Serves Markdown when a request contains an Accept: text\u002Fmarkdown header.AI Bot Detection (enableBotDetection): Automatically detects known AI crawlers by their user agent and serves Markdown to them. Both features are enabled by default and can be used independently or together.",{"id":2311,"title":2312,"titles":2313,"content":2314,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fauto-serve#content-negotiation","Content Negotiation",[234],"When autoServeMarkdown is enabled, LLMify uses content negotiation to serve Markdown instead of HTML. If a request contains an Accept: text\u002Fmarkdown header, the same URL that normally returns HTML will return clean Markdown instead. This approach is inspired by Cloudflare's Markdown for Agents. It allows AI agents to request your existing page URLs and receive structured Markdown without needing separate \u002Fraw\u002F\u003Cslug>.md endpoints. This works well in combination with the isRealUrlLlm setting. When both are enabled, llms.txt will point to your real page URLs, and AI agents can request those URLs with the Accept: text\u002Fmarkdown header to get the Markdown version.",{"id":2316,"title":2317,"titles":2318,"content":2319,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fauto-serve#ai-bot-detection","AI Bot Detection",[234],"When enableBotDetection is enabled, LLMify detects known AI crawlers by their user agent and automatically serves Markdown to them. The following bots are detected by default: GPTBot, ChatGPT-User, OAI-SearchBot, ClaudeBot, Claude-Web, Amazonbot, Bytespider, CCBot, Google-Extended, FacebookBot, PerplexityBot, Applebot-Extended, cohere-ai You can add custom bot user agents via the additionalBotUserAgents config option.",{"id":2321,"title":2322,"titles":2323,"content":2324,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fauto-serve#discovery-tag","Discovery Tag",[234],"When autoInjectDiscoveryTag is enabled (default), LLMify injects a \u003Clink> tag into the HTML head of every page that has Markdown available: \u003Clink rel=\"alternate\" type=\"text\u002Fmarkdown\" href=\"https:\u002F\u002Fyour-site.com\u002Fraw\u002Fabout.md\"> This allows AI agents to discover the Markdown version of a page without needing to know about content negotiation.",{"id":2326,"title":1160,"titles":2327,"content":2328,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fauto-serve#how-it-works",[234],"When a request hits a page: LLMify checks if the request has an Accept: text\u002Fmarkdown header or if the user agent matches a known AI bot.If either condition is met, it looks up the pre-generated Markdown for the requested entry.If no pre-generated version exists, it generates the Markdown on-the-fly from the template output.The response is returned with the appropriate headers.",{"id":2330,"title":2331,"titles":2332,"content":2333,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fauto-serve#response-headers","Response Headers",[234,1160],"All Markdown responses include the following headers: HeaderValuePurposeContent-Typetext\u002Fmarkdown; charset=utf-8Identifies the response as MarkdownVaryAccept (or Accept, User-Agent for bot detection)Tells CDNs to cache HTML and Markdown separatelyX-Robots-Tagnoindex, nofollowPrevents search engines from indexing Markdown responsesLink\u003Coriginal-url>; rel=\"canonical\"Points back to the original HTML page",{"id":2335,"title":2336,"titles":2337,"content":2338,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fauto-serve#testing","Testing",[234],"You can test both auto-serve methods with curl: curl -H \"Accept: text\u002Fmarkdown\" https:\u002F\u002Fyour-site.com\u002Fabout\ncurl -A \"GPTBot\u002F1.0\" https:\u002F\u002Fyour-site.com\u002Fabout\ncurl -v -H \"Accept: text\u002Fmarkdown\" https:\u002F\u002Fyour-site.com\u002Fabout 2>&1 | grep \"\u003C \"",{"id":2340,"title":2341,"titles":2342,"content":2343,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fauto-serve#blitz-integration","Blitz Integration",[234],"LLMify works with Blitz out of the box when using the default Blitz caching strategy. LLMify automatically tells Blitz to skip its cache for Accept: text\u002Fmarkdown requests, so the request is passed through to PHP where LLMify can handle it.",{"id":2345,"title":2346,"titles":2347,"content":2348,"level":740},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fauto-serve#blitz-with-server-rewrites","Blitz with Server Rewrites",[234,2341],"If you use Blitz with Nginx server rewrites, Nginx serves cached pages directly from the file system without ever hitting PHP. In this case, LLMify cannot intercept the request. To fix this, add a condition to your Nginx config that skips the Blitz cache when the Accept header contains text\u002Fmarkdown: set $cache_path false;\nif ($request_method = GET) {\n    set $cache_path \u002Fcache\u002Fblitz\u002F$host\u002F$uri\u002Findex.html;\n}\nif ($args ~ \"token=\") {\n    set $cache_path false;\n}\n# Skip Blitz cache for text\u002Fmarkdown requests (LLMify auto-serve)\nif ($http_accept ~ \"text\u002Fmarkdown\") {\n    set $cache_path false;\n}\n\nlocation \u002F {\n    try_files $cache_path $uri $uri\u002F \u002Findex.php?$query_string;\n} html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"id":239,"title":238,"titles":2350,"content":2351,"level":713},[],"Learn about the console commands available in the LLMify Craft CMS plugin. As of now the LLMify plugin provides two console commands to manage the markdown generation process. You can run these commands in CI\u002FCD pipelines or as cron jobs to automate the markdown generation process.",{"id":2353,"title":2354,"titles":2355,"content":2356,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fconsole-commands#craft-llmifymarkdowngenerate","craft llmify\u002Fmarkdown\u002Fgenerate",[238],"This will generate the markdown files for all entries that are enabled for markdown generation and have the llmify tag in their templates. php craft llmify\u002Fmarkdown\u002Fgenerate",{"id":2358,"title":2359,"titles":2360,"content":2361,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fconsole-commands#craft-llmifymarkdownclear","craft llmify\u002Fmarkdown\u002Fclear",[238],"This will clear all generated markdown files. This is useful if you want to regenerate the markdown files from scratch. php craft llmify\u002Fmarkdown\u002Fclear",{"id":2363,"title":2364,"titles":2365,"content":2366,"level":719},"\u002Flibraries\u002Fcraft-llmify\u002Fusage\u002Fconsole-commands#cron-jobs","Cron Jobs",[238],"You can set up cron jobs to automate the Markdown generation process: # Generate markdown files for all entries every day at midnight\n0 0 * * * php \u002Fpath\u002Fto\u002Fcraft llmify\u002Fmarkdown\u002Fgenerate html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}",{"id":208,"title":207,"titles":2368,"content":2369,"level":713},[],"LLMify makes your Craft CMS content instantly AI-ready. AI models like ChatGPT struggle to read websites built for people. They see a wall of code, menus, ads, and sidebars. This \"noise\" makes it hard for them to find the real story - your valuable story.\nLLMify solves this by converting your Twig templates into clean, structured Markdown. If you want to learn more about the broader landscape of Generative Engine Optimization, check out my blog post: Current State of GEO.",{"id":2371,"title":2372,"titles":2373,"content":2374,"level":719},"\u002Flibraries\u002Fcraft-llmify#why-llmify","Why LLMify?",[207],"LLMify is built for production-scale AI content delivery.\nInstead of converting HTML to Markdown on every request, LLMify does the work upfront. Your Markdown is stored and ready before any bot shows up.\nCombined with Craft Commerce compatibility, granular control over your Markdowns and user permissions, LLMify gives you everything you need to make your entire site AI-ready.",{"id":2376,"title":1168,"titles":2377,"content":734,"level":719},"\u002Flibraries\u002Fcraft-llmify#features",[207],{"id":2379,"title":2380,"titles":2381,"content":2382,"level":740},"\u002Flibraries\u002Fcraft-llmify#content-generation","Content Generation",[207,1168],"Pre-Generated Markdown: Async batch processing stores Markdown in a dedicated database table for instant delivery at any scale.On-Demand Fallback: Automatically generates Markdown on first request if not yet pre-generated.Template-Level Control: Use {% llmify %} and {% excludellmify %} Twig tags for precise control over what content is included.CSS Class Exclusion: Define classes to exclude entire sections from the HTML-to-Markdown conversion.YAML Front Matter: Configurable metadata with hierarchical inheritance (Site > Section > Entry).Console Commands: llmify\u002Fmarkdown\u002Fgenerate and llmify\u002Fmarkdown\u002Fclear for CI\u002FCD and deployment workflows.",{"id":2384,"title":2385,"titles":2386,"content":2387,"level":740},"\u002Flibraries\u002Fcraft-llmify#ai-content-delivery","AI Content Delivery",[207,1168],"Auto-Serve Markdown: Content negotiation via Accept: text\u002Fmarkdown header.AI Crawler Detection: Automatically serve Markdown to known AI bots (GPTBot, ClaudeBot, ChatGPT-User, and more).LLM-Ready Text Files: Generates llms.txt, llms-full.txt, and \u002F.well-known\u002Fllms.txt.Discovery Tag: Injects \u003Clink rel=\"alternate\" type=\"text\u002Fmarkdown\"> into your HTML head.Industry Standard Response Headers: Sets Vary: Accept, X-Robots-Tag: noindex, nofollow, and Link: rel=\"canonical\" on all Markdown responses.",{"id":2389,"title":2390,"titles":2391,"content":2392,"level":740},"\u002Flibraries\u002Fcraft-llmify#content-management","Content Management",[207,1168],"Hierarchical Settings: Site-wide, section, and entry-level configuration with inheritance.Per-Entry Control: Include or exclude individual entries via the LLMify Settings Field.Permission System: Granular user permissions for dashboard, content settings, site settings, generate, and clear actions.Preview Targets: Preview Markdown output directly from the entry editor.Dashboard: Site setup scores and section-level content statistics at a glance.",{"id":2394,"title":59,"titles":2395,"content":2396,"level":740},"\u002Flibraries\u002Fcraft-llmify#integrations",[207,1168],"SEOmatic Integration: Automatically populate front matter from SEOmatic fields.Craft Commerce Support: Full support for Commerce Products alongside Entries.",{"id":2398,"title":2399,"titles":2400,"content":734,"level":719},"\u002Flibraries\u002Fcraft-llmify#why-it-matters","Why it Matters",[207],{"id":2402,"title":2403,"titles":2404,"content":2405,"level":740},"\u002Flibraries\u002Fcraft-llmify#future-proof-your-site","Future-Proof Your Site",[207,2399],"The way we find information is changing. Search is evolving from a list of links into a direct conversation with AI.\nBy making your content perfectly readable for machines, you ensure your website remains a trusted, primary source for these new systems.\nYou're not just optimizing for today; you're securing your relevance for tomorrow's web.",{"id":2407,"title":2408,"titles":2409,"content":2410,"level":740},"\u002Flibraries\u002Fcraft-llmify#improve-ai-accuracy","Improve AI Accuracy",[207,2399],"AI models are powerful, but they're only as good as the data they read. When they parse messy HTML, they have to guess what's important, often leading to incorrect summaries and unreliable answers.\nBy feeding them clean, structured content, you eliminate the guesswork. This ensures that when an AI references your site, it represents your brand and information with the accuracy you can trust.",{"id":2412,"title":2413,"titles":2414,"content":2415,"level":740},"\u002Flibraries\u002Fcraft-llmify#gain-a-competitive-edge","Gain a Competitive Edge",[207,2399],"Right now, most websites are only built for human eyes. This gives you a massive opportunity. By making your site \"bilingual\"—fluent in both human-centric design and machine-readable text—you put yourself\nfar ahead of the competition. While their content is ignored or misinterpreted by AI, yours will be the clear, authoritative source, capturing a rapidly growing channel of traffic and influence.",{"id":251,"title":107,"titles":2417,"content":2418,"level":713},[],"Learn how to install the Craft Loanwords Craft CMS plugin.",{"id":2420,"title":716,"titles":2421,"content":2422,"level":719},"\u002Flibraries\u002Fcraft-loanwords\u002Fget-started\u002Finstallation#requirements",[107],"Requires Craft CMS 5.0.0 or later.PHP 8.2 or later.",{"id":2424,"title":722,"titles":2425,"content":2426,"level":719},"\u002Flibraries\u002Fcraft-loanwords\u002Fget-started\u002Finstallation#craft-plugin-store",[107],"To install Loanwords, go to the Plugin Store in your Craft control panel, search for \"Loanwords,\" and click the Install button.",{"id":2428,"title":727,"titles":2429,"content":2430,"level":719},"\u002Flibraries\u002Fcraft-loanwords\u002Fget-started\u002Finstallation#composer",[107],"With ddev: ddev composer require samuelreichor\u002Fcraft-loanwords &&\nddev craft plugin\u002Finstall loanwords With php: composer require samuelreichor\u002Fcraft-loanwords &&\nphp craft plugin\u002Finstall loanwords html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":254,"title":34,"titles":2432,"content":2433,"level":713},[],"Learn how to use the Craft Loanwords Craft CMS plugin.",{"id":2435,"title":2436,"titles":2437,"content":2438,"level":719},"\u002Flibraries\u002Fcraft-loanwords\u002Fget-started\u002Fusage#define-loanwords","Define Loanwords",[34],"Once you've installed the Loanwords plugin, you'll gain access to a dedicated section in Craft CMS for managing your loanwords. When you click on New Loanword you add new words. After saving, you can use the a11yTextReplacer() Twig extension in your templates.",{"id":2440,"title":2441,"titles":2442,"content":2443,"level":719},"\u002Flibraries\u002Fcraft-loanwords\u002Fget-started\u002Fusage#usage-in-frontent","Usage in Frontent",[34],"After saving, you can use the a11yTextReplacer() Twig extension in your templates. This automatically replaces loanwords in your content with the correct \u003Cspan lang=\"xx\"> tags. {{ a11yTextReplacer(entry.richText) | raw }} This extension takes an string as an argument.",{"id":262,"title":261,"titles":2445,"content":2446,"level":713},[],"Learn how to configure the Craft Loanwords Craft CMS plugin.",{"id":2448,"title":29,"titles":2449,"content":2450,"level":719},"\u002Flibraries\u002Fcraft-loanwords\u002Fconfiguration\u002Fconfig#configuration",[261],"Create a loanwords.php file under your \u002Fconfig directory with the following options available to you. You can also use multi-environment options to change these per environment. \u003C?php\n\nreturn [\n    '*' => [\n        'defaultLang' => 'de-AT',\n        'caseSensitive' => false,\n        'cssClass' => 'inline',\n    ]\n]; defaultLang: Sets the default language for loanwords, defaults to en.caseSensitive: Makes the replacement process case-sensitive, matching capitalization exactly, defaults to falsecssClass: Defines a CSS class for styling loanwords, defaults to position: inline as style if left blank. This File will overwrite the settings from the control panel.",{"id":2452,"title":808,"titles":2453,"content":2454,"level":719},"\u002Flibraries\u002Fcraft-loanwords\u002Fconfiguration\u002Fconfig#control-panel",[261],"You can also manage configuration settings through the Control Panel by visiting Settings → Loanwords. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":243,"title":242,"titles":2456,"content":2457,"level":713},[],"A plugin to enhance screen reader experience with Loanwords.",{"id":2459,"title":1168,"titles":2460,"content":2461,"level":719},"\u002Flibraries\u002Fcraft-loanwords#features",[242],"Manage and organize your loanwords effortlessly within Craft CMS.Includes a Twig Extension to automatically wrap loanwords with a tag for accessibility.Customize default language tags and CSS classes for consistent styling.Provides case-sensitive and case-insensitive options for flexible loanword matching.",{"id":2463,"title":2464,"titles":2465,"content":2466,"level":719},"\u002Flibraries\u002Fcraft-loanwords#what-are-loanwords","What are loanwords?",[242],"Loanwords are words borrowed from one language and incorporated into another, often retaining their original spelling and pronunciation. In German, common loanwords are Anglicisms like \"Bachelor\", \"Job\" or \"FAQ\" borrowed from English.",{"id":2468,"title":2469,"titles":2470,"content":2471,"level":719},"\u002Flibraries\u002Fcraft-loanwords#why-it-matters","Why it matters?",[242],"Using appropriate language tags for loanwords is essential for accessibility and semantic accuracy. These tags ensure that screen readers pronounce words correctly based on their language, providing a better experience for users with visual impairments. Additionally, proper language tagging improves SEO and helps search engines understand your content more effectively.",{"id":2473,"title":2474,"titles":2475,"content":2476,"level":719},"\u002Flibraries\u002Fcraft-loanwords#how-it-works","How it works",[242],"Once you've installed the Loanwords plugin, you'll gain access to a dedicated section in Craft CMS for managing your loanwords with ease. Adding a new loanword is simple—just provide the word and select the appropriate language from a dropdown menu. This ensures that each loanword is correctly tagged for accessibility and semantic accuracy. After saving, you can use the a11yTextReplacer() Twig extension in your templates. This automatically replaces loanwords in your content with the correct  tags, enhancing accessibility and ensuring proper screen reader pronunciation on the frontend.",{"id":266,"title":265,"titles":2478,"content":2479,"level":713},[],"A plugin for using the Craft CMS query builder externally.",{"id":2481,"title":1168,"titles":2482,"content":2483,"level":719},"\u002Flibraries\u002Fcraft-query-api#features",[265],"Comprehensive Content API: Supports querying for addresses, assets, entries, and users, providing a complete Content API for Craft CMS.Bearer Token Auth: Define schemas and bearer tokens in the controlpanel to control who can access your data.Get Only the Data You Need: Avoid overfetching by using a custom function in the query builder to select only the fields you require.Export TypeScript Types: You can easiliy export types based on fields and element with a command and use them directly.Pretty JSON Responses: JSON Transformers prettify the response for better readability.Native and Custom Field Detection: Automatically detects native Craft CMS fields and custom fields across all element types.Prerendering Helper: Fetch all active page URLs for prerendering, static site generation.Optimized Data Retrieval: High-performance content access with smart caching strategies ensures your queries run fast.Extensible: You can add your own Json Transformer and custom element types to the Query API.Support for native Asset Transforms: When querying images, it can return the optimized srcset generated by Craft Asset Transforms.ImagerX Support: When querying images, it can return the optimized srcset generated by ImagerX.",{"id":2485,"title":2486,"titles":2487,"content":2488,"level":719},"\u002Flibraries\u002Fcraft-query-api#usage-in-frontend","Usage in Frontend",[265],"The Craft Query API Plugin is highly adaptable. It comes with npm packages for Vue, Nuxt, React, Next.js and TypeScript, making integration seamless.\nThese packages enable developers to easily use the query builder to fetch data dynamically from your frontend with minimal configuration. Example in Nuxt: const currentSite = useCraftCurrentSite()\nconst uri = useCraftUri()\n\nconst { data, error } = await useCraftEntry()\n  .siteId(currentSite.value.id)\n  .uri(uri.value)\n  .section('news')\n  .all()\n\nif (error.value) {\n  console.error(error.value)\n} This approach simplifies the process of querying Craft CMS with JavaScript, making it a powerful tool for headless development.",{"id":2490,"title":2491,"titles":2492,"content":2493,"level":719},"\u002Flibraries\u002Fcraft-query-api#available-frontend-sdks","Available Frontend SDKs",[265],"The Craft Query API offers several SDks for modern frontend frameworks:",{"id":2495,"title":2496,"titles":2497,"content":2498,"level":719},"\u002Flibraries\u002Fcraft-query-api#access-control-with-schemas","Access Control with Schemas",[265],"Schemas allow you to define fine-grained access control for your data. Each access token is associated with one schema, which defines what content the token can access.\nThis ensures a secure and predictable way of querying data via the API. When creating a schema, you can assign permissions for specific content types, such as: SiteSectionVolumeUser GroupAddressCustom element types This setup gives you full flexibility to tailor access to your needs - for example, restricting a token to only a specific section or user group. Here's an example of what a schema configuration might look like: And that's how you define tokens:",{"id":2500,"title":2501,"titles":2502,"content":734,"level":719},"\u002Flibraries\u002Fcraft-query-api#why-not-graphql","Why not GraphQl?",[265],{"id":2504,"title":2505,"titles":2506,"content":2507,"level":740},"\u002Flibraries\u002Fcraft-query-api#productivity","Productivity",[265,2501],"GraphQL requires detailed schemas, fragments, which can feel counterproductive for developers focused on efficiency.",{"id":2509,"title":2510,"titles":2511,"content":2512,"level":740},"\u002Flibraries\u002Fcraft-query-api#steep-learning-curve","Steep Learning Curve",[265,2501],"If you're new to GraphQL, the syntax, schema design, error handling and tooling like Apollo can take significant time to learn. The Craft Query API Plugin works right out of the box like you were used to in twig.",{"id":2514,"title":2515,"titles":2516,"content":2517,"level":740},"\u002Flibraries\u002Fcraft-query-api#overhead-and-architectural-complexity","Overhead and Architectural Complexity",[265,2501],"Flexibility in GraphQL leads to a lot things you have to think of. Maintainability and error handling is hard with graphQl. The Craft CMS Query API eliminates this overhead. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":275,"title":274,"titles":2519,"content":2520,"level":713},[],"Use the Craft CMS query builder, enabling efficient data fetching. The Query API extends your Craft CMS project with endpoints, allowing you to query Addresses, Assets, Entries, and Users using simple URL parameters. The plugin speeds up and simplifies headless development with Craft CMS, so you as a developer can focus on the important parts of your application.",{"id":2522,"title":2523,"titles":2524,"content":2525,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Fintroduction#frontend-sdks","Frontend SDKs",[274],"It’s designed to make headless development incredibly fast and flexible, especially when paired with our SDKs. These libraries let you build queries in JavaScript\nusing a query builder that feels just like Craft’s native Twig syntax.",{"id":2527,"title":716,"titles":2528,"content":2529,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Fintroduction#requirements",[274],"Requires Craft CMS 5.0.0 or later.PHP 8.2 or later.For optimal image performance, it's highly recommended to use ImagerX.",{"id":2531,"title":2532,"titles":2533,"content":2534,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Fintroduction#supported-element-types","Supported Element Types",[274],"AddressesAssetsEntriesUsers To access any API endpoint, you must include a valid access token. This enforces secure, scoped access to your Craft CMS data.",{"id":2536,"title":2537,"titles":2538,"content":2539,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Fintroduction#need-help","Need Help?",[274],"If you encounter bugs or have feature requests, please submit an issue. Your feedback helps improve the library!",{"id":278,"title":107,"titles":2541,"content":2542,"level":713},[],"Learn how to install the Craft Query API Craft CMS  plugin.",{"id":2544,"title":2545,"titles":2546,"content":2547,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Finstall#craft-cms-setup","Craft CMS Setup",[107],"Set up a Craft CMS > 5 project. You could use that Guide.",{"id":2549,"title":2550,"titles":2551,"content":2552,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Finstall#using-a-template","Using a Template",[107],"You can try it out by using our CLI. This will setup a headless project in seconds. Just paste this command in your favorite terminal and get started. npx create-query-api@latest",{"id":2554,"title":2555,"titles":2556,"content":2557,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Finstall#install","Install",[107],"With ddev: ddev composer require samuelreichor\u002Fcraft-query-api &&\nddev craft plugin\u002Finstall query-api With php: composer require samuelreichor\u002Fcraft-query-api &&\nphp craft plugin\u002Finstall query-api",{"id":2559,"title":2560,"titles":2561,"content":2562,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Finstall#create-access-token","Create Access Token",[107],"You can use this command php craft query-api\u002Fdefault\u002Fcreate-public-token to automatically add a public access token with the according public schema.\nThen copy the access token.",{"id":2564,"title":2565,"titles":2566,"content":2567,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Finstall#finish-up","Finish up",[107],"You can test it now by hitting that endpoint with a curl or by using tools like bruno or postman. curl --request GET \\\n  --url 'https:\u002F\u002Fyour-site.ddev.site\u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery' \\\n  --header 'authorization: Bearer your-access-token' You should get an empty array as response: []. html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}",{"id":282,"title":281,"titles":2569,"content":2570,"level":713},[],"Learn how to configure the Craft Query API Craft CMS plugin. Here you find a brief overview of the first steps I always do after installing the Query API. These are all optional but I think they make sense.",{"id":2572,"title":2573,"titles":2574,"content":2575,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Ffirst-steps#configure-cors-origins","Configure Cors Origins",[281],"If you're using a reverse proxy (with some Nginx magic) and serve both frontend and backend from the same domain, you usually don't need to configure this.\nYou can see an example of this setup in the craft-nuxt starter repository. To prevent CORS origin errors in your frontend, you should configure allowed origins in the config\u002Fapp.web.php file.\nAdd the following configuration to define which domains are allowed to make cross-origin requests: \u003C?php\n\n  return [\n      'as corsFilter' => [\n          'class' => \\craft\\filters\\Cors::class,\n\n          \u002F\u002F Add your origins here\n          'cors' => [\n              'Origin' => [\n                  'http:\u002F\u002Flocalhost:3000',\n              ],\n              'Access-Control-Request-Method' => ['GET'],\n              'Access-Control-Request-Headers' => ['*'],\n              'Access-Control-Allow-Credentials' => true,\n              'Access-Control-Max-Age' => 86400,\n              'Access-Control-Expose-Headers' => [],\n          ],\n      ],\n  ];",{"id":2577,"title":2578,"titles":2579,"content":2580,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Ffirst-steps#headless-mode","Headless Mode",[281],"Set headless mode in your config\u002Fgeneral.php to true. Read more about the headless mode.",{"id":2582,"title":2583,"titles":2584,"content":2585,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Ffirst-steps#enable-preview","Enable Preview",[281],"To enable previewing entries etc. you have to tell Craft CMS, where the frontend lives.",{"id":2587,"title":2588,"titles":2589,"content":2590,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Ffirst-steps#add-a-new-env-var","Add a new env var:",[281,2583],"WEBSITE_URL=\"http:\u002F\u002Flocalhost:3000\"",{"id":2592,"title":2593,"titles":2594,"content":2595,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Ffirst-steps#add-new-alias-to-craft-cms","Add new alias to Craft CMS:",[281,2583],"Now add this recently created env var to your config\u002Fgeneral.php as an alias. ->aliases([\n    '@websiteUrl' => getenv('WEBSITE_URL'),\n])",{"id":2597,"title":2598,"titles":2599,"content":2600,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Ffirst-steps#change-site-url","Change Site URL",[281,2583],"And finally go to your control panel settings -> sites -> and change the base URL of your Site. If you click on the Craft CMS logo in the left top corner, you should land on your defined WEBSITE_URL",{"id":2602,"title":2603,"titles":2604,"content":2605,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Ffirst-steps#native-image-transforms","Native Image Transforms",[281],"Currently the Query API supports Craft's native image transforms and ImagerX out of the box. If you are using ImagerX, you can continue reading in the ImagerX Guide. As of now Craft does not support a global definition of srcSet's, but we need to define these somewhere. You can do that by adding a file named query-api.php in the config folder.\nHere you can configure the Query API and define image srcSets per image transform. This can look like that: \u003C?php\n\nreturn [\n    'assetTransforms' => [\n        'portrait' => [\n            'srcset' => ['100w', '200w'],\n            'generateOnSaveVolumes' => ['graphics']\n        ],\n        'landscape' => [\n            'srcset' => ['0.5x', '1x'],\n            'generateOnSaveVolumes' => true,\n        ],\n    ],\n]; You can find more about this in the settings page.",{"id":2607,"title":2608,"titles":2609,"content":2610,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Ffirst-steps#generatetransformsbeforepageload","generateTransformsBeforePageLoad",[281,2603],"Another thing that makes sense is to set the generateTransformsBeforePageLoad setting in the config\u002Fgeneral.php to true. This makes sure, image generation happens before the response comes back. You can read more about that in the offical docs of craft.",{"id":2612,"title":2613,"titles":2614,"content":2615,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fget-started\u002Ffirst-steps#enable-typescript-generation","Enable Typescript Generation",[281],"The Query API comes with some black magic that generates TypeScript definitions based on your project yamls. It offers settings to automatically regenerate this TypeScript file whenever the project config changes. To set this up, you need to have your frontend in the same repository. Otherwise it get's tricky to copy the TypeScript file to the right place. Start by adding a file named query-api.php in the config folder. \u003C?php\n\nreturn [\n    '*' => [],\n    'dev' => [\n        \u002F\u002F Automatic regeneration on project config changes\n        'typeGenerationMode' => 'auto',\n        \u002F\u002F \u002F\u002F Set the path where the generated TS file should be saved\n        'typeGenerationOutputPath' => '@root\u002Ffrontend\u002Fshared\u002Ftypes\u002Fbase.ts',\n    ]\n]; You can read more about that in the TypeScript and Craft CMS blog, to get an idea how to work with it. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}",{"id":290,"title":289,"titles":2617,"content":2618,"level":713},[],"Learn how to configure imagerX for the Craft Query API Craft CMS plugin.",{"id":2620,"title":2621,"titles":2622,"content":2623,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fintegrations\u002Fimager-x#image-generation","Image Generation",[289],"If you're using ImagerX (which I highly recommend), you'll need to generate all image transforms before querying them.\nOtherwise, the first fetch may take some time as all images will be generated during the initial request. To do this, create an imager-x-generate.php file in your .\u002Fconfig folder, listing all the named transforms. Here's an example of what that file might look like: \u003C?php\n\nreturn [\n    'volumes' => [\n        'images' => ['auto', 'square', 'landscape', 'portrait', 'dominantColor'],\n    ]\n]; The plugin will automatically detect the named transforms and widths defined in your imager-x-transforms.php. The response will include an object where the keys are the transform names, and the values are the srcset of all defined transforms.",{"id":2625,"title":2626,"titles":2627,"content":2628,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fintegrations\u002Fimager-x#add-imager-url","Add Imager Url",[289],"If your frontend and backend are not accessible under the same URL, you’ll need to configure an Imager URL. This ensures that your srcset attributes use absolute URLs instead of the default relative ones.\nThis is particularly important in development environments, especially if you’re not using a reverse proxy (e.g., in DDEV) to serve your frontend. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":294,"title":293,"titles":2630,"content":2631,"level":713},[],"Learn how to configure SEOmatic for the Craft Query API Craft CMS plugin.",{"id":2633,"title":2634,"titles":2635,"content":2636,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fintegrations\u002Fseo-matic#configure-seomatic","Configure SEOmatic",[293],"SEOmatic provides its own endpoints, which can be enabled in the plugin settings. I highly recommend checking out the documentation for more details. The values of SEOmatic fields are filtered out of the response due to the endpoints mentioned above.",{"id":301,"title":34,"titles":2638,"content":2639,"level":713},[],"Learn how to effectively use the Craft Query API You can fetch elements (such as addresses, assets, entries, and users) using the customQuery endpoint. If you need to retrieve all routes, the allRoutes endpoint is available. For more details, check out the customQuery and allRoutes documentation. You can either manually build your URLs or leverage one of the following SDKs for JavaScript frameworks:",{"id":2641,"title":2642,"titles":2643,"content":2644,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fusage#build-your-own","Build Your Own",[34],"If your favorite framework isn’t listed here, you can use the JS SDK to create custom queries tailored to your specific needs. Feel free to reach out if you need any help! :)",{"id":305,"title":304,"titles":2646,"content":2647,"level":713},[],"Learn about caching your queries with Craft Cuery API The API endpoints are blazingly fast. 🚀",{"id":2649,"title":2650,"titles":2651,"content":2652,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fcaching#caching-strategy","Caching Strategy",[304],"The plugin utilizes Craft's built-in caching mechanism, similar to the {% cache %} tag in Twig. Caches are automatically invalidated when any element in the request changes. The cache will persist based on the cacheDuration setting defined in your configuration. You can adjust this in your Craft CMS configuration. You can learn how to override that in the Settings Page. A new cache is created when a previously unqueried element is requested. However, simply changing the order of your GET parameters will NOT generate a new cache.",{"id":2654,"title":2655,"titles":2656,"content":2657,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fcaching#eager-loading","Eager Loading",[304],"To optimize the initial cache generation, eager loading is used to reduce the number of database queries. This is handled automatically through an internal eager loading map, so no additional configuration is required. You should however try to reuse relational fields to keep things scalable.",{"id":309,"title":308,"titles":2659,"content":2660,"level":713},[],"Learn about all of the settings of the craft query API You can define a multi environment aware config in \u002Fconfig\u002Fquery-api.php. You can find an example in that file.",{"id":2662,"title":2663,"titles":2664,"content":2665,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fsettings#assettransforms","assetTransforms",[308],"Define named image transforms with srcset configurations. The key is the handle of the named image transform. return [\n  '*' => [\n    'assetTransforms' => [\n      'portrait' => [\n        'srcset' => ['100w', '200w'], \u002F\u002F define a srcset\n        'generateOnSaveVolumes' => ['graphics'], \u002F\u002F auto generate images for volume \"graphics\"\n      ],\n      'landscape' => [\n        'srcset' => ['1x', '2x'], \u002F\u002F define a srcset\n        'generateOnSaveVolumes' => true, \u002F\u002F auto generate images for all volumes\n      ],\n    ],\n  ]\n] Native image transforms are not automatically detected by the Query API. If you want a srcSet to be included in the response, you need to define this setting explicitly.\nOtherwise, there's no reliable way for the API to know which srcSet should be generated. If ImagerX is installed and enabled, this get's ignored.",{"id":2667,"title":2668,"titles":2669,"content":2670,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fsettings#cacheduration","cacheDuration",[308],"Defines the cache duration. Defaults to the cache duration defined in your general.php. return [\n 'production' => [\n   'cacheDuration' => 3600, \u002F\u002F cache for 1h\n ]\n]",{"id":2672,"title":2673,"titles":2674,"content":2675,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fsettings#excludedfieldclasses","excludedFieldClasses",[308],"Define field classes that should be excluded from the json response. Used for example for excluding the seo settings field, because SEOmatic has its own API endpoint for that. return [\n 'production' => [\n   'excludeFieldClasses' => ['nystudio107\\seomatic\\fields\\SeoSettings'],\n ]\n]",{"id":2677,"title":2678,"titles":2679,"content":2680,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fsettings#includeallentry","includeAllEntry",[308],"Defines how entry relations from an Entries field are returned. If enabled, the customQuery endpoint will include full entry objects, otherwise only minimal data (title, URI, ID, slug) is returned. return [\n  '*' => [\n    'includeAllEntry' => true,\n  ]\n] If you use this, be sure that you don't have circular entry relations. This would end up in an endless loop.",{"id":2682,"title":2683,"titles":2684,"content":2685,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fsettings#typegenerationmode","typeGenerationMode",[308],"Determines how ts types for your frontend should be created.",{"id":2687,"title":2688,"titles":2689,"content":2690,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fsettings#manuel","Manuel",[308,2683],"Set it to manuel if you want to create your type definitions manually with the craft query-api\u002Fgenerate-types command. return [\n  'dev' => [\n    'typeGenerationMode' => 'manual',\n  ]\n]",{"id":2692,"title":2693,"titles":2694,"content":2695,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fsettings#auto","Auto",[308,2683],"Set it to auto if you want to recreate your type definitions on demand, everything your project config changes. return [\n  'dev' => [\n    'typeGenerationMode' => 'auto',\n  ]\n] This will only run if you change the project config through the Craft CMS control panel. If you run craft project-config\u002Fapply it will NOT run. Then you have to do it manually with the craft query-api\u002Fgenerate-types command.",{"id":2697,"title":2698,"titles":2699,"content":2700,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fsettings#typegenerationoutputpath","typeGenerationOutputPath",[308],"Defines where ts definitions get created. Aliases can be used here as well. return [\n  'dev' => [\n    'typeGenerationOutputPath' => '@root\u002FqueryApiTypes.ts',\n  ]\n] html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":313,"title":312,"titles":2702,"content":2703,"level":713},[],"Learn about all of the commands of the craft query API",{"id":2705,"title":2706,"titles":2707,"content":2708,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fcommands#create-public-schema","create-public-schema",[312],"Creates a public schema. ddev craft query-api\u002Fdefault\u002Fcreate-public-schema\nphp craft query-api\u002Fdefault\u002Fcreate-public-schema",{"id":2710,"title":2711,"titles":2712,"content":2713,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fcommands#create-public-token","create-public-token",[312],"Creates a public schema along with an access token.\nThis will fail if a schema or token with the same identifier already exists. ddev craft query-api\u002Fdefault\u002Fcreate-public-token\nphp craft query-api\u002Fdefault\u002Fcreate-public-token",{"id":2715,"title":2716,"titles":2717,"content":2718,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fcommands#clear-caches","clear-caches",[312],"This will clear all data caches managed by the Query API. ddev craft query-api\u002Fdefault\u002Fclear-caches\nphp craft query-api\u002Fdefault\u002Fclear-caches",{"id":2720,"title":2721,"titles":2722,"content":2723,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fcommands#generate-types","generate-types",[312],"This will generate TypeScript types based on your elements and fields. ddev craft query-api\u002Ftypescript\u002Fgenerate-types\nphp craft query-api\u002Ftypescript\u002Fgenerate-types",{"id":2725,"title":2726,"titles":2727,"content":2728,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fcommands#options","Options",[312,2721],"--output: Define an output path, where the file should be stored. This will also accept craft aliases. Example: ddev craft query-api\u002Ftypescript\u002Fgenerate-types --output=.\u002Fyour-path\u002FyourFile.ts",{"id":2730,"title":2731,"titles":2732,"content":2733,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fcommands#image-transforms","image-transforms",[312],"Bulk generate image transforms, for native craft asset transforms. ddev craft query-api\u002Fimage-transforms\u002Fgenerate\nphp craft query-api\u002Fimage-transforms\u002Fgenerate",{"id":2735,"title":2726,"titles":2736,"content":2737,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fusage\u002Fcommands#options-1",[312,2731],"--transforms: Define one or more transform handles.--volumes: Define one or more volume handles. Example: ddev craft query-api\u002Fimage-transforms\u002Fgenerate --transforms=portrait --volumes=images,graphics html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}",{"id":322,"title":321,"titles":2739,"content":2740,"level":713},[],"Learn how to use the customQuery API endpoint. The customQuery endpoint allows you to query addresses, assets, entries, and users directly via URL parameters. It returns a JSON response for easy consumption. To use it, simply send a GET request to: ${PRIMARY_SITE_URL}\u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery with some query params. This could look like that\n\u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery?elementType=entries&section=home&one=1. A full example with an access token might look like this: curl --request GET \\\n  --url 'https:\u002F\u002Fyour-site.ddev.site\u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery?elementType=entries&section=home&one=1' \\\n  --header 'authorization: Bearer your-access-token'",{"id":2742,"title":2743,"titles":2744,"content":2745,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fcustom-query#get-params","GET Params",[321],"Each element type has its own set of available GET parameters. This ensures precise control over the query and enhances security. Internally, these parameters are filtered to prevent potential exploits.",{"id":2747,"title":2748,"titles":2749,"content":2750,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fcustom-query#special-parameters","Special Parameters",[321],"Below is a list of special GET parameters that are available in all element types. ParamsDescriptionPossible ValuesallFetch all elements1elementTypeSpecify the element type to queryaddresses, assets, entries, usersincludeAllEntryWhether to include the full data of entries or just the minimal fields (title, URI, ID, and slug).1 for true and 0 for falsefieldsQuery specific field data by handlestring or array of field handles, use dot notation to filter out nested data, use * as a wildcardoneFetch a single element1 The following parameters are required: elementType and either one or all.",{"id":2752,"title":2753,"titles":2754,"content":2755,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fcustom-query#fields","fields",[321,2748],"The fields param is a simple filter, to minify the response returned to the client.\nYou can use a * in combination with fieldhandle.nestedFieldHandle, to filter out stuff that is not important.",{"id":2757,"title":2678,"titles":2758,"content":2759,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fcustom-query#includeallentry",[321,2748],"The includeAllEntry defines how entry relations from an Entries field are returned.\nIf enabled, the customQuery endpoint will include full entry objects, otherwise only minimal data (title, URI, ID, slug) is returned.\nTo enable this setting globally you can use the includeAllEntry setting If you use the includeAllEntry param, be sure that you don't have circular entry relations. This would end up in an endless loop.",{"id":2761,"title":2762,"titles":2763,"content":2764,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fcustom-query#addresses","Addresses",[321],"Below is a list of all available GET parameters for the addresses element type: ParamsElement typeaddressLine1addressesaddressLine2addressesaddressLine3addressesfixedOrderallfullNameaddressesidalllimitalllocalityaddressesoffsetallorderByallorganizationaddressessearchall",{"id":2766,"title":2767,"titles":2768,"content":2769,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fcustom-query#assets","Assets",[321],"Below is a list of all available GET parameters for the assets element type: ParamsElement typefilenameassetsfixedOrderallidallkindassetslimitalloffsetallorderByallsearchallsiteassetssiteIdassetsvolumeassets",{"id":2771,"title":2772,"titles":2773,"content":2774,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fcustom-query#entries","Entries",[321],"Below is a list of all available GET parameters for the entries element type: ParamsElement typefixedOrderallidalllevelentrieslimitalloffsetallorderByallpostDateentriesrelatedToentriesnotRelatedToentriesandRelatedToentriesandNotrelatedToentriessearchallsectionentriessectionIdentriessiteentriessiteIdentriesslugentriesstatusalltypeentriesurientries",{"id":2776,"title":2777,"titles":2778,"content":2779,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fcustom-query#users","Users",[321],"Below is a list of all available GET parameters for the users element type: ParamsElement typeadminusersauthorOfusersemailusersfixedOrderallfullNameusersgroupusersgroupIdusershasPhotousersidalllimitalloffsetallorderByallsearchallstatusall html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":326,"title":325,"titles":2781,"content":2782,"level":713},[],"Learn how to effectively use the allRoutes API endpoint. The allRoutes endpoint retrieves all active routes for a specified siteId or for all sites. This is particularly useful for prerendering your pages.",{"id":2784,"title":394,"titles":2785,"content":2786,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fall-routes#basic-usage",[325],"To use this endpoint, send a GET request to ${PRIMARY_SITE_URL}\u002Fv1\u002Fapi\u002FqueryApi\u002FallRoutes to receive an array of routes for all sites. If you want to fetch routes for a specific site, append the siteId to the URL. For example for siteId = 1 you could use the endpoint like that: ${PRIMARY_SITE_URL}\u002Fv1\u002Fapi\u002FqueryApi\u002FallRoutes\u002F1. A full example with an access token might look like this: curl --request GET \\\n  --url 'https:\u002F\u002Fyour-site.ddev.site\u002Fv1\u002Fapi\u002FqueryApi\u002FallRoutes' \\\n  --header 'authorization: Bearer your-access-token'",{"id":2788,"title":398,"titles":2789,"content":2790,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fall-routes#advanced-usage",[325],"You can pass an array as a URL parameter to the allRoutes endpoint by encoding the array as a JSON string and then URL encoding it. This allows you to retrieve routes for multiple siteIds in a single request.",{"id":2792,"title":681,"titles":2793,"content":2794,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fall-routes#example",[325,398],"To fetch routes for siteId 1 and 2: https:\u002F\u002Fexample.com\u002Fv1\u002Fapi\u002FqueryApi\u002FallRoutes?siteIds=%5B1%2C2%5D",{"id":2796,"title":2797,"titles":2798,"content":2799,"level":2800},"\u002Flibraries\u002Fcraft-query-api\u002Fendpoints\u002Fall-routes#breakdown","Breakdown:",[325,398,681],"https:\u002F\u002Fexample.com\u002Fv1\u002Fapi\u002FqueryApi\u002FallRoutes: Base URL of your API endpoint.?siteIds=: Query parameter indicating you’re passing siteIds.%5B1%2C2%5D: URL-encoded JSON string 1,2.\n%5B is [%2C is ,%5D is ] html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",4,{"id":335,"title":334,"titles":2802,"content":2803,"level":713},[],"Learn how you can add your own transformers for custom fields. You can use the EVENT_REGISTER_FIELD_TRANSFORMERS event to define custom transformers for specific field types. A transformer is responsible for processing the data for your json response for a given field. Here's how to set it up:",{"id":2805,"title":2806,"titles":2807,"content":2808,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fevents\u002Fadd-custom-transformer#initialize-event-listener","Initialize Event Listener",[334],"Add the following code to your module or plugin to register your custom transformer: use modules\\queryapiextension\\transformers\\HyperTransformer;\nuse samuelreichoer\\queryapi\\transformers\\BaseTransformer;\nuse samuelreichoer\\queryapi\\events\\RegisterFieldTransformersEvent;\n\nEvent::on(\n    BaseTransformer::class,\n    BaseTransformer::EVENT_REGISTER_FIELD_TRANSFORMERS,\n    function (RegisterFieldTransformersEvent $event) {\n        $event->transformers[] = [\n            'fieldClass' => 'verbb\\hyper\\fields\\HyperField', \u002F\u002F class of your field you want to transform\n            'transformer' => HyperTransformer::class, \u002F\u002F class of your transformer\n        ];\n    }\n); In this example: fieldClass specifies the fully qualified class name of the field you want to transform.transformer defines the custom transformer class that will handle the transformation.",{"id":2810,"title":2811,"titles":2812,"content":2813,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fevents\u002Fadd-custom-transformer#creating-a-transformer","Creating a Transformer",[334],"A transformer class processes the field's data. Here’s an example for a HyperField transformer: \u003C?php\n\nnamespace modules\\queryapiextension\\transformers;\n\nuse verbb\\hyper\\models\\LinkCollection;\n\nclass HyperTransformer\n{\n    private LinkCollection $hyper;\n\n    public function __construct(LinkCollection $hyper)\n    {\n        $this->hyper = $hyper;\n    }\n\n    \u002F**\n     * Transforms the Hyper field data.\n     *\n     * @return array\n     *\u002F\n    public function getTransformedData(): array\n    {\n        return [\n            'metadata' => $this->getMetaData(),\n            'linkText' => $this->hyper->text,\n            'linkUrl' => $this->hyper->url,\n            'linkTarget' => $this->hyper->target,\n        ];\n    }\n\n    \u002F**\n     * Retrieves metadata from the Hyper field.\n     *\n     * @return array\n     *\u002F\n    protected function getMetaData(): array\n    {\n        return [\n            'type' => $this->hyper->type,\n        ];\n    }\n}",{"id":2815,"title":2816,"titles":2817,"content":2818,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fevents\u002Fadd-custom-transformer#extending-the-base-transformer","Extending the Base Transformer",[334,2811],"If your custom transformer requires shared functionality, you can extend the BaseTransformer class to inherit common logic. For example: use samuelreichoer\\queryapi\\transformers\\BaseTransformer;\n\nclass HyperTransformer extends BaseTransformer\n{\n    public function getTransformedData(): array\n    {\n        return [\n            'linkText' => $this->hyper->text,\n            'linkUrl' => $this->hyper->url,\n        ];\n    }\n}",{"id":2820,"title":2821,"titles":2822,"content":2823,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fevents\u002Fadd-custom-transformer#important-notes","Important Notes",[334],"Method Naming: The plugin uses the getTransformedData() method to fetch transformed data. This method is required in all custom transformers.Error Logging: If a transformer is not properly registered or does not implement getTransformedData(), an error will be logged, but it will not throw it. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":339,"title":338,"titles":2825,"content":2826,"level":713},[],"Learn how you can add your own element type for plugins. You can use the EVENT_REGISTER_ELEMENT_TYPES event to define custom element types. An element Type has it's own transformer and query. We will try that out with the awesome Navigation Plugin. Here's how to set it up:",{"id":2828,"title":2806,"titles":2829,"content":2830,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fevents\u002Fadd-custom-element-type#initialize-event-listener",[338],"Add the following code to your module or plugin to register your custom transformer: use modules\\queryapiextension\\transformers\\NavigationTransformer;\n\nuse samuelreichoer\\queryapi\\events\\RegisterElementTypesEvent;\nuse samuelreichoer\\queryapi\\models\\RegisterElementType;\nuse samuelreichoer\\queryapi\\services\\ElementQueryService;\n\nEvent::on(\n    ElementQueryService::class,\n    ElementQueryService::EVENT_REGISTER_ELEMENT_TYPES,\n    function (RegisterElementTypesEvent $event) {\n        $event->elementTypes[] = new RegisterElementType([\n            'elementTypeClass' => 'verbb\\navigation\\elements\\Node',\n            'elementTypeHandle' => 'navigation',\n            'allowedMethods' => ['limit', 'handle', 'id'],\n            'transformer' => NavigationTransformer::class,\n        ]);\n    }\n); In this example: elementTypeClass specifies the full class name of the element type you want to add.elementTypeHandle defines the handle that you use later for quering from that element type.allowedMethods defines all allowed methods that you can later use in the query builder.transformer adds the json transformer for beautiful responses.",{"id":2832,"title":2811,"titles":2833,"content":2834,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fevents\u002Fadd-custom-element-type#creating-a-transformer",[338],"The Transformer processes the data for the response. Here’s an example for the NavigationTransformer: \u003C?php\n\nnamespace modules\\queryapiextension\\transformers; \u002F\u002F Change this to your namespace\n\nuse samuelreichoer\\queryapi\\transformers\\BaseTransformer;\nuse verbb\\navigation\\elements\\Node;\n\nclass NavigationTransformer extends BaseTransformer\n{\n    protected Node $navigation;\n\n    public function __construct(Node $navigation)\n    {\n        parent::__construct($navigation);\n        $this->navigation = $navigation;\n    }\n\n    \u002F**\n     * Transforms the Navigation Node into an array.\n     *\n     * @param array $predefinedFields\n     * @return array\n     *\u002F\n    public function getTransformedData(array $predefinedFields = []): array\n    {\n        return [\n            'metadata' => $this->getMetaData(),\n            'title' => $this->navigation->title,\n            'url' => $this->navigation->getUrl(),\n            'type' => $this->navigation->getTypeLabel(),\n            'level' => $this->navigation->level,\n        ];\n    }\n\n    \u002F**\n     * Retrieves metadata from the Navigation Node.\n     *\n     * @return array\n     *\u002F\n    protected function getMetaData(): array\n    {\n        return array_merge(parent::getMetaData(), [\n            'id' => $this->navigation->id,\n            'siteId' => $this->navigation->site->id,\n            'status' => $this->navigation->getStatus(),\n        ]);\n    }\n}",{"id":2836,"title":34,"titles":2837,"content":2838,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fevents\u002Fadd-custom-element-type#usage",[338],"After that you should be able to query from the new added navigation element type like that: \u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery?elementType=navigation&handle=main-navigation&all=1 You can use all query params that you have added through the allowedMethods property and all of the special parameters (e.g. one=1 and all=1). html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"id":343,"title":342,"titles":2840,"content":2841,"level":713},[],"Learn how you can add your own TypeScript types. You can use the EVENT_REGISTER_TYPE_DEFINITIONS event to define custom TypeScript type definitions for specific Craft CMS field types.",{"id":2843,"title":2806,"titles":2844,"content":2845,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fevents\u002Fadd-custom-ts-types#initialize-event-listener",[342],"Add the following code to your module or plugin to register your custom type definitions: use modules\\queryapiextension\\transformers\\NavigationTransformer;\n\nuse samuelreichoer\\queryapi\\events\\RegisterTypeDefinitionEvent;\nuse samuelreichoer\\queryapi\\models\\RegisterTypeDefinition;\nuse samuelreichoer\\queryapi\\services\\TypescriptService;\n\nEvent::on(\n    TypescriptService::class,\n    TypescriptService::EVENT_REGISTER_TYPE_DEFINITIONS,\n    function (RegisterTypeDefinitionEvent $event) {\n        $event->typeDefinitions[] = new RegisterTypeDefinition([\n            'fieldTypeClass' => 'verbb\\hyper\\fields\\HyperField',\n            'staticHardType' => 'export type hello = string',\n            'dynamicHardType' => HyperTypeService::class,\n            'staticTypeDefinition' => 'hello[]',\n            'dynamicDefinitionClass' => HyperTypeService::class,\n        ]);\n    }\n); Each RegisterTypeDefinition allows the user to define: fieldTypeClass: The Craft field class this applies to (e.g., HyperField::class).staticHardType: A custom hardcoded TypeScript type that will be injected globally (e.g., utility or shared types). It gets overwritten if dynamicHardType is defined.dynamicHardType: A PHP class that can dynamically generate hardcoded types (must implement a method like setHardTypes()).staticTypeDefinition: A fixed return type for this field (e.g., hello[]). It gets overwritten if dynamicHardType is defined.dynamicDefinitionClass: A PHP class that will receive the field and return a context-aware type (must have a method like setTypeByField()).",{"id":2847,"title":2811,"titles":2848,"content":2849,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fevents\u002Fadd-custom-ts-types#creating-a-transformer",[342],"To set dynamic types you can create a file like the following: \u003C?php\n\nnamespace modules\\queryapiextension\\services;\n\nuse samuelreichoer\\queryapi\\services\\TypescriptService;\nuse verbb\\hyper\\fields\\HyperField;\n\nclass HyperTypeService extends TypescriptService\n{\n    \u002F\u002F Set type for all fields that have the HyperField class\n    public function setTypeByField(HyperField $field): string\n    {\n        return 'HyperField';\n    }\n\n    \u002F\u002F Set global type, you can use this in the setTypeByField method.\n    public function setCustomHardTypes(): string\n    {\n        return 'export type HyperField = object';\n    }\n} html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"id":352,"title":351,"titles":2851,"content":2852,"level":713},[],"Learn how to deploy a headless Craft Cms site with a Nuxt frontend. Here are a few ways to deploy your headless project.\nThese guides are based on the Craft Nuxt Starter example.\nIf you have a different setup then these might not work for you.\nFeel free to raise a GitHub issue if you feel something is missing here.",{"id":2854,"title":2855,"titles":2856,"content":2857,"level":719},"\u002Flibraries\u002Fcraft-query-api\u002Fdeployment\u002Fnuxt#coolify","Coolify",[351],"Coolify is a docker based, open-source Paas. For me it is the go to choice for cheap hosting.",{"id":2859,"title":2860,"titles":2861,"content":2862,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fdeployment\u002Fnuxt#prepare-project","Prepare Project",[351,2855],"To get started, you can add these files to your project. docker-compose.yaml should be in the root of your project. # favicon.ico\nlocation = \u002Ffavicon.ico {\n    log_not_found off;\n    access_log    off;\n}\n\n# robots.txt\nlocation = \u002Frobots.txt {\n    log_not_found off;\n    access_log    off;\n}\n\n# assets, media\nlocation ~* \\.(?:css(\\.map)?|js(\\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv|txt)$ {\n    expires    7d;\n    access_log off;\n}\n\n# svg, fonts\nlocation ~* \\.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ {\n    add_header Access-Control-Allow-Origin \"*\";\n    expires    7d;\n    access_log off;\n}\n\n# gzip\ngzip              on;\ngzip_vary         on;\ngzip_proxied      any;\ngzip_comp_level   6;\ngzip_types        text\u002Fplain text\u002Fcss text\u002Fxml application\u002Fjson application\u002Fjavascript application\u002Frss+xml application\u002Fatom+xml image\u002Fsvg+xml;\n# 404\ntry_files                     $fastcgi_script_name =404;\n\n# default fastcgi_params\ninclude                       fastcgi_params;\n\n# fastcgi settings\nfastcgi_pass                  127.0.0.1:9000;\nfastcgi_index                 index.php;\nfastcgi_buffers               8 16k;\nfastcgi_buffer_size           32k;\n\n# fastcgi params\nfastcgi_param DOCUMENT_ROOT   $realpath_root;\nfastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;\n# security headers\nadd_header X-Frame-Options         \"SAMEORIGIN\" always;\nadd_header X-XSS-Protection        \"1; mode=block\" always;\nadd_header X-Content-Type-Options  \"nosniff\" always;\nadd_header Referrer-Policy         \"no-referrer-when-downgrade\" always;\n#add_header Content-Security-Policy \"default-src 'self' http: https: data: blob: 'unsafe-inline'\" always;\n\n# . files\nlocation ~ \u002F\\.(?!well-known) {\n    deny all;\n}\nserver {\n    listen      80 default_server;\n    listen      [::]:80 default_server;\n    set         $base \u002Fapp;\n    root        $base\u002Fweb;\n    # security\n    include     craftcms\u002Fsecurity.conf;\n\n    # index\n    index index.html index.htm index.php;\n\n    # Craft CMS Stuff\n    location ~ .*\u002Fapi\u002F.* {\n        root \u002Fapp\u002Fweb;\n        try_files $uri $uri\u002F \u002Findex.php?$query_string;\n    }\n\n    location ~ .*\u002Factions\u002F.* {\n        root \u002Fapp\u002Fweb;\n        try_files $uri $uri\u002F \u002Findex.php?$query_string;\n    }\n\n    location \u002Fadmin {\n        root \u002Fapp\u002Fweb;\n        try_files $uri $uri\u002F \u002Findex.php?$query_string;\n    }\n\n    location \u002Fgql {\n        root \u002Fapp\u002Fweb;\n        try_files $uri $uri\u002F \u002Findex.php?$query_string;\n    }\n\n    location ~ ^\u002F(sitemap.*|robots\\.txt|security\\.txt) {\n        root \u002Fapp\u002Fweb;\n        try_files $uri $uri\u002F \u002Findex.php?$query_string;\n    }\n\n    location ^~ \u002Fassets\u002F {\n        root \u002Fapp\u002Fweb;\n        try_files $uri $uri\u002F @craft;\n    }\n\n    location ^~ \u002Fcpresources\u002F {\n        root \u002Fapp\u002Fweb;\n        try_files $uri $uri\u002F \u002Findex.php?$query_string;\n    }\n\n    location ^~ \u002Fstatic\u002F {\n        root \u002Fapp\u002Fweb;\n        try_files $uri $uri\u002F \u002Findex.php?$query_string;\n    }\n\n    location ^~ \u002Fuploads\u002F {\n        root \u002Fapp\u002Fweb;\n        try_files $uri $uri\u002F \u002Findex.php?$query_string;\n    }\n\n    # Nuxt Stuff\n    location \u002F {\n        root \u002Fapp\u002Ffrontend\u002F.output\u002Fpublic;\n        index index.html;\n        try_files $uri $uri.html $uri\u002Findex.html @nuxt-proxy;\n    }\n\n    location @nuxt-proxy {\n        proxy_pass http:\u002F\u002Ffrontend:3000;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection 'upgrade';\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_cache_bypass $http_upgrade;\n    }\n\n    location ^~ \u002F_nuxt\u002F {\n        root \u002Fapp\u002Ffrontend\u002F.output\u002Fpublic;\n        try_files $uri $uri.html $uri\u002Findex.html @nuxt-proxy;\n    }\n\n    # additional config\n    include craftcms\u002Fgeneral.conf;\n\n    # handle .php\n    location ~ \\.php$ {\n        include craftcms\u002Fphp_fastcgi.conf;\n        fastcgi_split_path_info ^(.+\\.php)(\u002F.+)$;\n        fastcgi_param PATH_INFO $fastcgi_path_info;\n    }\n}\npid                  \u002Frun\u002Fnginx.pid;\nworker_processes     auto;\nworker_rlimit_nofile 65535;\ndaemon               off;\nerror_log \u002Fdev\u002Fstdout;\n\nevents {\n    multi_accept       on;\n    worker_connections 65535;\n}\n\nhttp {\n    charset              utf-8;\n    sendfile             on;\n    tcp_nopush           on;\n    tcp_nodelay          on;\n    server_tokens        off;\n    log_not_found        off;\n    types_hash_max_size  2048;\n    client_max_body_size 25M;\n\n    # MIME\n    include              mime.types;\n    default_type         application\u002Foctet-stream;\n\n    # Logging\n\n     # Define custom log format to include reponse times\n    log_format main_timed '$remote_addr - $remote_user [$time_local] \"$request\" '\n                          '$status $body_bytes_sent \"$http_referer\" '\n                          '\"$http_user_agent\" \"$http_x_forwarded_for\" '\n                          '$request_time $upstream_response_time $pipe $upstream_cache_status';\n    access_log           \u002Fdev\u002Fstdout main_timed;\n\n    # write to tmp for non-privileged user\n    client_body_temp_path \u002Ftmp\u002Fclient_temp;\n    proxy_temp_path \u002Ftmp\u002Fproxy_temp_path;\n    fastcgi_temp_path \u002Ftmp\u002Ffastcgi_temp;\n    uwsgi_temp_path \u002Ftmp\u002Fuwsgi_temp;\n    scgi_temp_path \u002Ftmp\u002Fscgi_temp;\n\n    # Load configs\n    include              \u002Fetc\u002Fnginx\u002Fconf.d\u002F*.conf;\n    include              \u002Fetc\u002Fnginx\u002Fsites-enabled\u002F*;\n}\n[program:nginx]\ncommand=\u002Fusr\u002Fsbin\u002Fnginx -c \u002Fetc\u002Fnginx\u002Fnginx.conf\nstdout_logfile=\u002Fdev\u002Fstdout\nstdout_logfile_maxbytes=0\nstderr_logfile=\u002Fdev\u002Fstderr\nstderr_logfile_maxbytes=0\nstartretries=0\nautorestart=true\nARG php_version\nFROM ghcr.io\u002Fcraftcms\u002Fimage:${php_version}\n\nUSER root\n\n# copy the files from the host to the container that we need\nRUN rm \u002Fetc\u002Fnginx\u002Fsites-enabled\u002Fdefault\nCOPY .\u002F.coolify\u002Fnginx\u002Fnginx.conf \u002Fetc\u002Fnginx\u002Fnginx.conf\nCOPY .\u002F.coolify\u002Fnginx\u002Fnginx.ini \u002Fetc\u002Fsupervisord.d\u002Fnginx.ini\nCOPY .\u002F.coolify\u002Fnginx\u002Fcraftcms \u002Fetc\u002Fnginx\u002Fcraftcms\nRUN mkdir -p \u002Fetc\u002Fnginx\u002Fsites-enabled\nCOPY .\u002F.coolify\u002Fnginx\u002Fsites-available\u002Fdefault.conf \u002Fetc\u002Fnginx\u002Fsites-enabled\u002Fdefault.conf\n\n# set the sockets and pid files to be writable by the appuser\nRUN mkdir -p \u002Fvar\u002Flog\u002Fnginx && chown -R appuser:appgroup \u002Fvar\u002Flog\u002Fnginx\nRUN chown -R appuser:appgroup \u002Fvar\u002Flib\u002Fnginx && touch \u002Frun\u002Fnginx.pid && chown -R appuser:appgroup \u002Frun\u002Fnginx.pid\n\n# Install Composer\nCOPY --from=composer:2 \u002Fusr\u002Fbin\u002Fcomposer \u002Fusr\u002Fbin\u002Fcomposer\n\n# Install other packages\nRUN apt-get update && apt-get install -y --no-install-recommends \\\n  unzip bash vim \\\n  default-mysql-client libmariadb3 \\\n  && rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\n\nWORKDIR \u002Fapp\nUSER appuser\n\nCOPY composer.json composer.lock .\u002F\nRUN composer install --no-interaction --no-dev --optimize-autoloader\n\nCOPY --chown=appuser:appgroup . .\n\nEXPOSE 9000 8080 80\n# ---------- Build Stage ----------\nFROM node:22-alpine AS build\nWORKDIR \u002Fapp\n\nCOPY package.json package-lock.json .\u002F\nCOPY frontend\u002Fpackage.json frontend\u002Fpackage.json\n\nRUN npm ci --workspaces --include-workspace-root\n\nCOPY frontend\u002F .\u002F\nRUN npm run build\n\n# ---------- Runtime Stage ----------\nFROM node:22-alpine\nWORKDIR \u002Fapp\n\nCOPY --from=build \u002Fapp\u002F.output\u002F .\u002F\n\nEXPOSE 3000\n\nCMD [\"node\", \"\u002Fapp\u002Fserver\u002Findex.mjs\"]\nservices:\n  web:\n    build:\n      context: .\n      dockerfile: .\u002F.coolify\u002Fweb\u002FDockerfile\n      args:\n        - php_version=8.3\n    volumes:\n      - assets_data:\u002Fapp\u002Fweb\u002Fassets\n    depends_on:\n      db:\n        condition: service_healthy\n\n  frontend:\n    build:\n      context: .\n      dockerfile: .\u002F.coolify\u002Fnode\u002FDockerfile\n\n  db:\n    image: mysql:8.4\n    environment:\n      MYSQL_DATABASE: db\n      MYSQL_USER: db\n      MYSQL_PASSWORD: db\n      MYSQL_ROOT_PASSWORD: db\n    volumes:\n      - db_data:\u002Fvar\u002Flib\u002Fmysql\n    healthcheck:\n      test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\"]\n      interval: 1s\n      timeout: 3s\n      retries: 10\n\nvolumes:\n  db_data:\n  assets_data::\nThis file is not needed. It should just represent your craft entry point.\nThis file is not needed. It should just represent your nuxt frontend.",{"id":2864,"title":2865,"titles":2866,"content":734,"level":740},"\u002Flibraries\u002Fcraft-query-api\u002Fdeployment\u002Fnuxt#prepare-coolify","Prepare Coolify",[351,2855],{"id":2868,"title":2869,"titles":2870,"content":2871,"level":2800},"\u002Flibraries\u002Fcraft-query-api\u002Fdeployment\u002Fnuxt#_1-create-a-project-and-add-aresource","1. Create a Project and Add a Resource",[351,2855,2865],"Log in to your Coolify dashboard.Then, create a new project.Next, you'll need to add a new resource. When you do that, choose \"Public Repository\" as your deployment method. Important Note: You really want to use Git-based resources here, not Docker. I know, it's confusing, and I messed this up the first time too. But trust me, Git-based is what you need for things like auto-deployments when you push to your repo, and those are super handy.",{"id":2873,"title":2874,"titles":2875,"content":2876,"level":2800},"\u002Flibraries\u002Fcraft-query-api\u002Fdeployment\u002Fnuxt#_2-set-up-the-repository-details","2. Set Up the Repository Details",[351,2855,2865],"Now, you'll have to give Coolify the URL of your repository on GitHub.For the Build Pack, make sure you select \"Docker Compose.\"Coolify should then automatically detect the docker-compose.yaml file in your repo. Double-check that it does! If it looks good, hit \"Continue.\"",{"id":2878,"title":2879,"titles":2880,"content":2881,"level":2800},"\u002Flibraries\u002Fcraft-query-api\u002Fdeployment\u002Fnuxt#_3-configure-the-web-container","3. Configure the Web Container",[351,2855,2865],"You'll need to assign a domain to your web container.And don't forget to tick that little checkbox in the screenshot! It's easy to miss.",{"id":2883,"title":2884,"titles":2885,"content":2886,"level":2800},"\u002Flibraries\u002Fcraft-query-api\u002Fdeployment\u002Fnuxt#_4-add-environment-variables","4. Add Environment Variables",[351,2855,2865],"In the left sidebar of Coolify, find Environment Variables.Add the following variables (Pro tip: If you enable the developer view in Coolify, it'll make adding these a lot faster!): CRAFT_APP_ID=CraftCMS--bc2c8733-c91a-46fe-87f3-b53b44d38c2e\nCRAFT_DB_DATABASE=db\nCRAFT_DB_DRIVER=mysql\nCRAFT_DB_PASSWORD=db\nCRAFT_DB_PORT=3306\nCRAFT_DB_SCHEMA=public\nCRAFT_DB_SERVER=db\nCRAFT_DB_TABLE_PREFIX=\nCRAFT_DB_USER=db\nCRAFT_ENVIRONMENT=production\nCRAFT_SECURITY_KEY=qxyV2FckKZEwr91pVthQNaATzkVE41Zd\nFALLBACK_IMAGE=\u002Fstatic\u002Fimages\u002Fplaceholder.png\nPLUGIN_IMAGERX=XXXXXXXXXXXXXXXXXXXXXXXX\nPLUGIN_NAVIGATION=XXXXXXXXXXXXXXXXXXXXXXXX\nPLUGIN_QUERY_API=XXXXXXXXXXXXXXXXXXXXXXXX\nPLUGIN_SEOMATIC=XXXXXXXXXXXXXXXXXXXXXXXX\nPRIMARY_SITE_URL=https:\u002F\u002Fcheap-craft.steelcity-creative.at\nPRIMARY_SITE_URL_DE=https:\u002F\u002Fcheap-craft.steelcity-creative.at\u002Fde\nPRIMARY_SITE_URL_ES=https:\u002F\u002Fcheap-craft.steelcity-creative.at\u002Fes\nNUXT_CRAFT_TOKEN=iIkWn1cMYA181On591yqdhJluAzI-r1c\nNUXT_ENVIRONMENT=production\nNUXT_PRIMARY_SITE_URL=https:\u002F\u002Fcheap-craft.steelcity-creative.at\nNUXT_PRIMARY_SITE_URL_DE=https:\u002F\u002Fcheap-craft.steelcity-creative.at\u002Fde\nNUXT_PRIMARY_SITE_URL_ES=https:\u002F\u002Fcheap-craft.steelcity-creative.at\u002Fes",{"id":2888,"title":2889,"titles":2890,"content":2891,"level":2800},"\u002Flibraries\u002Fcraft-query-api\u002Fdeployment\u002Fnuxt#_5-deploy","5. Deploy!",[351,2855,2865],"You can finally deploy your application! Just click the \"Deploy\" button in the top right corner.\nYou should now see an error of Nuxt in the frontend (\u002F) and an error of Craft in the backend (\u002Fadmin).",{"id":2893,"title":2894,"titles":2895,"content":2896,"level":2800},"\u002Flibraries\u002Fcraft-query-api\u002Fdeployment\u002Fnuxt#_6-import-database","6. Import Database",[351,2855,2865],"Now you can import an existing database into the db container or use the php craft setup command in the web container to start fresh.",{"id":2898,"title":2899,"titles":2900,"content":2901,"level":2800},"\u002Flibraries\u002Fcraft-query-api\u002Fdeployment\u002Fnuxt#_7-apply-changes-after-deployment","7. Apply Changes after Deployment",[351,2855,2865],"Go to the \"General Configuration\" and scroll down to \"Pre\u002FPost Deployment Commands.\"You can put commands here that you want to run automatically after a successful deployment. For me, it's usually something likephp craft up && php craft clear-caches\u002Fall, but you can also put the path to a script if you need to do something more complicated. html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .sQeJH, html code.shiki .sQeJH{--shiki-light:#032F62;--shiki-default:#DBEDFF;--shiki-dark:#DBEDFF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}",{"id":364,"title":107,"titles":2903,"content":2904,"level":713},[],"Learn how to install the Craft Quick Edit Craft CMS plugin.",{"id":2906,"title":716,"titles":2907,"content":2908,"level":719},"\u002Flibraries\u002Fcraft-quick-edit\u002Fget-started\u002Finstallation#requirements",[107],"Supports Craft CMS 4 and 5PHP 8 or later.",{"id":2910,"title":722,"titles":2911,"content":2912,"level":719},"\u002Flibraries\u002Fcraft-quick-edit\u002Fget-started\u002Finstallation#craft-plugin-store",[107],"To install Quick Edit, go to the Plugin Store in your Craft control panel, search for \"Quick Edit,\" and click the Install button.",{"id":2914,"title":727,"titles":2915,"content":2916,"level":719},"\u002Flibraries\u002Fcraft-quick-edit\u002Fget-started\u002Finstallation#composer",[107],"With ddev: ddev composer require samuelreichor\u002Fcraft-quick-edit &&\nddev craft plugin\u002Finstall quick-edit With php: composer require samuelreichor\u002Fcraft-quick-edit &&\nphp craft plugin\u002Finstall quick-edit html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":367,"title":34,"titles":2918,"content":2919,"level":713},[],"Learn how to use the Craft Quick Edit Craft CMS plugin. After installing the Plugin you are already set up. But you can give your authors an even better experience by styling the Quick Edit button.",{"id":2921,"title":2922,"titles":2923,"content":2924,"level":719},"\u002Flibraries\u002Fcraft-quick-edit\u002Fget-started\u002Fusage#custom-styling","Custom Styling",[34],"You can personalize the button’s look and feel by adding your own custom styles. The following example will animate the Quick Edit button in if a user hovers over the left corner. .craft-quick-edit {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 1.5rem;\n  height: 1.5rem;\n  z-index: 1000;\n\n  a.craft-quick-edit_link {\n    position: fixed;\n    top: 0.5rem;\n    left: 0.5rem;\n    right: unset;\n    background-color: black;\n    color: white;\n    padding: 6px;\n    text-decoration: none;\n    border-radius: 3px;\n    transform: translateY(-100px);\n    transition-property: opacity, transform;\n    transition-duration: 300ms;\n    opacity: 0;\n  }\n\n  &:hover .craft-quick-edit_link {\n    transform: translateX(0);\n    opacity: 1;\n  }\n}",{"id":2926,"title":2927,"titles":2928,"content":2929,"level":719},"\u002Flibraries\u002Fcraft-quick-edit\u002Fget-started\u002Fusage#csp-compatibility","CSP Compatibility",[34],"If your site uses Content Security Policy (CSP), you need to disable automatic injection and render the Quick Edit assets manually using Twig template tags. Set autoInject to false in your config or via the Control Panel.",{"id":2931,"title":2275,"titles":2932,"content":2933,"level":740},"\u002Flibraries\u002Fcraft-quick-edit\u002Fget-started\u002Fusage#template-tags",[34,2927],"{# Without nonce #}\n{{ craft.quickEdit.render() }}\n\n{# With nonce #}\n{{ craft.quickEdit.render(nonce) }}\n\n{# Full control - raw code without tags #}\n\u003Cdiv class=\"craft-quick-edit\">\u003C\u002Fdiv>\n\u003Cscript nonce=\"{{ nonce }}\">{{ craft.quickEdit.js()|raw }}\u003C\u002Fscript>\n\u003Cstyle nonce=\"{{ nonce }}\">{{ craft.quickEdit.css()|raw }}\u003C\u002Fstyle> CSP nonces and static caching don't work together. The nonce gets cached but the CSP header doesn't. Choose one approach:Static caching + no CSP nonce → {{ craft.quickEdit.render() }}CSP nonce + no static caching → {{ craft.quickEdit.render(nonce) }} html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":375,"title":261,"titles":2935,"content":2936,"level":713},[],"Learn how to configure the Craft Quick Edit Craft CMS plugin.",{"id":2938,"title":29,"titles":2939,"content":2940,"level":719},"\u002Flibraries\u002Fcraft-quick-edit\u002Fcofiguration\u002Fconfig#configuration",[261],"Create a quick-edit.php file under your \u002Fconfig directory with the following options available to you. You can also use multi-environment options to change these per environment. \u003C?php\n\nreturn [\n    '*' => [\n        'isGlobalDisabled' => false,\n        'targetBlank' => false,\n        'isStandalonePreview' => false,\n        'linkText' => '',\n        'alwaysEnabled' => false,\n        'autoInject' => true,\n    ],\n\n    'dev' => [\n        'alwaysEnabled' => true,\n    ]\n]; isGlobalDisabled: Disables Quick Edit globally. So no edit link will be shown.targetBlank: Opens the control panel edit link in a new window.isStandalonePreview: Enable this option to open the edit link in the standalone preview mode (Only available in > Craft 5.6.0).linkText: Hides the icon in the edit link and displays text instead.alwaysEnabled: Enable this option for development purposes only. It bypasses all user permissions and always displays the quick edit button.autoInject: Automatically injects the required JavaScript and CSS. Disable this for CSP compatibility and use the Twig template tags instead. This File will overwrite the settings from the control panel.",{"id":2942,"title":808,"titles":2943,"content":2944,"level":719},"\u002Flibraries\u002Fcraft-quick-edit\u002Fcofiguration\u002Fconfig#control-panel",[261],"You can also manage configuration settings through the Control Panel by visiting Settings → Quick Edit. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":356,"title":355,"titles":2946,"content":2947,"level":713},[],"Automatically adds an edit page link to your frontend.",{"id":2949,"title":1168,"titles":2950,"content":2951,"level":719},"\u002Flibraries\u002Fcraft-quick-edit#features",[355],"Automatically adds an edit page link to your frontend.Only visible if the logged-in user has permission to save the entry.Support for the Standalone Preview Mode added in Craft 5.6.0.Full Support for Multisites.Support for Craft Commerce Product Pages.Works perfectly with pages cached by Blitz.Completely customizable by css.No configuration required.",{"id":2953,"title":2954,"titles":2955,"content":2956,"level":719},"\u002Flibraries\u002Fcraft-quick-edit#enable-your-authors-a-better-experience","Enable your Authors a better Experience",[355],"This plugin is incredibly useful for authors managing content on a website. It allows authors to quickly access the editing interface of entries directly from the frontend, but only if they have the necessary permissions to save the content. This eliminates the need for navigating through the control panel, making content management faster and more efficient.",{"id":2958,"title":2474,"titles":2959,"content":2960,"level":719},"\u002Flibraries\u002Fcraft-quick-edit#how-it-works",[355],"After installing the Quick Edit plugin and logging into your control panel, a small button will appear in the right corner of your frontend. This button is only visible to logged-in users who have the necessary permission to edit the page. You can personalize the button’s look and feel by adding your own custom styles. Additionally, you can animate it easily using just CSS to match your site's design and create an even more interactive experience.",{"id":379,"title":378,"titles":2962,"content":2963,"level":713},[],"Foundation to build a query builder with your preferred JS framework.",{"id":2965,"title":1168,"titles":2966,"content":2967,"level":719},"\u002Flibraries\u002Fjs-craftcms-api#features",[378],"Support for Main Element Types: Query addresses, assets, entries and users.Helper for Preview Mode: Easily add preview mode to your headless setup.Typesafe: Built with typescript in mind.Easy Adaptable: You can easily build your own custom wrapper with that core logic.",{"id":2969,"title":440,"titles":2970,"content":2971,"level":719},"\u002Flibraries\u002Fjs-craftcms-api#examples",[378],"Want to see how it works? import { buildCraftQueryUrl } from '@query-api\u002Fjs';\n\n\u002F\u002F Build URL for fetching a single address\nconst url = buildCraftQueryUrl('entries')\n  .id(1)\n  .status('active')\n  .siteId(1)\n  .buildBaseUrl('one');\n\u002F\u002F Result: \u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery?elementType=addresses&id=1&status=active&siteId=1&one=1 It is as simple as that. 🚀",{"id":2973,"title":2974,"titles":2975,"content":2976,"level":719},"\u002Flibraries\u002Fjs-craftcms-api#further-resources","Further Resources",[378],"Craft Query API: A Craft CMS Plugin, that powers this stuff.Vue SDK: A package to use the query builder in Vue.Nuxt SDK: A package to use the query builder in Nuxt.React SDK: A package to use the query builder in React.Next SDK: A package to use the query builder in Next.js. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":383,"title":107,"titles":2978,"content":2979,"level":713},[],"Learn how to install the JS SDK package.",{"id":2981,"title":716,"titles":2982,"content":2983,"level":719},"\u002Flibraries\u002Fjs-craftcms-api\u002Finstall#requirements",[107],"The Craft Query API plugin must be installed and configured.Node > 20",{"id":2985,"title":2555,"titles":2986,"content":2987,"level":719},"\u002Flibraries\u002Fjs-craftcms-api\u002Finstall#install",[107],"npm install @query-api\u002Fjs Boom, finished. 🚀 html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":387,"title":386,"titles":2989,"content":2990,"level":713},[],"Get an overview of all the methods of @query-api\u002Fjs. This API allows building urls for Craft CMS elements (addresses, assets, entries, and users) by providing a querybuilder.",{"id":2992,"title":2532,"titles":2993,"content":2994,"level":719},"\u002Flibraries\u002Fjs-craftcms-api\u002Fmethods#supported-element-types",[386],"Each element type has its own set of available methods. This ensures precise control and great type safty. AddressesAssetsEntriesUsers Categories, Tags and Globals are not supported because they may be deprecated in the future.",{"id":2996,"title":2997,"titles":2998,"content":2999,"level":719},"\u002Flibraries\u002Fjs-craftcms-api\u002Fmethods#special-methods","Special Methods",[386],"These are methods available for all element types and are not native in Craft CMS. When the type is defined as number[], you can always include operator strings such as not or and. You can find out more about types and methodes in the source code. MethodDescriptionTypefieldsSelect specific fields to retrieve.string or string[]includeAllEntryWhether to include the full data of entries or just the minimal fields (title, URI, ID, and slug).booleanbuildBaseUrlBuild the url for one() or all()one or all If you use the includeAllEntry param, be sure that you don't have circular entry relations. This would end up in an endless loop.",{"id":3001,"title":3002,"titles":3003,"content":3004,"level":719},"\u002Flibraries\u002Fjs-craftcms-api\u002Fmethods#address-methods","Address Methods",[386],"MethodDescriptionTypeaddressLine1Filter by first line of address.stringaddressLine2Filter by second line of address.stringaddressLine3Filter by third line of address.stringfixedOrderMaintain order of id().booleanfullNameFilter by full name.stringidFilter by unique identifier.number or number[]limitLimit the number of results returned.numberlocalityFilter by city or locality.stringoffsetSet an offset for pagination.numberorderByDefine sorting order.stringorganizationFilter by organization name.stringsearchSearch by string.string",{"id":3006,"title":3007,"titles":3008,"content":3009,"level":719},"\u002Flibraries\u002Fjs-craftcms-api\u002Fmethods#asset-methods","Asset Methods",[386],"MethodDescriptionTypefilenameFilter by file name.stringfixedOrderMaintain order of id().booleanidFilter by unique identifier.number or number[]kindFilter by asset type (e.g., \"image\").stringlimitLimit the number of results returned.numberoffsetSet an offset for pagination.numberorderByDefine sorting order.stringsearchSearch by string.stringsiteFilter by site handle.stringsiteIdFilter by site ID.number or number[]volumeFilter by asset volume.string",{"id":3011,"title":3012,"titles":3013,"content":3014,"level":719},"\u002Flibraries\u002Fjs-craftcms-api\u002Fmethods#entry-methods","Entry Methods",[386],"MethodDescriptionTypefixedOrderMaintain order of id().booleanidFilter by unique identifier.number or number[]levelFilter by the level.number or number[]limitLimit the number of results returned.numberoffsetSet an offset for pagination.numberorderByDefine sorting order.stringpostDateFilter by post date.stringrelatedToGet related elements.RelatedToParam (use ids instead of entries)notRelatedToGet NOT related elements.RelatedToParam (use ids instead of entries)andRelatedToGet AND related elements.RelatedToParam (use ids instead of entries)andNotRelatedToGet AND NOT related elements.RelatedToParam (use ids instead of entries)searchSearch by string.stringsectionFilter by section handle.string or string[]sectionIdFilter by section id.number or number[]siteFilter by site handle.stringsiteIdFilter by site ID.number or number[]slugFilter by entry slug.stringstatusFilter by status.EntryStatusString or EntryStatusString[]typeFilter by entryType.string or string[]uriFilter by entry URI.string or string[]",{"id":3016,"title":3017,"titles":3018,"content":3019,"level":740},"\u002Flibraries\u002Fjs-craftcms-api\u002Fmethods#user-methods","User Methods",[386,3012],"MethodDescriptionTypeadminFilter if user is admin.emailFilter by email address.stringfixedOrderMaintain order of id().booleanfullNameFilter by full name.stringgroupFilter by user group.string or string[]groupIdFilter by user group ID.number or number[]hasPhotoFilter users with profile photos.booleanidFilter by unique identifier.number or number[]limitLimit the number of results returned.numberoffsetSet an offset for pagination.numberorderByDefine sorting order.stringsearchSearch by string.stringstatusFilter by status.UserStatusString or UserStatusString[]",{"id":395,"title":394,"titles":3021,"content":3022,"level":713},[],"Learn how to use the JS SDK package.",{"id":3024,"title":3025,"titles":3026,"content":3027,"level":719},"\u002Flibraries\u002Fjs-craftcms-api\u002Fusage\u002Fusage#buildcraftqueryurl","buildCraftQueryUrl",[394],"buildCraftQueryUrl is the core function for building query URLs. It takes an elementType as an argument and allows you to chain various methods to specify query parameters. This function makes it easy to generate URLs to fetch specific data from Craft CMS.",{"id":3029,"title":3030,"titles":3031,"content":3032,"level":740},"\u002Flibraries\u002Fjs-craftcms-api\u002Fusage\u002Fusage#example-usage","Example Usage",[394,3025],"import { buildCraftQueryUrl } from '@query-api\u002Fjs';\n\n\u002F\u002F Build URL for fetching a single address\nconst url = buildCraftQueryUrl('addresses').id(1).buildBaseUrl('one');\n\u002F\u002F Result: \u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery?elementType=addresses&id=1&one=1\n\n\u002F\u002F Build URL for fetching a single asset\nconst url = buildCraftQueryUrl('assets').id(1).buildBaseUrl('one');\n\u002F\u002F Result: \u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery?elementType=assets&id=1&one=1\n\n\u002F\u002F Build URL for fetching a single entry\nconst url = buildCraftQueryUrl('entries').id(1).buildBaseUrl('one');\n\u002F\u002F Result: \u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery?elementType=entries&id=1&one=1\n\n\u002F\u002F Build URL for fetching a single user\nconst url = buildCraftQueryUrl('users').id(1).buildBaseUrl('one');\n\u002F\u002F Result: \u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery?elementType=users&id=1&one=1 For a full list of available methods, refer to the API documentation. You can use the generated URL to make a fetch request to your Craft CMS backend. Just be sure to add a Authorization Header with a valid Bearer Token to your request.",{"id":3034,"title":3035,"titles":3036,"content":3037,"level":719},"\u002Flibraries\u002Fjs-craftcms-api\u002Fusage\u002Fusage#preview-mode","Preview Mode",[394],"buildCraftQueryUrl() automatically handles preview mode by injecting the necessary token into the URL. This feature ensures that you can easily preview content without additional setup. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":399,"title":398,"titles":3039,"content":3040,"level":713},[],"Learn how to build a wrapper around the JS SDK package.",{"id":3042,"title":3043,"titles":3044,"content":3045,"level":719},"\u002Flibraries\u002Fjs-craftcms-api\u002Fusage\u002Fadvanced-usage#custom-wrapper-example","Custom Wrapper Example",[398],"The following example demonstrates how to build a custom wrapper for buildCraftQueryUrl() in Vue.\nThis wrapper, useCraftUrlBuilder, adds custom methods and handles URLs more flexibly. import { buildCraftQueryUrl } from '@query-api\u002Fjs';\nimport type { ElementType, ExecutionMethod } from '@query-api\u002Fjs';\n\nexport function useCraftUrlBuilder\u003CT extends ElementType>(elementType: T) {\n  const queryBuilder = buildCraftQueryUrl(elementType); \u002F\u002F Initialize the core builder\n\n  const baseUrl = '' \u002F\u002F primary site url of your craft system\n  const debug = false \n\n  return {\n    ...queryBuilder,\n\n    \u002F\u002F Custom method to build the full URL\n    buildUrl(execOpt: ExecutionMethod) {\n      const queryUrl = queryBuilder.buildBaseUrl(execOpt);\n      const url = `${baseUrl}${queryUrl}`;\n\n      if (debug) {\n        console.log('The built URL is: ' + url);\n      }\n      return url;\n    },\n  };\n}",{"id":3047,"title":3048,"titles":3049,"content":3050,"level":740},"\u002Flibraries\u002Fjs-craftcms-api\u002Fusage\u002Fadvanced-usage#explanation","Explanation",[398,3043],"queryBuilder: Uses buildCraftQueryUrl() to initialize the core query builder.baseUrl and debug: These values should come from a global config or env file.buildUrl(execOpt: ExecutionMethod): Extends the base query builder with a buildUrl method, which generates the full URL by appending baseUrl and, if debug is enabled, logs the URL to the console. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":403,"title":402,"titles":3052,"content":3053,"level":713},[],"A Nuxt module for using the Craft CMS query builder in Nuxt.",{"id":3055,"title":1168,"titles":3056,"content":3057,"level":719},"\u002Flibraries\u002Fnuxt-craftcms#features",[402],"Query builder: Easily build and execute queries directly from Nuxt, enabling flexible, real-time data retrieval from Craft CMSBuilt in Helper Components: Connect your data directly with your Vue components, to speed up development.Get Only the Data You Need: Avoid overfetching by using a custom function in the query builder to select only the fields you require.Pretty Json: Json Transformer are in place to prettify the response.Support for Main Element Types: Query addresses, assets, entries and users.Full Typescript Suppport: Craft Query Builder with typescript support pretty cool hah?😎Multisite Composables: Built in composables to support Craft Multisites.SeoMatic Composables: Connect SeoMatic with Nuxt fast with the built in SeoMatic composables.",{"id":3059,"title":440,"titles":3060,"content":3061,"level":719},"\u002Flibraries\u002Fnuxt-craftcms#examples",[402],"Want to see how it works? const { data, error } = await useCraftEntry()\n  .section('news')\n  .fields(['title']) \u002F\u002F add more field handles if you like\n  .limit(3)\n  .all()\n\nif (error.value) {\n  console.error(error.value)\n} It is as simple as that. 🚀 The response will be three entries of the section news.",{"id":3063,"title":2974,"titles":3064,"content":3065,"level":719},"\u002Flibraries\u002Fnuxt-craftcms#further-resources",[402],"Craft Query API: A Craft CMS Plugin, that powers this stuff.Vue SDK: A package to use the query builder in Vue.JS SDK: Foundation to build a query builder with your preferred JS framework. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":411,"title":274,"titles":3067,"content":3068,"level":713},[],"An introduction to the @query-api\u002Fnuxt SDK for Nuxt. The @query-api\u002Fnuxt introduces a powerful query builder to your Nuxt app, allowing you to easily fetch data from Craft CMS,\nsimilar to how you would query in Twig. It allows you to connect your Craft CMS sections and entry types to Vue components, making it easy to render dynamic content in your Nuxt applications.",{"id":3070,"title":716,"titles":3071,"content":3072,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fintroduction#requirements",[274],"The Craft Query API plugin must be installed and properly configured in Craft CMS.Node.js - 20.x or newer (but I recommend the active LTS release)Nuxt > 3 is required (Nuxt 4 is already supported).",{"id":3074,"title":2532,"titles":3075,"content":3076,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fintroduction#supported-element-types",[274],"AddressesAssetsEntriesUsers",{"id":3078,"title":2537,"titles":3079,"content":3080,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fintroduction#need-help",[274],"If you encounter bugs or have feature requests, please submit an issue. Your feedback helps improve the module!",{"id":415,"title":414,"titles":3082,"content":3083,"level":713},[],"Use the create-query-api CLI to scaffold a new @query-api\u002Fnuxt project.",{"id":3085,"title":716,"titles":3086,"content":3072,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fquick-start#requirements",[414],{"id":3088,"title":107,"titles":3089,"content":3090,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fquick-start#installation",[414],"The fastest way to get started is with the create-query-api command-line tool. It scaffolds a complete project for you, including a pre-configured Craft CMS and a Nuxt frontend. Open your terminal and run the following command: npx create-query-api@latest query-api-nuxt --template nuxt",{"id":3092,"title":3093,"titles":3094,"content":3095,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fquick-start#manual-installation","Manual Installation",[414],"If you want to integrate the @query-api\u002Fnuxt SDK into an existing Nuxt project or want to understand the setup process step by step, you can head over to the Manual Setup Guide html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":419,"title":418,"titles":3097,"content":3098,"level":713},[],"Learn how to install and configure the @query-api\u002Fnuxt package for your Nuxt project. This guide is for developers who want to integrate the Query API into an existing Nuxt project or for those who want to understand the setup process step-by-step. If you prefer to dive straight into code, you can check out the Nuxt demo project on GitHub.",{"id":3100,"title":1390,"titles":3101,"content":3102,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fmanual-setup#prerequisites",[418],"Before you begin, please ensure you have the following set up:",{"id":3104,"title":3105,"titles":3106,"content":3107,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fmanual-setup#_2-nuxt-app","2. Nuxt App",[418,1390],"You'll need a Nuxt application. If you're starting from scratch, you can create one inside your Craft project's root folder. npm create nuxt frontend You can now open the frontend directory in your code editor to begin the setup.",{"id":3109,"title":3110,"titles":3111,"content":3112,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fmanual-setup#installation-and-folder-structure","Installation and Folder Structure",[418],"First, install the @query-api\u002Fnuxt SDK in your Nuxt project. npm install @query-api\u002Fnuxt Next, we will create the following folder and file structure inside the src directory. This structure helps organize your code by separating concerns. ├── app\n│   ├── components\n│   │   ├── content\n│   │   │   ├── BlockHeadline.vue\n│   │   │   ├── ViewHome.vue\n│   ├── pages\n│   │   └── [...slug].vue\n│   ├── types\n│   │   └── base.ts\n│   └── app.vue\n├── .env\n├── nuxt.config.ts",{"id":3114,"title":3115,"titles":3116,"content":3117,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fmanual-setup#environment-variables","Environment Variables",[418],"Create a .env file in the root of your Nuxt project to store your Craft CMS connection details. # Allows Node.js to connect to local development URLs (e.g., DDEV).\n# Remove this in production.\nNODE_TLS_REJECT_UNAUTHORIZED=0\n\n# The base URL of your Craft CMS backend.\nNUXT_CRAFT_BASE_URL=https:\u002F\u002Fquery-api-starter.ddev.site\n\n# The bearer token you generated in the Query API plugin settings.\nNUXT_CRAFT_AUTH_TOKEN=\"Bearer sqKTlMFsky_OeJVeDfnps75b2Gny4NBG\" # Default of create-query-api starter template You can find\u002Fcreate the bearer token under \u002Fadmin\u002Fquery-api\u002Ftokens in the control panel.",{"id":3119,"title":3120,"titles":3121,"content":734,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fmanual-setup#generate-types","Generate Types",[418],{"id":3123,"title":3124,"titles":3125,"content":3126,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fmanual-setup#query-api-configuration","Query API Configuration",[418],"We can configure the Query API in the nuxt.config.ts file. \u002F\u002F https:\u002F\u002Fnuxt.com\u002Fdocs\u002Fapi\u002Fconfiguration\u002Fnuxt-config\nexport default defineNuxtConfig({\n  compatibilityDate: '2025-05-15',\n  devtools: { enabled: true },\n  modules: ['@query-api\u002Fnuxt'],\n\n  craftcms: {\n    baseUrl: process.env.NUXT_CRAFT_BASE_URL ?? '',\n    authToken: process.env.NUXT_CRAFT_AUTH_TOKEN ?? '',\n    debug: false,\n    siteMap: [\n      {\n        handle: 'en',\n        path: '\u002F',\n        origin: 'http:\u002F\u002Flocalhost:3000',\n        id: 1,\n      },\n      {\n        handle: 'de',\n        path: '\u002Fde',\n        origin: 'http:\u002F\u002Flocalhost:3000\u002Fde',\n        id: 2,\n      },\n      {\n        handle: 'es',\n        path: '\u002Fes',\n        origin: 'http:\u002F\u002Flocalhost:3000\u002Fes',\n        id: 3,\n      },\n    ],\n  },\n})",{"id":3128,"title":432,"titles":3129,"content":3130,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fmanual-setup#content-driven-components",[418],"These are the Vue components that will render your Craft CMS content. We recommend placing them in a dedicated components\u002Fcontent directory to distinguish them from general-purpose UI components. Here is an example of a component for a headline entry type that is used in a matrix block. \u003Cscript setup lang=\"ts\">\nimport type { CraftEntryTypeHeadline } from '~\u002Ftypes\u002Fbase'\n\nconst props = defineProps\u003CCraftEntryTypeHeadline>()\n\n\u002F\u002F This component renders a headline from a Matrix block.\n\u002F\u002F The props are fully typed based on the generated `base.ts` file.\n\u002F\u002F The `selectHeadlineTag` field is a dropdown in Craft,\n\u002F\u002F allowing content editors to choose the HTML tag (e.g., h1, h2).\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Ccomponent :is=\"props.selectHeadlineTag.value\">\n    {{ props.title }}\n  \u003C\u002Fcomponent>\n\u003C\u002Ftemplate> Next, create the main view component for your home section. \u003Cscript setup lang=\"ts\">\nimport type { CraftPageHome } from '~\u002Ftypes\u002Fbase'\n\nconst props = defineProps\u003CCraftPageHome>()\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003C!-- `translatablePlainText` is a field from our Craft entry. -->\n    \u003Ch1>{{ props.translatablePlainText }}\u003C\u002Fh1>\n    \u003CRichText v-if=\"props.richText\" :text=\"props.richText\" \u002F>\n    \u003C!-- The CraftArea component dynamically renders entries of matrix blocks -->\n    \u003CCraftArea v-if=\"props.contentBuilder\" :content=\"props.contentBuilder\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>",{"id":3132,"title":3133,"titles":3134,"content":3135,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fmanual-setup#root-entry-point","Root Entry Point",[418],"Next let's create some NuxtLinks in the app.vue file. This will help to test, if everything works on both client and server side navigation. \u003Ctemplate>\n  \u003Cdiv>\n    \u003Cul>\n      \u003Cli>\u003CNuxtLink href=\"\u002F\">Home\u003C\u002FNuxtLink>\u003C\u002Fli>\n      \u003Cli>\u003CNuxtLink href=\"\u002Fde\">Home DE\u003C\u002FNuxtLink>\u003C\u002Fli>\n      \u003Cli>\u003CNuxtLink href=\"\u002Fes\">Home ES\u003C\u002FNuxtLink>\u003C\u002Fli>\n    \u003C\u002Ful>\n    \u003CNuxtPage \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>",{"id":3137,"title":3138,"titles":3139,"content":3140,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fmanual-setup#catch-all-route","Catch-All Route",[418],"This dynamic route is the core of the page rendering logic. It captures every incoming URL, fetches the corresponding entry from Craft CMS, and renders it using the CraftPage component. \u003Cscript setup lang=\"ts\">\nimport type { ContentMapping } from '@query-api\u002Fnuxt'\nimport { CraftNotImplemented } from '#components'\nimport ViewHome from '~\u002Fcomponents\u002Fcontent\u002FViewHome.vue'\nimport BlockHeadline from '~\u002Fcomponents\u002Fcontent\u002FBlockHeadline.vue'\nimport type { CraftPageBase } from '~\u002Ftypes\u002Fbase'\n\nconst uri = useCraftUri()\nconst currentSite = useCraftCurrentSite()\n\nconst { data: entry, error } = useCraftEntry\u003CCraftPageBase>()\n  .uri(uri.value)\n  .siteId(currentSite.value.id)\n  .one()\n\nif (error.value) {\n  throw new Error(error.value.message)\n}\n\nconst contentMapping: ContentMapping = {\n  pages: {\n    home: ViewHome,\n    'news:news': CraftNotImplemented,\n  },\n  components: {\n    headline: BlockHeadline,\n    text: CraftNotImplemented,\n    imageAndText: CraftNotImplemented,\n    image: CraftNotImplemented,\n  },\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CCraftPage v-if=\"entry\" :content=\"entry\" :config=\"contentMapping\" \u002F>\n\u003C\u002Ftemplate> With this setup, navigating to any page on your Nuxt site will trigger a fetch to your Craft CMS backend, and the correct content will be rendered automatically. It's as simple as that! 🚀",{"id":3142,"title":3143,"titles":3144,"content":3145,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fmanual-setup#anything-missing","Anything missing?",[418],"If you have questions, run into issues, or have ideas for improvements, your feedback is very welcome! Please don't hesitate to open an issue on GitHub. Whether it's a bug report, a feature request, or a general suggestion, your input helps make this project better for everyone. html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":422,"title":29,"titles":3147,"content":3148,"level":713},[],"Learn how to configure the @query-api\u002Fnuxt package for your Nuxt application. The @query-api\u002Fnuxt package can be configured in the nuxt.config.ts file.",{"id":3150,"title":3151,"titles":3152,"content":3153,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fconfiguration#example-configuration","Example Configuration",[29],"This example shows a minimal setup for a Nuxt application using the Query API: \u002F\u002F https:\u002F\u002Fnuxt.com\u002Fdocs\u002Fapi\u002Fconfiguration\u002Fnuxt-config\nexport default defineNuxtConfig({\n  modules: ['@query-api\u002Fnuxt'],\n\n  craftcms: {\n    baseUrl: 'https:\u002F\u002Fyour-craft-backend.ddev.site',\n    authToken: 'Bearer yourBearerToken',\n  },\n})",{"id":3155,"title":3156,"titles":3157,"content":734,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fconfiguration#configuration-options","Configuration Options",[29],{"id":3159,"title":3160,"titles":3161,"content":3162,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fconfiguration#baseurl","baseUrl",[29,3156],"The base URL of your Craft CMS backend where the Query API is running. Type: stringRequired: trueExample: https:\u002F\u002Fyour-craft-backend.ddev.site",{"id":3164,"title":3165,"titles":3166,"content":3167,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fconfiguration#authtoken","authToken",[29,3156],"The authentication token for accessing the Craft CMS API. You can generate this Bearer token in the Query API plugin settings in your Craft control panel. Type: stringRequired: trueExample: Bearer yourSecretToken...",{"id":3169,"title":3170,"titles":3171,"content":3172,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fconfiguration#sitemap","siteMap",[29,3156],"The siteMap option allows you to define an array of your Craft Sites. This is essential for multi-site setups, as it enables the library to correctly resolve sites based on the request URL. Type: CraftSite[]Default: []Example: \u002F\u002F Define the structure for a Craft site object.\ntype CraftSite = {\n  handle: string\n  origin: string\n  path: string\n  id?: number\n  label?: string\n  lang?: string\n  primary?: boolean\n}\n\n\u002F\u002F Example siteMap configuration.\nsiteMap: [\n  {\n    handle: 'en',\n    path: '\u002F',\n    origin: 'http:\u002F\u002Flocalhost:3000',\n    id: 1,\n    primary: true,\n  },\n  {\n    handle: 'de',\n    path: '\u002Fde',\n    origin: 'http:\u002F\u002Flocalhost:3000', \u002F\u002F Origin can be the same for path-based multi-site\n    id: 2,\n  },\n]",{"id":3174,"title":902,"titles":3175,"content":3176,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fconfiguration#debug",[29,3156],"Enable debug mode to log additional information to the console. This is useful during development for troubleshooting data fetching and component mapping. Type: booleanDefault: false",{"id":3178,"title":3179,"titles":3180,"content":3181,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fconfiguration#enableentrytypemapping","enableEntryTypeMapping",[29,3156],"By default, the library can map pages using a sectionHandle:entryTypeHandle format (e.g., news:article). If you prefer to only map by section handle, you can set this to false. Type: booleanDefault: true",{"id":3183,"title":3184,"titles":3185,"content":3186,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fconfiguration#sitedetectionmode","siteDetectionMode",[29,3156],"This option controls how the current site is identified in a multi-site Craft CMS setup. path: (Default) Detects the site from the URL path (e.g., \u002Fde\u002Fnews).origin: Detects the site from the domain or origin (e.g., german-site.com).Type: 'path' | 'origin'Default: 'path'",{"id":3188,"title":3189,"titles":3190,"content":3191,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fconfiguration#caching","caching",[29,3156],"Enables client side caching for all composables that fetch data on the cient side. Unfortunately this can't use the SSR payload that is generated by Nitro with SWR or ISR.\nThis may change soon with this (PR)https:\u002F\u002Fgithub.com\u002Fnuxt\u002Fnuxt\u002Fpull\u002F33467. Type: boolean | { ttl: number }Default: falseExample: caching: {\n  ttl: 3600 \u002F\u002F cache for 1h\n}\ncaching: true \u002F\u002F cache for this session\ncaching: false \u002F\u002F disable caching",{"id":3193,"title":3194,"titles":3195,"content":3196,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fget-started\u002Fconfiguration#default-configuration","Default Configuration",[29],"This is the default configuration for the @query-api\u002Fnext package. export const defaultCraftOptions = {\n  baseUrl: '',\n  authToken: '',\n  debug: false,\n  enableEntryTypeMapping: true,\n  siteDetectionMode: siteDetectionModes.PATH,\n  siteMap: [],\n  caching: false,\n} html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}",{"id":429,"title":394,"titles":3198,"content":3199,"level":713},[],"Learn how you can use the Nuxt SDK module. Let's dive in and use that thing! This module offers two flexible methods for integrating Craft CMS data into your Nuxt application.",{"id":3201,"title":432,"titles":3202,"content":3203,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fbasic-usage#content-driven-components",[394],"You can map Craft CMS section handles and matrix block handles to Vue components, enabling the module to automatically render pages and blocks based on your\ncontent structure. This method simplifies data rendering by letting the module handle the content logic. You can find detailed instructions on how to connect your components here.",{"id":3205,"title":3206,"titles":3207,"content":3208,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fbasic-usage#manually-queries","Manually Queries",[394],"You can also use the built-in query builder to dynamically fetch Craft CMS data. This approach allows you to construct precise queries and\nretrieve content as you need it. You can find detailed instructions on how manual queries work here.",{"id":433,"title":432,"titles":3210,"content":3211,"level":713},[],"Learn how to map Craft CMS data with your Nuxt components This guide explains the steps to connect your Vue components with data from Craft CMS. We’ll set up a catch-all route, create a mapping object for components, query data,\nand use the \u003CCraftPage\u002F> and \u003CCraftArea\u002F> components to display content dynamically.",{"id":3213,"title":3214,"titles":3215,"content":3216,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fconnect-components#catch-all-route","Catch all route",[432],"To support dynamic URLs in your Nuxt app, add a catch-all route by creating a file named ~\u002Fpages\u002F[...slug].vue.\nThis route will capture all URLs and allow you to dynamically render the corresponding content.",{"id":3218,"title":3219,"titles":3220,"content":3221,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fconnect-components#mapping-object","Mapping Object",[432],"Define a mapping object in the ~\u002Fpages\u002F[...slug].vue file. This object connects each Craft CMS section handle to a Vue page component and each field handle to a specific\nVue component. This setup allows the correct component to render based on the Craft CMS data. For example: \u003Cscript setup lang=\"ts\">\n  import type { ContentMapping } from '@query-api\u002Fnuxt'\n  import Home from '~\u002Ftemplates\u002Fpages\u002Fhome.vue'\n  import News from '~\u002Ftemplates\u002Fpages\u002Fnews.vue'\n\n  import ImageText from '~\u002Ftemplates\u002Fcomponents\u002FimageText.vue'\n  import Headline from '~\u002Ftemplates\u002Fcomponents\u002Fheadline.vue'\n\n  const mapping: ContentMapping = {\n    pages: {\n      home: Home, \u002F\u002F 'home' is the section handle of the Craft CMS section, 'Home' is the Vue component.\n      news: News,\n    },\n    components: {\n      imageText: ImageText,\n      headline: Headline,\n    },\n  }\n\u003C\u002Fscript>",{"id":3223,"title":3224,"titles":3225,"content":3226,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fconnect-components#working-with-entry-types","Working with Entry Types",[432,3219],"When enableEntryTypeMapping is set to true in your nuxt.config.ts, you can link your Craft entries using the format sectionHandle:entryTypeHandle. If the entry type handle is default or matches the section handle, you don’t need to explicitly define the :entryTypeHandle. const mapping: ContentMapping = {\n  pages: {\n    home: Home, \u002F\u002F equivalent to home:default or home:home\n    'news:default': News, \u002F\u002F equivalent to news or news:news\n    'news:reference': News, \u002F\u002F section handle = news, entry type handle = reference\n  },\n  components: {\n    \u002F\u002F additional components\n  },\n};",{"id":3228,"title":3229,"titles":3230,"content":3231,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fconnect-components#query-data","Query Data",[432],"Use the useCraftQuery() composable to fetch data from Craft CMS. Combine this with Nuxt’s useRoute() composable to get the correct URI based on the route parameters. Here’s what you can add the code to [...slug].vue: const uri = useCraftUri();\nconst { data, error } = await useCraftQuery('entries').uri(uri.value).one()\n\nif (error.value) {\n  console.error(error.value)\n}\n\nconsole.log(data.value) To easily enable multisite support, refer to the Multisite Example.",{"id":3233,"title":3234,"titles":3235,"content":3236,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fconnect-components#display-page","Display Page",[432],"To display the page data, use the \u003CCraftPage\u002F> component in [...slug].vue. This component automatically renders defined pages based on the mapping configuration and data received from Craft CMS. To find out more about the \u003CCraftPage\u002F> check out the docs. Here’s what a full example file might look like: \u003Cscript setup lang=\"ts\">\n  import { CraftNotImplemented, type ContentMapping } from '@query-api\u002Fnuxt'\n  import Home from '~\u002Ftemplates\u002Fpages\u002Fhome.vue';\n  import News from '~\u002Ftemplates\u002Fpages\u002Fnews.vue';\n\n  import Headline from '~\u002Ftemplates\u002Fcomponents\u002Fheadline.vue'\n\n  const mapping: ContentMapping = {\n    pages: {\n      'home': Home,\n      'news:home': News,\n    },\n    components: {\n      'block_imageText': CraftNotImplemented,\n      'block_headline': Headline,\n    }\n  };\n\n  const uri = useCraftUri()\n  const { data, error } = await useCraftQuery('entries').uri(uri.value).one()\n\n  if(error.value) {\n    console.error(error.value)\n  }\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003CCraftPage v-if=\"data\" :config=\"mapping\" :content=\"data\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate> This setup should render the correct Nuxt page based on the Craft CMS section handle. To verify the data structure Craft CMS sends to your page, you can add the following code to inspect the data in home.vue: \u003Ctemplate>\n  \u003Ch1>Home\u003C\u002Fh1>\n  \u003Cpre>\n    {{ $attrs }}\n  \u003C\u002Fpre>\n\u003C\u002Ftemplate>",{"id":3238,"title":3239,"titles":3240,"content":3241,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fconnect-components#display-components","Display Components",[432],"To connect Matrix blocks with Vue components, use the \u003CCraftArea\u002F> component. This component will dynamically render\nVue components based on the content provided from Craft CMS. Example: \u003Cscript setup lang=\"ts\">\n  const props = defineProps({\n    metadata: {\n      type: Object,\n      required: true,\n    },\n    contentBuilder: {\n      type: Object,\n      required: true,\n    },\n    sectionHandle: {\n      type: String,\n      required: true,\n    },\n    title: {\n      type: String,\n      required: true,\n    },\n  });\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Ch1>{{ props.title }}\u003C\u002Fh1>\n    \u003CCraftArea v-if=\"props.contentBuilder\" :content=\"props.contentBuilder\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate> To find out more about the \u003CCraftArea\u002F> check out the docs. html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":437,"title":436,"titles":3243,"content":3244,"level":713},[],"Learn how to manually query Craft CMS data in Nuxt In this guide, we’ll cover how to use manual queries with the useCraftQuery() composable in Nuxt.\nThis approach gives you direct control over the data you fetch, allowing you to display specific fields and customize your queries.",{"id":3246,"title":3247,"titles":3248,"content":3249,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fmanuel-queries#write-a-query","Write a query",[436],"Using useCraftQuery(), we can use the Craft CMS query builder for specific data. Here’s how to set up a query to fetch a list of related news articles: This query underneath will return three entries from the news section, containing only the title field.\nThe await keyword is used to wait for the query to complete, and any errors are logged. const { data, error } = await useCraftQuery('entries')\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()\n\nif (error.value) {\n  console.error(error.value)\n}\n\nconsole.log(data.value) Find out more about the available query methodes in the useCraftQuery() docs. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":441,"title":440,"titles":3251,"content":3252,"level":713},[],"Learn how to use the Nuxt SDK module through an example.",{"id":3254,"title":3255,"titles":3256,"content":3257,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fexamples#full-example","Full Example",[440],"For a complete setup, check out the full example here.\nThis monorepo includes a Craft and Nuxt setup where you can test around locally. Clone Repo: git clone git@github.com:samuelreichor\u002Fcraft-nuxt-starter.git",{"id":3259,"title":3260,"titles":3261,"content":3262,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fexamples#starter-template","Starter template",[440],"The fastest way to get started is with the create-query-api command-line tool. It scaffolds a complete project for you, including a pre-configured Craft CMS and a Nuxt frontend. Open your terminal and run the following command: npx create-query-api@latest query-api-nuxt --template nuxt This command uses this template on GitHub",{"id":3264,"title":3265,"titles":3266,"content":734,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fexamples#multisite-example","Multisite Example",[440],{"id":3268,"title":3269,"titles":3270,"content":3271,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fexamples#adding-multisites","Adding Multisites",[440,3265],"First, ensure that you have defined your multisite configuration in nuxt.config.ts: export default defineNuxtConfig({\n  craftcms: {\n    baseUrl: 'https:\u002F\u002Fexample.ddev.site',\n    authToken: 'owiwrtgnfsjhsadgsdagf',\n    siteMap: [\n      {\n        handle: 'en',\n        origin: 'http:\u002F\u002Flocalhost:3000',\n        id: 1,\n      },\n      {\n        handle: 'de',\n        origin: 'http:\u002F\u002Flocalhost:3000\u002Fde',\n        id: 2,\n      },\n    ],\n  }\n}); Once configured, you can use the useCraftFullUrl and useCraftCurrentSite composables to query your data.",{"id":3273,"title":3274,"titles":3275,"content":3276,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fusage\u002Fexamples#querying-data","Querying Data",[440,3265],"In your catch-all route ([...slug].vue), you can retrieve the relevant data using the provided composables. Here’s an example: const uri = useCraftUri();\nconst currentSite = useCraftCurrentSite();\nconst { data, error } = await useCraftQuery('entries')\n  .uri(uri.value)\n  .site(currentSite.value.handle)\n  .one();\n\nif (error.value) {\n  console.error(error.value);\n} This approach ensures that your queries are multisite-aware, dynamically resolving the correct URI and site handle based on the current request. 🚀 html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}",{"id":450,"title":449,"titles":3278,"content":3279,"level":713},[],"Learn how to use the useCraftQuery composable. This composable provides a simple way to fetch data from your Craft CMS Backend.\nIt leverages the JS SDK to build query URLs and useAsyncData for fetching data asynchronously in an ssr friedndly way.",{"id":3281,"title":3282,"titles":3283,"content":3284,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-query#element-types","Element Types",[449],"\u003Cscript setup lang=\"ts\">\n  \u002F\u002F query addresses\n  const { data, error } = await useCraftQuery('addresses').one()\n  \u002F\u002F or use the shorthand\n  const { data, error } = await useCraftAddress().one()\n\n  \u002F\u002F query assets\n  const { data, error } = await useCraftQuery('assets').one()\n  \u002F\u002F or use the shorthand\n  const { data, error } = await useCraftAsset().one()\n\n  \u002F\u002F query entry\n  const { data, error } = await useCraftQuery('entries').one()\n  \u002F\u002F or use the shorthand\n  const { data, error } = await useCraftEntry().one()\n\n  \u002F\u002F query users\n  const { data, error } = await useCraftQuery('users').one()\n  \u002F\u002F or use the shorthand\n  const { data, error } = await useCraftUser().one()\n\u003C\u002Fscript> data and error are refs and they should be accessed with .value when used within the \u003Cscript setup>.",{"id":3286,"title":3287,"titles":3288,"content":3289,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-query#execute-query","Execute Query",[449],"By using the one() or the all() methode the fetch gets executed. If you just building your query and are not executing it you need not to await it. const query = useCraftQuery('entries').section('news')\n\n\u002F\u002F Fetch a single entry\nconst { data: singleEntry, error: singleError } = await query.one()\n\n\u002F\u002F Fetch all entries\nconst { data: allEntries, error: allError } = await query.all()",{"id":3291,"title":3292,"titles":3293,"content":3294,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-query#available-methods","Available Methods",[449],"useCraftQuery supports all methods from js-craftcms-api. For the full list of available methods, see the documentation here. In addition, the following Nuxt-specific methods are available: MethodDescriptionTypeoneFetch one elementvoidallFetch all elementsvoid",{"id":3296,"title":681,"titles":3297,"content":3298,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-query#example",[449],"\u002F\u002F fetch without type definition\nconst { data, error } = useCraftQuery('entries')\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()\n\n\u002F\u002F with ts\ntype CraftEntry = {\n  title: string\n}\nconst { data, error } = useCraftQuery\u003CCraftEntry, 'entries'>('entries')\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()\n\n\u002F\u002F or using the shorthand\nconst { data, error } = useCraftEntry\u003CCraftEntry>()\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()",{"id":3300,"title":3301,"titles":3302,"content":3303,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-query#types","Types",[449],"type ElementType = 'addresses' | 'assets' | 'entries' | 'users'\n\ntype ReturnType\u003CResT, T extends ElementType> = QueryBuilder\u003CT> & {\n  one(): AsyncData\u003CPickFrom\u003CResT, KeysOf\u003CResT>> | null, NuxtError\u003Cunknown> | null>\n  all(): AsyncData\u003CPickFrom\u003CResT, KeysOf\u003CResT>> | null, NuxtError\u003Cunknown> | null>\n  buildUrl(execOpt: ExecutionMethod): string\n}\n\nexport function useCraftQuery\u003CResT, T extends ElementType>(elementType: T): ReturnType\u003CResT, T>\nexport function useCraftEntry\u003CResT>()\nexport function useCraftAddress\u003CResT>()\nexport function useCraftAsset\u003CResT>()\nexport function useCraftUser\u003CResT>() html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":454,"title":453,"titles":3305,"content":3306,"level":713},[],"Learn how to use the useCraftCurrentSite composable. This composable offers an easy way to retrieve the current site based on the siteMap defined in nuxt.config.ts. It facilitates multisite support and simplifies querying data from your Craft CMS backend.",{"id":3308,"title":34,"titles":3309,"content":3310,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-current-site#usage",[453],"const currentSite = useCraftCurrentSite(); By default it returns the current site based on the path defined in the siteMap property in your nuxt.config.ts. You can change this behavior by changing the\nsiteDetectionMode to origin.",{"id":3312,"title":3313,"titles":3314,"content":3315,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-current-site#sitedetectionmode-path","siteDetectionMode: path",[453,34],"\u002F\u002F Url: http:\u002F\u002Flocalhost:3000\u002Fde\u002Fhappy-trying\n\u002F\u002F\n\u002F\u002F Nuxt Config:\n\u002F\u002F  craftcms: {\n\u002F\u002F    baseUrl: 'https:\u002F\u002Fcms.ddev.site',\n\u002F\u002F    authToken: 'xxxx',\n\u002F\u002F    siteDetectionMode: 'path',\n\u002F\u002F    siteMap: [\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      },\n\u002F\u002F      {\n\u002F\u002F        handle: 'de',\n\u002F\u002F        origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F        path: '\u002Fde',\n\u002F\u002F      }\n\u002F\u002F    ],\n\u002F\u002F  },\n\nconst currentSite = useCraftCurrentSite();\n\n\u002F\u002F currentSite.value will be:\n\u002F\u002F  {\n\u002F\u002F    handle: 'de',\n\u002F\u002F    origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F    path: '\u002Fde',\n\u002F\u002F  }",{"id":3317,"title":3318,"titles":3319,"content":3320,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-current-site#sitedetectionmode-origin","siteDetectionMode: origin",[453,34],"\u002F\u002F Url: https:\u002F\u002Fen-site.ddev.site\u002Fhappy-trying\n\u002F\u002F\n\u002F\u002F Nuxt Config:\n\u002F\u002F  craftcms: {\n\u002F\u002F    baseUrl: 'https:\u002F\u002Fcms.ddev.site',\n\u002F\u002F    authToken: 'xxxx',\n\u002F\u002F    siteDetectionMode: 'origin', \n\u002F\u002F    siteMap: [\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'https:\u002F\u002Fen-site.ddev.site',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      },\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'https:\u002F\u002Fde-site.ddev.site',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      }\n\u002F\u002F    ],\n\u002F\u002F  },\n\nconst currentSite = useCraftCurrentSite();\n\n\u002F\u002F currentSite.value will be:\n\u002F\u002F  {\n\u002F\u002F    handle: 'en',\n\u002F\u002F    origin: 'https:\u002F\u002Fen-site.ddev.site',\n\u002F\u002F    path: '\u002F',\n\u002F\u002F  } To use this composable, you have to define your sites in the siteMap property in the nuxt.config.ts.",{"id":3322,"title":3323,"titles":3324,"content":3325,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-current-site#no-site-found","No site found",[453],"If no current site is available, it will return the first site defined in the siteMap Array.",{"id":3327,"title":3328,"titles":3329,"content":3330,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-current-site#type","Type",[453],"function useCraftCurrentSite(): CompoutedRef\u003CCraftSite>;\n\ntype CraftSite = {\n    handle: string;\n    origin: string;\n    path: string;\n    id?: number;\n    label?: string;\n    lang?: string;\n    primary?: boolean;\n}; html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":458,"title":457,"titles":3332,"content":3333,"level":713},[],"Learn how to use the useCraftUri composable. This composable provides an easy way to retrieve the current URI based on the defined siteMap within the nuxt.config.ts.\nIt enhances multisite support and simplifies querying data from your Craft CMS backend.",{"id":3335,"title":34,"titles":3336,"content":3337,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-uri#usage",[457],"const uri = useCraftUri(); By default it returns the uri based on the path defined in the siteMap property in your nuxt.config.ts. You can change this behavior by changing the\nsiteDetectionMode to origin.",{"id":3339,"title":3313,"titles":3340,"content":3341,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-uri#sitedetectionmode-path",[457,34],"\u002F\u002F Url: http:\u002F\u002Flocalhost:3000\u002Fde\u002Fhappy-trying\n\u002F\u002F\n\u002F\u002F Nuxt Config:\n\u002F\u002F  craftcms: {\n\u002F\u002F    baseUrl: 'https:\u002F\u002Fcms.ddev.site',\n\u002F\u002F    authToken: 'xxxx',\n\u002F\u002F    siteDetectionMode: 'path',\n\u002F\u002F    siteMap: [\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      },\n\u002F\u002F      {\n\u002F\u002F        handle: 'de',\n\u002F\u002F        origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F        path: '\u002Fde',\n\u002F\u002F      }\n\u002F\u002F    ],\n\u002F\u002F  },\nconst uri = useCraftUri();\n\n\u002F\u002F uri.value will result in: \"happy-trying\"",{"id":3343,"title":3318,"titles":3344,"content":3345,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-uri#sitedetectionmode-origin",[457,34],"\u002F\u002F Url: https:\u002F\u002Fen-site.ddev.site\u002Fhappy-trying\n\u002F\u002F\n\u002F\u002F Nuxt Config:\n\u002F\u002F  craftcms: {\n\u002F\u002F    baseUrl: 'https:\u002F\u002Fcms.ddev.site',\n\u002F\u002F    authToken: 'xxxx',\n\u002F\u002F    siteDetectionMode: 'origin', \n\u002F\u002F    siteMap: [\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'https:\u002F\u002Fen-site.ddev.site',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      },\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'https:\u002F\u002Fde-site.ddev.site',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      }\n\u002F\u002F    ],\n\u002F\u002F  },\n\nconst uri = useCraftUri();\n\n\u002F\u002F uri.value will result in: \"happy-trying\" To use this composable, you have to define your sites in the siteMap property in the nuxt.config.ts.",{"id":3347,"title":3328,"titles":3348,"content":3349,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-uri#type",[457],"function useCraftUri(): ComputedRef\u003Cstring>; html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"id":462,"title":461,"titles":3351,"content":3352,"level":713},[],"Learn how to use the useCraftFetch composable. This composable adds a useFetch wrapper to query data with the provided Bearer token in your nuxt.config.ts.",{"id":3354,"title":34,"titles":3355,"content":3356,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-fetch#usage",[461],"const { baseUrl } = useRuntimeConfig().public.craftcms\nconst apiUrl = `${baseUrl}\u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery?elementType=navigation&handle=mainNavigation&all=1`\n\nconst { data: links, error } = useCraftFetch(apiUrl)\n\nif (error.value) {\n  console.log(error.value)\n} To see all the available options please refer to the official useFetch docs.",{"id":3358,"title":3328,"titles":3359,"content":3360,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-fetch#type",[461],"function useCraftFetch\u003CT>(\n  url: Ref\u003Cstring> | string | (() => string),\n  options?: UseFetchOptions\u003CT>,\n): ReturnType\u003Ctypeof useFetch\u003CT>> html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":466,"title":465,"titles":3362,"content":3363,"level":713},[],"Learn how to use the useCraftSeoMatic composable. This composable adds a useAsyncData wrapper to get seoMatic data from the seoMatic API endpoints.",{"id":3365,"title":34,"titles":3366,"content":3367,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-seo-matic#usage",[465],"const { data, error } = useCraftSeoMatic() This will automatically detect your current site and uri to query\nseoMatic data from the \u002Factions\u002Fseomatic\u002Fmeta-container\u002Fall-meta-containers endpoint.",{"id":3369,"title":3370,"titles":3371,"content":3372,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-seo-matic#use-queried-data","Use queried data",[465,34],"The composable just returns the title, meta, link and jsonLd tags.\nTherefore you need to use useHead to set the queried data. A full example might look like this: const { data, error } = useCraftSeoMatic() \u002F\u002F query the seodata\n\nif (error.value) {\n  console.error(error.value)\n}\n\n\u002F\u002F make things reactive\nconst title = computed(() => data.value?.title ?? '')\nconst meta = computed(() => data.value?.metaTags ?? [])\nconst link = computed(() => data.value?.linkTags ?? [])\nconst jsonLd = computed(() => data.value?.jsonLd ?? {})\n\n\u002F\u002F use data with useHead\nuseHead({\n  title,\n  meta,\n  link,\n  script: [\n    {\n      type: 'application\u002Fld+json',\n      innerHTML: jsonLd,\n    },\n  ],\n}) Read more about that endpoint in the official seomatic docs.",{"id":3374,"title":3375,"titles":3376,"content":3377,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-seo-matic#custom-url","Custom Url",[465,34],"You can also provide your own API url to query the things you need. const { baseUrl } = config.public.craftcms\nconst apiUrl = `${baseUrl}meta-container-api-endpoints?asArray=true&uri=\u002F`\nconst { data, error } = useCraftSeoMatic(apiUrl)",{"id":3379,"title":3380,"titles":3381,"content":3382,"level":740},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-seo-matic#usage-in-appvue","Usage in app.vue",[465,34],"If you want to set the SEO tags in the app.vue, you need to watch the route for client side navigation.\nThis is actually expected behavior from nuxt and not reccomended as it destroys the cache everytime you use client side navigation. You can do that by using the watch option from useAsyncData. const page = useRoute()\nconst { data: seoData, error } = useCraftSeoMatic(undefined, {\n  watch: [page],\n}) To see all the available options please refer to the official useAsyncData docs.",{"id":3384,"title":3328,"titles":3385,"content":3386,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-seo-matic#type",[465],"function useCraftSeoMatic\u003CT = TransformedSeoData>(\n  url?: string,\n  options: AsyncDataOptions\u003CT> = {}): CraftSeoMaticReturn\u003CT>\n\ntype TransformedSeoData = {\n  title: string\n  metaTags: Array\u003C{\n    hid: string\n    name?: string\n    property?: string\n    content?: string\n  }>\n  linkTags: Array\u003C{\n    rel: string\n    href: string\n    hreflang?: string\n  }>\n  jsonLd: Record\u003Cstring, unknown>\n}\n\ninterface CraftSeoMaticReturn\u003CT> extends Promise\u003C{\n  data: Ref\u003CT | null>\n  error: Ref\u003CError | null>\n  pending: Ref\u003Cboolean>\n  refresh: () => Promise\u003Cvoid>\n}> {\n  data: Ref\u003CT | null>\n  pending: Ref\u003Cboolean>\n  refresh: () => Promise\u003Cvoid>\n  error: Ref\u003CError | null>\n} html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":470,"title":469,"titles":3388,"content":3389,"level":713},[],"Learn how to use the useCraftAuthToken composable. This composable returns the Bearer auth token defined in your nuxt.config.ts.",{"id":3391,"title":34,"titles":3392,"content":3393,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-auth-token#usage",[469],"const authToken = useCraftAuthToken();",{"id":3395,"title":3328,"titles":3396,"content":3397,"level":719},"\u002Flibraries\u002Fnuxt-craftcms\u002Fcomposables\u002Fuse-craft-auth-token#type",[469],"function useCraftAuthToken(): string; html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":479,"title":478,"titles":3399,"content":3400,"level":713},[],"Learn how to use the CraftPage component. The CraftPage component maps section handles defined in Craft CMS to pages in Nuxt via the config prop.\nThe content prop receives the actual data from your Craft CMS query, typically using useCraftQuery(). You can find more about the CraftPage component in the Vue SDK docs. The Vue package is used under the hood here.",{"id":483,"title":482,"titles":3402,"content":3403,"level":713},[],"Learn how to use the CraftArea component. The CraftArea component maps field handles defined in Craft CMS to components in Nuxt defined in the config prop of the CraftPage.\nThe content prop receives the actual data from your Craft CMS query, typically an array of Matrix Field data. You can find more about the CraftArea component in the Vue SDK docs. The Vue package is used under the hood here.",{"id":487,"title":486,"titles":3405,"content":3406,"level":713},[],"Learn how to use the CraftNotImplemented component. The CraftNotImplemented componentis a small development helper with the following purposes: Display Unimplemented Block Types: Shows a message indicating any block type that hasn’t been implemented yet.Debug Block Attributes: Outputs the block’s attributes in a readable format for easier debugging. You can find more about the CraftNotImplemented component in the Vue SDK docs. The Vue package is used under the hood here.",{"id":491,"title":490,"titles":3408,"content":3409,"level":713},[],"A library for using the Craft CMS query builder in Next.js.",{"id":3411,"title":1168,"titles":3412,"content":3413,"level":719},"\u002Flibraries\u002Fquery-api-next#features",[490],"Query builder: Easily build and execute queries directly from Next.js, enabling flexible, real-time data retrieval from Craft CMSServer and Client Component Support: Full support for both client and server components with dedicated hooks and functions.Data Driven Components: Connect your data directly with your Vue components, to speed up development.Get Only the Data You Need: Avoid overfetching by using a custom function in the query builder to select only the fields you require.Pretty JSON: JSON transformers are in place to format the response for better readability.Support for Main Element Types: Query addresses, assets, entries and users.Full TypeScript Support: A fully-typed query builder for Craft CMS. Pretty cool, huh? 😎Multisite Helpers: Built-in helpers to support Craft Multisites.",{"id":3415,"title":440,"titles":3416,"content":3417,"level":719},"\u002Flibraries\u002Fquery-api-next#examples",[490],"Want to see how it works? const { data, error } = await getCraftEntry()\n  .section('news')\n  .fields(['title']) \u002F\u002F add more field handles if you like\n  .limit(3)\n  .all() It is as simple as that. 🚀 The response will contain three entries from the 'news' section.",{"id":3419,"title":2974,"titles":3420,"content":3421,"level":719},"\u002Flibraries\u002Fquery-api-next#further-resources",[490],"Craft Query API: A Craft CMS Plugin, that powers this great stuff.React SDK: A package to use the query builder in React.JS SDK: Foundation to build a query builder with your preferred JS framework. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":499,"title":274,"titles":3423,"content":3424,"level":713},[],"Learn how to use the @query-api\u002Fnext library in Next.js. The @query-api\u002Fnext introduces a powerful query builder to your Next.js app, allowing you to easily fetch data from Craft CMS,\nsimilar to how you would in Twig. It allows you to connect your Craft CMS sections and entry types to React components, making it easy to render dynamic content in your Next.js applications.",{"id":3426,"title":716,"titles":3427,"content":3428,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fintroduction#requirements",[274],"The Craft Query API plugin must be installed and properly configured in Craft CMS.Node.js - 20.x or newer (but I recommend the active LTS release)",{"id":3430,"title":2532,"titles":3431,"content":3432,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fintroduction#supported-element-types",[274],"The library supports querying for the following Craft CMS element types: AddressesAssetsEntriesUsers",{"id":3434,"title":2537,"titles":3435,"content":2539,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fintroduction#need-help",[274],{"id":502,"title":414,"titles":3437,"content":3438,"level":713},[],"Use the create-query-api CLI to scaffold a new @query-api\u002Fnext project.",{"id":3440,"title":716,"titles":3441,"content":3428,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fquick-start#requirements",[414],{"id":3443,"title":107,"titles":3444,"content":3445,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fquick-start#installation",[414],"The fastest way to get started is with the create-query-api command-line tool. It scaffolds a complete project for you, including a pre-configured Craft CMS and a Next.js frontend. Open your terminal and run the following command: npx create-query-api@latest query-api-next --template next",{"id":3447,"title":3093,"titles":3448,"content":3449,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fquick-start#manual-installation",[414],"If you want to integrate the @query-api\u002Fnext SDK into an existing Next.js project or want to understand the setup process step by step, you can head over to the Manual Setup Guide html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":505,"title":418,"titles":3451,"content":3452,"level":713},[],"Learn how to install and configure the @query-api\u002Fnext package for your Next.js project. This guide is for developers who want to integrate the Query API into an existing Next.js project or for those who want to understand the setup process step-by-step. If you prefer to dive straight into code, you can check out the Next.js demo project on GitHub.",{"id":3454,"title":1390,"titles":3455,"content":3102,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fmanual-setup#prerequisites",[418],{"id":3457,"title":3458,"titles":3459,"content":3460,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fmanual-setup#_2-nextjs-app","2. Next.js App",[418,1390],"You'll need a Next.js application. If you're starting from scratch, you can create one inside your Craft project's root folder. npx create-next-app@latest frontend --app --ts --src-dir --empty You can now open the frontend directory in your code editor to begin the setup.",{"id":3462,"title":3110,"titles":3463,"content":3464,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fmanual-setup#installation-and-folder-structure",[418],"First, install the @query-api\u002Fnext SDK in your Next.js project. npm install @query-api\u002Fnext Next, we will create the following folder and file structure inside the src directory. This structure helps organize your code by separating concerns. ├── src\n│   ├── app\n│   │   ├── [[...slug]]\n│   │   │   └── page.tsx\n│   │   └── layout.tsx\n│   ├── components\n│   │   ├── content\n│   │   │   ├── BlockHeadline.tsx\n│   │   │   └── ViewHome.tsx\n│   ├── libs\n│   │   └── query-api.ts\n│   ├── types\n│   │   └── base.ts\n│   └── middleware.ts\n├── .env",{"id":3466,"title":3115,"titles":3467,"content":3468,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fmanual-setup#environment-variables",[418],"Create a .env file in the root of your Next.js project to store your Craft CMS connection details. # Allows Node.js to connect to local development URLs (e.g., DDEV).\n# Remove this in production.\nNODE_TLS_REJECT_UNAUTHORIZED=0\n\n# The base URL of your Craft CMS backend.\nNEXT_PUBLIC_CRAFT_BASE_URL=https:\u002F\u002Fquery-api-starter.ddev.site\n\n# The bearer token you generated in the Query API plugin settings.\nNEXT_PUBLIC_CRAFT_AUTH_TOKEN=\"Bearer sqKTlMFsky_OeJVeDfnps75b2Gny4NBG\" # Default of create-query-api starter template You can find\u002Fcreate the bearer token under \u002Fadmin\u002Fquery-api\u002Ftokens in the control panel.",{"id":3470,"title":3120,"titles":3471,"content":734,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fmanual-setup#generate-types",[418],{"id":3473,"title":432,"titles":3474,"content":3475,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fmanual-setup#content-driven-components",[418],"These are the React components that will render your Craft CMS content. We recommend placing them in a dedicated components\u002Fcontent directory to distinguish them from general-purpose UI components. Here is an example of a component for a headline entry type that is used in a matrix block. import type { CraftEntryTypeHeadline } from '@\u002Ftypes\u002Fbase'\n\n\u002F\u002F This component renders a headline from a Matrix block.\n\u002F\u002F The props are fully typed based on the generated `base.ts` file.\nexport default function Headline(props: CraftEntryTypeHeadline) {\n  \u002F\u002F The `selectHeadlineTag` field is a dropdown in Craft,\n  \u002F\u002F allowing content editors to choose the HTML tag (e.g., h1, h2).\n  const Tag = props.selectHeadlineTag.value\n  return \u003CTag>{props.title}\u003C\u002FTag>\n} Next, create the main view component for your home section. import { CraftArea } from '@query-api\u002Fnext'\nimport type { CraftPageHome } from '@\u002Ftypes\u002Fbase'\n\n\u002F\u002F This component renders the \"Home\" page.\nexport default function Home(props: CraftPageHome) {\n  return (\n    \u003Cdiv>\n      {\u002F* `translatablePlainText` is a field from our Craft entry. *\u002F}\n      \u003Ch1>{props.translatablePlainText}\u003C\u002Fh1>\n\n      {\u002F* The CraftArea component dynamically renders Matrix blocks. *\u002F}\n      {\u002F* It takes the `contentBuilder` field (a Matrix field) and maps each block *\u002F}\n      {\u002F* to the corresponding component defined in `query-api.ts`. *\u002F}\n      \u003CCraftArea content={props.contentBuilder} \u002F>\n    \u003C\u002Fdiv>\n  )\n}",{"id":3477,"title":3478,"titles":3479,"content":3480,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fmanual-setup#middleware-setup","Middleware Setup",[418],"Middleware is used to share request context globally, which is essential for features like live preview to work correctly without needing to pass request data down through every component. import { createQueryApiMiddleware } from '@query-api\u002Fnext\u002Fserver'\n\n\u002F\u002F This function initializes the middleware with default settings.\nexport default createQueryApiMiddleware()\n\nexport const config = {\n  \u002F\u002F The matcher ensures the middleware runs on all paths except for\n  \u002F\u002F API routes, TRPC routes, Next.js internal paths, and static files.\n  matcher: '\u002F((?!api|trpc|_next|_vercel|.*\\\\..*).*)',\n}",{"id":3482,"title":3124,"titles":3483,"content":3484,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fmanual-setup#query-api-configuration",[418],"This file initializes the Query API client and defines the contentMapping, which tells the library which React components to use for different Craft CMS pages and blocks. import { craftInit, CraftNotImplemented } from '@query-api\u002Fnext\u002Fserver'\n\n\u002F\u002F Import the components that will render Craft CMS content.\nimport ViewHome from '@\u002Fcomponents\u002Fcontent\u002FViewHome'\nimport BlockHeadline from '@\u002Fcomponents\u002Fcontent\u002FBlockHeadline'\n\nexport const craftConfig = craftInit({\n  baseUrl: process.env.NEXT_PUBLIC_CRAFT_BASE_URL ?? '',\n  authToken: process.env.NEXT_PUBLIC_CRAFT_AUTH_TOKEN ?? '',\n  \n  \u002F\u002F Define a site map for multi-site setups.\n  siteMap: [\n    { handle: 'en', path: '\u002F', origin: 'http:\u002F\u002Flocalhost:3000', id: 1 },\n    { handle: 'de', path: '\u002Fde', origin: 'http:\u002F\u002Flocalhost:3000', id: 2 },\n    { handle: 'es', path: '\u002Fes', origin: 'http:\u002F\u002Flocalhost:3000', id: 3 },\n  ],\n\n  \u002F\u002F The contentMapping connects Craft handles to your React components.\n  contentMapping: {\n    \u002F\u002F `pages` maps a section handle (e.g., \"home\") to a view component.\n    pages: {\n      home: ViewHome,\n    },\n    \u002F\u002F `components` maps a block type handle (e.g., \"headline\") to a component.\n    \u002F\u002F This is typically used for Matrix blocks.\n    components: {\n      headline: BlockHeadline,\n      \u002F\u002F Use CraftNotImplemented as a placeholder for components you haven't created yet.\n      text: CraftNotImplemented,\n      imageAndText: CraftNotImplemented,\n      image: CraftNotImplemented,\n    }\n  }\n})",{"id":3486,"title":3487,"titles":3488,"content":3489,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fmanual-setup#root-layout","Root Layout",[418],"The CraftClientProvider must wrap your root layout to make the configuration available to all components, including client-side components. import Link from \"next\u002Flink\";\nimport { CraftClientProvider } from '@query-api\u002Fnext\u002Fserver'\nimport { craftConfig } from '@\u002Flibs\u002Fquery-api';\n\nexport default function RootLayout({\n  children,\n}: Readonly\u003C{\n  children: React.ReactNode;\n}>) {\n  return (\n    \u002F\u002F The provider makes the `craftConfig` available throughout the component tree.\n    \u003CCraftClientProvider config={craftConfig}>\n      \u003Chtml lang=\"en\">\n        \u003Cbody>\n          \u003Cnav>\n            \u003Cul>\n              \u003Cli>\u003CLink href=\"\u002F\">Home\u003C\u002FLink>\u003C\u002Fli>\n              \u003Cli>\u003CLink href=\"\u002Fde\">Home DE\u003C\u002FLink>\u003C\u002Fli>\n              \u003Cli>\u003CLink href=\"\u002Fes\">Home ES\u003C\u002FLink>\u003C\u002Fli>\n            \u003C\u002Ful>\n          \u003C\u002Fnav>\n          {children}\n        \u003C\u002Fbody>\n      \u003C\u002Fhtml>\n    \u003C\u002FCraftClientProvider>\n  );\n}",{"id":3491,"title":3138,"titles":3492,"content":3493,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fmanual-setup#catch-all-route",[418],"This dynamic route is the core of the page rendering logic. It captures every incoming URL, fetches the corresponding entry from Craft CMS, and renders it using the CraftPage component. import { getCraftUri, getCraftCurrentSite, getCraftEntry, CraftPage } from '@query-api\u002Fnext\u002Fserver'\nimport { CraftPageBase } from '@\u002Ftypes\u002Fbase'\n\nexport default async function CraftCatchAllPage() {\n  \u002F\u002F getCraftUri() determines the page URI based on your currentSite.\n  const uri = await getCraftUri()\n  \u002F\u002F getCraftCurrentSite() identifies the current site based on the URL (e.g., \u002Fde).\n  const { id } = await getCraftCurrentSite()\n\n  \u002F\u002F getCraftEntry() starts building a query for a single entry.\n  \u002F\u002F The query is configured with the URI and site ID, and then executed with .one().\n  const { data, error } = await getCraftEntry\u003CCraftPageBase>()\n    .uri(uri)\n    .siteId(id)\n    .one()\n\n  if (error || !data) {\n    throw new Error(error?.message || 'No data returned from Craft CMS.')\n  }\n\n  \u002F\u002F The CraftPage component automatically selects the correct view\n  \u002F\u002F (e.g., ViewHome) from your contentMapping based on the fetched data.\n  return \u003CCraftPage content={data} \u002F>\n} With this setup, navigating to any page on your Next.js site will trigger a fetch to your Craft CMS backend, and the correct content will be rendered automatically. It's as simple as that! 🚀",{"id":3495,"title":3143,"titles":3496,"content":3497,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fmanual-setup#anything-missing",[418],"If you have questions, run into issues, or have ideas for improvements, your feedback is very welcome! Please don't hesitate to open an issue on GitHub. Whether it's a bug report, a feature request, or a general suggestion, your input helps make this project better for everyone. html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}",{"id":508,"title":29,"titles":3499,"content":3500,"level":713},[],"Learn how to configure the @query-api\u002Fnext package for your Next.js application. The @query-api\u002Fnext package is configured by calling the craftInit function. This function initializes the Query API client with your Craft CMS backend details and maps your React components to Craft CMS entries and blocks. Typically, you will do this in a dedicated file, such as libs\u002Fquery-api.ts, to keep your configuration organized and easily accessible.",{"id":3502,"title":3151,"titles":3503,"content":3504,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fconfiguration#example-configuration",[29],"This example shows a minimal setup for a React application using the Query API: craftInit({\n  baseUrl: 'https:\u002F\u002Fyour-craft-backend.ddev.site',\n  authToken: 'Bearer yourBearerToken',\n  contentMapping: {\n    pages: {}\n    components: {},\n  },\n})",{"id":3506,"title":3156,"titles":3507,"content":734,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fconfiguration#configuration-options",[29],{"id":3509,"title":3160,"titles":3510,"content":3162,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fconfiguration#baseurl",[29,3156],{"id":3512,"title":3165,"titles":3513,"content":3167,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fconfiguration#authtoken",[29,3156],{"id":3515,"title":3516,"titles":3517,"content":3518,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fconfiguration#contentmapping","contentMapping",[29,3156],"The contentMapping option lets you connect your Craft CMS sections and entry types to React components. In pages, use sectionHandle:entryTypeHandle (e.g., news:home) to map to a React page. If the entry type handle is the same as the section handle, or if it's the default entry type for that section, you can simply use the section handle as the key (e.g., home). To turn off sectionHandle:entryTypeHandle mapping, set enableEntryTypeMapping: false in craftInit. In components, map entry types to React components. This is useful for things like matrix blocks. Type: objectDefault: { pages: {}, components: {} }Example: contentMapping: {\n  pages: {\n    home: Home, \u002F\u002F Maps section home entry with entry type home to the Home component.\n    'news:home': News, \u002F\u002F Maps section news entry with entry type home to the News component.\n  },\n  components: {\n    headline: Headline, \u002F\u002F Entry type headline will be rendered with the Headline component.\n    imageText: CraftNotImplemented,\n  },\n}",{"id":3520,"title":3521,"titles":3522,"content":3523,"level":2800},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fconfiguration#error-pages","Error Pages",[29,3156,3516],"You can also map error pages by providing special keys in the contentMapping.pages object. This allows you to render custom Next.js components for specific error scenarios. page404: For 404 Not Found errors.page500: For 500 Internal Server Error responses from Craft.error: A general fallback for other errors.",{"id":3525,"title":3170,"titles":3526,"content":3172,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fconfiguration#sitemap",[29,3156],{"id":3528,"title":902,"titles":3529,"content":3176,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fconfiguration#debug",[29,3156],{"id":3531,"title":3179,"titles":3532,"content":3181,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fconfiguration#enableentrytypemapping",[29,3156],{"id":3534,"title":3184,"titles":3535,"content":3186,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fconfiguration#sitedetectionmode",[29,3156],{"id":3537,"title":3194,"titles":3538,"content":3539,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fconfiguration#default-configuration",[29],"This is the default configuration for the @query-api\u002Fnext package. export const defaultCraftOptions = {\n  baseUrl: '',\n  authToken: '',\n  contentMapping: { pages: {}, components: {} },\n  debug: false,\n  enableEntryTypeMapping: true,\n  siteDetectionMode: siteDetectionModes.PATH,\n  siteMap: [],\n} html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}",{"id":512,"title":511,"titles":3541,"content":3542,"level":713},[],"Here you will learn more about internal implementation detail of the library.",{"id":3544,"title":3545,"titles":3546,"content":3547,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fimplementation-details#imports","Imports",[511],"@query-api\u002Fnext uses react-server conditional exports\nto load code that is optimized for use in Server or Client Components. For example, hooks like useCraftUri() rely on useContext when used in Client Components.\nOn the server, however, values like the current URI or site are resolved directly via headers(). Usage in Server Components: import { getCraftUri, getCraftCurrentSite, getCraftEntry } from '@query-api\u002Fnext\u002Fserver' Usage in Client Components: 'use-client'\n\nimport { useCraftUri, useCraftCurrentSite, useCraftEntry } from '@query-api\u002Fnext'",{"id":3549,"title":473,"titles":3550,"content":3551,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fimplementation-details#components",[511],"All of the components are context independent, meaning you can use them in client and in server components.",{"id":3553,"title":3554,"titles":3555,"content":3556,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fimplementation-details#provider","Provider",[511],"The CraftClientProvider is also context-agnostic. This is achieved through two CraftClientProvider components that work together through composition, bridging the gap between the Next.js server and client environments.",{"id":3558,"title":3559,"titles":3560,"content":3561,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fimplementation-details#server-side-provider-query-apinextserver","Server-Side Provider (@query-api\u002Fnext\u002Fserver)",[511,3554],"This is an async React Server Component. Its primary function is to resolve request-specific data that is only available on the server.It reads the incoming request headers (set by the createQueryApiMiddleware) to determine the full URL and path of the user's request. This server-side context is essential for site and preview resolution.After resolving the location data from the headers, it renders the client-side CraftClientProvider, passing the resolved location and the shared config object down as props.",{"id":3563,"title":3564,"titles":3565,"content":3566,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fimplementation-details#client-side-provider-query-apinext","Client-Side Provider (@query-api\u002Fnext)",[511,3554],"This is a standard React Client Component, marked with 'use client'.Its sole responsibility is to take the config and location props it receives from the server provider and inject them into a React Context using the underlying CraftProvider from @query-api\u002Freact.This makes the configuration and location context available to any descendant client component.",{"id":3568,"title":3569,"titles":3570,"content":3571,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fget-started\u002Fimplementation-details#execution-flow","Execution Flow:",[511,3554],"On a page request, the Server Provider executes first.It awaits the request headers to get the URL.It then returns the Client Provider in its render output, passing the URL data as props.The Client Provider receives these props and establishes the React Context for the rest of the application, including all client-side hooks (useCraftQuery, etc.). This pattern allows you to initialize the provider with server-known information (the URL) while making that information accessible to client-side components through a standard React Context. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":521,"title":520,"titles":3573,"content":3574,"level":713},[],"Learn how to use the getCraftQuery function. This function provides a simple way to fetch data from your Craft CMS Backend.\nIt leverages the JS SDK to build query URLs and fetch for fetching data in server components.",{"id":3576,"title":3282,"titles":3577,"content":3578,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-query#element-types",[520],"\u002F\u002F query addresses\nconst { data, error } = await getCraftQuery('addresses').one()\n\u002F\u002F or use the shorthand\nconst { data, error } = await getCraftAddress().one()\n\n\u002F\u002F query assets\nconst { data, error } = await getCraftQuery('assets').one()\n\u002F\u002F or use the shorthand\nconst { data, error } = await getCraftAsset().one()\n\n\u002F\u002F query entry\nconst { data, error } = await getCraftQuery('entries').one()\n\u002F\u002F or use the shorthand\nconst { data, error } = await getCraftEntry().one()\n\n\u002F\u002F query users\nconst { data, error } = await getCraftQuery('users').one()\n\u002F\u002F or use the shorthand\nconst { data, error } = await getCraftUser().one()",{"id":3580,"title":3287,"titles":3581,"content":3582,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-query#execute-query",[520],"The fetch request is executed by calling the .one() or .all() method. If you are only building the query object without executing it, you don't need to use await. const query = getCraftQuery('entries').section('news')\n\n\u002F\u002F Fetch a single entry\nconst { data: singleEntry, error: singleError } = await query.one()\n\n\u002F\u002F Fetch all entries\nconst { data: allEntries, error: allError } = await query.all()",{"id":3584,"title":3292,"titles":3585,"content":3586,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-query#available-methods",[520],"getCraftQuery supports all methods from js-craftcms-api. For the full list of available methods, see the documentation here. In addition, the following methods are available for executing the query: MethodDescriptionTypeoneFetch one elementvoidallFetch all elementsvoid",{"id":3588,"title":681,"titles":3589,"content":3590,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-query#example",[520],"\u002F\u002F fetch without type definition\nconst { data, error } = await getCraftQuery('entries')\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()\n\n\u002F\u002F with ts\ntype CraftEntry = {\n  title: string\n}\nconst { data, error } = await getCraftQuery\u003CCraftEntry, 'entries'>('entries')\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()\n\n\u002F\u002F or using the shorthand\nconst { data, error } = await getCraftEntry\u003CCraftEntry>()\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()",{"id":3592,"title":3301,"titles":3593,"content":3594,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-query#types",[520],"type ElementType = 'addresses' | 'assets' | 'entries' | 'users'\n\nexport function getCraftQuery\u003CResT, T extends ElementType>(elementType: T): QueryBuilder\u003CT> & {\n  one(): Promise\u003C{\n    data: ResT | null;\n    error: Error | null;\n  }>;\n  all(): Promise\u003C{\n    data: ResT | null;\n    error: Error | null;\n  }>;\n} html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":525,"title":524,"titles":3596,"content":3597,"level":713},[],"Learn how to use the getCraftData function. This function is a fetch wrapper and used internally for all the getCraftQuery functions.\nYou can use this to fetch data from Craft CMS with custom element types or something else. It handles previewing and authorization for you.",{"id":3599,"title":34,"titles":3600,"content":3601,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-data#usage",[524],"const apiUrl = `?elementType=navigation&handle=mainNavigation&all=1`\n\nconst { data, error } = await getCraftData(apiUrl)",{"id":3603,"title":3328,"titles":3604,"content":3605,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-data#type",[524],"export async function getCraftData\u003CResT = any>(queryUrl: string, options?: RequestInit): Promise\u003C{\n    data: ResT | null;\n    error: Error | null;\n}> html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":529,"title":528,"titles":3607,"content":3608,"level":713},[],"Learn how to use the getCraftCurrentSite function. This function offers an easy way to retrieve the current site based on the siteMap defined in libs\u002Fquery-api.ts. It facilitates multisite support and simplifies querying data from your Craft CMS backend.",{"id":3610,"title":34,"titles":3611,"content":3612,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-current-site#usage",[528],"const currentSite = await getCraftCurrentSite(); To use this function, you have to define your sites in the siteMap property in the libs\u002Fquery-api.ts. By default it returns the current site based on the path defined in the siteMap property in your libs\u002Fquery-api.ts. You can change this behavior by changing the\nsiteDetectionMode to origin. You can read more about that in the configuration docs.",{"id":3614,"title":3313,"titles":3615,"content":3616,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-current-site#sitedetectionmode-path",[528,34],"\u002F\u002F Url: http:\u002F\u002Flocalhost:3000\u002Fde\u002Fhappy-trying\n\u002F\u002F\n\u002F\u002F  craftInit({\n\u002F\u002F    siteDetectionMode: 'path',\n\u002F\u002F    siteMap: [\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      },\n\u002F\u002F      {\n\u002F\u002F        handle: 'de',\n\u002F\u002F        origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F        path: '\u002Fde',\n\u002F\u002F      }\n\u002F\u002F    ],\n\u002F\u002F  })\n\nconst currentSite = await getCraftCurrentSite();\n\n\u002F\u002F currentSite will be:\n\u002F\u002F  {\n\u002F\u002F    handle: 'de',\n\u002F\u002F    origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F    path: '\u002Fde',\n\u002F\u002F  }",{"id":3618,"title":3318,"titles":3619,"content":3620,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-current-site#sitedetectionmode-origin",[528,34],"\u002F\u002F Url: https:\u002F\u002Fen-site.ddev.site\u002Fhappy-trying\n\u002F\u002F\n\u002F\u002F \u002Flibs\u002Fquery-api.ts\n\u002F\u002F  craftInit({\n\u002F\u002F    siteDetectionMode: 'origin',\n\u002F\u002F    siteMap: [\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'https:\u002F\u002Fen-site.ddev.site',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      },\n\u002F\u002F      {\n\u002F\u002F        handle: 'de',\n\u002F\u002F        origin: 'https:\u002F\u002Fde-site.ddev.site',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      }\n\u002F\u002F    ],\n\u002F\u002F  })\n\nconst currentSite = await getCraftCurrentSite();\n\n\u002F\u002F currentSite will be:\n\u002F\u002F  {\n\u002F\u002F    handle: 'en',\n\u002F\u002F    origin: 'https:\u002F\u002Fen-site.ddev.site',\n\u002F\u002F    path: '\u002F',\n\u002F\u002F  }",{"id":3622,"title":3323,"titles":3623,"content":3325,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-current-site#no-site-found",[528],{"id":3625,"title":3328,"titles":3626,"content":3627,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-current-site#type",[528],"export async function getCraftCurrentSite(): Promise\u003CCraftSite>;\n\ntype CraftSite = {\n    handle: string;\n    origin: string;\n    path: string;\n    id?: number;\n    label?: string;\n    lang?: string;\n    primary?: boolean;\n}; html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":533,"title":532,"titles":3629,"content":3630,"level":713},[],"Learn how to use the getCraftUri function. This function provides an easy way to retrieve the current URI based on the defined siteMap within the libs\u002Fquery-api.ts.\nIt enhances multisite support and simplifies querying data from your Craft CMS backend.",{"id":3632,"title":34,"titles":3633,"content":3634,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-uri#usage",[532],"const uri = await getCraftUri(); To use this function, you must define your sites in the siteMap property in the libs\u002Fquery-api.ts. By default it returns the current site based on the path defined in the siteMap property in your libs\u002Fquery-api.ts. You can change this behavior by changing the\nsiteDetectionMode to origin. You can read more about that in the configuration docs.",{"id":3636,"title":3313,"titles":3637,"content":3638,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-uri#sitedetectionmode-path",[532,34],"\u002F\u002F Url: http:\u002F\u002Flocalhost:3000\u002Fde\u002Fhappy-trying\n\u002F\u002F\n\u002F\u002F  craftInit({\n\u002F\u002F    siteDetectionMode: 'path',\n\u002F\u002F    siteMap: [\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      },\n\u002F\u002F      {\n\u002F\u002F        handle: 'de',\n\u002F\u002F        origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F        path: '\u002Fde',\n\u002F\u002F      }\n\u002F\u002F    ],\n\u002F\u002F  })\nconst uri = await getCraftUri();\n\n\u002F\u002F uri will result in: \"happy-trying\"",{"id":3640,"title":3318,"titles":3641,"content":3642,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-uri#sitedetectionmode-origin",[532,34],"\u002F\u002F Url: https:\u002F\u002Fen-site.ddev.site\u002Fhappy-trying\n\u002F\u002F\n\u002F\u002F \u002Flibs\u002Fquery-api.ts\n\u002F\u002F  craftInit({\n\u002F\u002F    siteDetectionMode: 'origin',\n\u002F\u002F    siteMap: [\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'https:\u002F\u002Fen-site.ddev.site',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      },\n\u002F\u002F      {\n\u002F\u002F        handle: 'de',\n\u002F\u002F        origin: 'https:\u002F\u002Fde-site.ddev.site',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      }\n\u002F\u002F    ],\n\u002F\u002F  })\n\nconst uri = await getCraftUri();\n\n\u002F\u002F uri will result in: \"happy-trying\"",{"id":3644,"title":3328,"titles":3645,"content":3646,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-uri#type",[532],"export async function getCraftUri(): Promise\u003Cstring> html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"id":537,"title":536,"titles":3648,"content":3649,"level":713},[],"Learn how to use the getCraftAuthToken function. This function returns the Bearer auth token defined in your \u002Flibs\u002Fquery-api.ts.",{"id":3651,"title":34,"titles":3652,"content":3653,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-auth-token#usage",[536],"const authToken = getCraftAuthToken();",{"id":3655,"title":3328,"titles":3656,"content":3657,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Ffunctions\u002Fget-craft-auth-token#type",[536],"function getCraftAuthToken(): string; html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":545,"title":449,"titles":3659,"content":3660,"level":713},[],"Learn how to use the useCraftQuery hook. This hook provides a simple way to fetch data from your Craft CMS Backend.\nIt leverages the JS SDK to build query URLs and fetch for fetching data in Client Components.",{"id":3662,"title":3282,"titles":3663,"content":3664,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-query#element-types",[449],"\u002F\u002F query addresses\nconst { data, error, loading } = useCraftQuery('addresses').one()\n\u002F\u002F or use the shorthand\nconst { data, error, loading } = useCraftAddress().one()\n\n\u002F\u002F query assets\nconst { data, error, loading } = useCraftQuery('assets').one()\n\u002F\u002F or use the shorthand\nconst { data, error, loading } = useCraftAsset().one()\n\n\u002F\u002F query entry\nconst { data, error, loading } = useCraftQuery('entries').one()\n\u002F\u002F or use the shorthand\nconst { data, error, loading } = useCraftEntry().one()\n\n\u002F\u002F query users\nconst { data, error, loading } = useCraftQuery('users').one()\n\u002F\u002F or use the shorthand\nconst { data, error, loading } = useCraftUser().one()",{"id":3666,"title":3287,"titles":3667,"content":3668,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-query#execute-query",[449],"By using the one() or the all() methode the fetch gets executed. If you just building your query and are not executing it with one() or all() you need not to it. const query = useCraftQuery('entries').section('news')\n\n\u002F\u002F Fetch a single entry\nconst { data: singleEntry } = query.one()\n\n\u002F\u002F Fetch all entries\nconst { data: allEntries } = query.all()",{"id":3670,"title":3292,"titles":3671,"content":3672,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-query#available-methods",[449],"useCraftQuery supports all methods from js-craftcms-api. For the full list of available methods, see the documentation here. In addition, the following methods are available for executing the query: MethodDescriptionTypeoneFetch one elementvoidallFetch all elementsvoid",{"id":3674,"title":681,"titles":3675,"content":3676,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-query#example",[449],"\u002F\u002F fetch without type definition\nconst { data, error, loading } = useCraftQuery('entries')\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()\n\n\u002F\u002F with ts\ntype CraftEntry = {\n  title: string\n}\nconst { data, error, loading } = useCraftQuery\u003CCraftEntry, 'entries'>('entries')\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()\n\n\u002F\u002F or using the shorthand\nconst { data, error, loading } = useCraftEntry\u003CCraftEntry>()\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()",{"id":3678,"title":3301,"titles":3679,"content":3680,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-query#types",[449],"type ElementType = 'addresses' | 'assets' | 'entries' | 'users'\n\nexport function useCraftQuery\u003CResT, T extends ElementType>(elementType: T): QueryBuilder\u003CT> & {\n  one(): {\n    data: ResT | null;\n    loading: boolean;\n    error: string | null;\n  };\n  all(): {\n    data: ResT | null;\n    loading: boolean;\n    error: string | null;\n  };\n} html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":549,"title":548,"titles":3682,"content":3683,"level":713},[],"Learn how to use the useCraftData hook. This hook is a fetch wrapper and used internally for all the useCraftQuery hooks.\nYou can use this to fetch data from Craft CMS with custom element types or something else. It handles previewing and authorization for you.",{"id":3685,"title":34,"titles":3686,"content":3687,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-data#usage",[548],"const apiUrl = `?elementType=navigation&handle=mainNavigation&all=1`\n\nconst { data, error, loading } = useCraftData(apiUrl)",{"id":3689,"title":3328,"titles":3690,"content":3691,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-data#type",[548],"export function useCraftData\u003CResT = any>(queryUrl: string, options?: RequestInit): {\n  data: ResT | null;\n  loading: boolean;\n  error: string | null;\n} html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":552,"title":453,"titles":3693,"content":3694,"level":713},[],"Learn how to use the useCraftCurrentSite hook. This hook offers an easy way to retrieve the current site based on the siteMap defined in libs\u002Fquery-api.ts. It facilitates multisite support and simplifies querying data from your Craft CMS backend.",{"id":3696,"title":34,"titles":3697,"content":3698,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-current-site#usage",[453],"const currentSite = useCraftCurrentSite(); To use this hook, you have to define your sites in the siteMap property in the libs\u002Fquery-api.ts. By default it returns the current site based on the path defined in the siteMap property in your libs\u002Fquery-api.ts. You can change this behavior by changing the\nsiteDetectionMode to origin. You can read more about that in the configuration docs.",{"id":3700,"title":3313,"titles":3701,"content":3702,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-current-site#sitedetectionmode-path",[453,34],"\u002F\u002F Url: http:\u002F\u002Flocalhost:3000\u002Fde\u002Fhappy-trying\n\u002F\u002F\n\u002F\u002F  craftInit({\n\u002F\u002F    siteDetectionMode: 'path',\n\u002F\u002F    siteMap: [\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      },\n\u002F\u002F      {\n\u002F\u002F        handle: 'de',\n\u002F\u002F        origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F        path: '\u002Fde',\n\u002F\u002F      }\n\u002F\u002F    ],\n\u002F\u002F  })\n\nconst currentSite = useCraftCurrentSite();\n\n\u002F\u002F currentSite will be:\n\u002F\u002F  {\n\u002F\u002F    handle: 'de',\n\u002F\u002F    origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F    path: '\u002Fde',\n\u002F\u002F  }",{"id":3704,"title":3318,"titles":3705,"content":3706,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-current-site#sitedetectionmode-origin",[453,34],"\u002F\u002F Url: https:\u002F\u002Fen-site.ddev.site\u002Fhappy-trying\n\u002F\u002F\n\u002F\u002F \u002Flibs\u002Fquery-api.ts\n\u002F\u002F  craftInit({\n\u002F\u002F    siteDetectionMode: 'origin',\n\u002F\u002F    siteMap: [\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'https:\u002F\u002Fen-site.ddev.site',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      },\n\u002F\u002F      {\n\u002F\u002F        handle: 'de',\n\u002F\u002F        origin: 'https:\u002F\u002Fde-site.ddev.site',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      }\n\u002F\u002F    ],\n\u002F\u002F  })\n\nconst currentSite = useCraftCurrentSite();\n\n\u002F\u002F currentSite will be:\n\u002F\u002F  {\n\u002F\u002F    handle: 'en',\n\u002F\u002F    origin: 'https:\u002F\u002Fen-site.ddev.site',\n\u002F\u002F    path: '\u002F',\n\u002F\u002F  }",{"id":3708,"title":3323,"titles":3709,"content":3325,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-current-site#no-site-found",[453],{"id":3711,"title":3328,"titles":3712,"content":3713,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-current-site#type",[453],"export function useCraftCurrentSite(): CraftSite;\n\ntype CraftSite = {\n    handle: string;\n    origin: string;\n    path: string;\n    id?: number;\n    label?: string;\n    lang?: string;\n    primary?: boolean;\n}; html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":555,"title":457,"titles":3715,"content":3716,"level":713},[],"Learn how to use the useCraftUri hook. This hook provides an easy way to retrieve the current URI based on the defined siteMap within the libs\u002Fquery-api.ts.\nIt enhances multisite support and simplifies querying data from your Craft CMS backend.",{"id":3718,"title":34,"titles":3719,"content":3720,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-uri#usage",[457],"const uri = useCraftUri(); To use this hook, you must define your sites in the siteMap property in the libs\u002Fquery-api.ts. By default it returns the current site based on the path defined in the siteMap property in your libs\u002Fquery-api.ts. You can change this behavior by changing the\nsiteDetectionMode to origin. You can read more about that in the configuration docs.",{"id":3722,"title":3313,"titles":3723,"content":3724,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-uri#sitedetectionmode-path",[457,34],"\u002F\u002F Url: http:\u002F\u002Flocalhost:3000\u002Fde\u002Fhappy-trying\n\u002F\u002F\n\u002F\u002F  craftInit({\n\u002F\u002F    siteDetectionMode: 'path',\n\u002F\u002F    siteMap: [\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      },\n\u002F\u002F      {\n\u002F\u002F        handle: 'de',\n\u002F\u002F        origin: 'http:\u002F\u002Flocalhost:3000',\n\u002F\u002F        path: '\u002Fde',\n\u002F\u002F      }\n\u002F\u002F    ],\n\u002F\u002F  })\nconst uri = useCraftUri();\n\n\u002F\u002F uri will result in: \"happy-trying\"",{"id":3726,"title":3318,"titles":3727,"content":3728,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-uri#sitedetectionmode-origin",[457,34],"\u002F\u002F Url: https:\u002F\u002Fen-site.ddev.site\u002Fhappy-trying\n\u002F\u002F\n\u002F\u002F \u002Flibs\u002Fquery-api.ts\n\u002F\u002F  craftInit({\n\u002F\u002F    siteDetectionMode: 'origin',\n\u002F\u002F    siteMap: [\n\u002F\u002F      {\n\u002F\u002F        handle: 'en',\n\u002F\u002F        origin: 'https:\u002F\u002Fen-site.ddev.site',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      },\n\u002F\u002F      {\n\u002F\u002F        handle: 'de',\n\u002F\u002F        origin: 'https:\u002F\u002Fde-site.ddev.site',\n\u002F\u002F        path: '\u002F',\n\u002F\u002F      }\n\u002F\u002F    ],\n\u002F\u002F  })\n\nconst uri = useCraftUri();\n\n\u002F\u002F uri will result in: \"happy-trying\"",{"id":3730,"title":3328,"titles":3731,"content":3732,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-uri#type",[457],"export function useCraftUri(): string html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"id":558,"title":469,"titles":3734,"content":3735,"level":713},[],"Learn how to use the useCraftAuthToken hook. This hook returns the Bearer auth token defined in your \u002Flibs\u002Fquery-api.ts.",{"id":3737,"title":34,"titles":3738,"content":3393,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-auth-token#usage",[469],{"id":3740,"title":3328,"titles":3741,"content":3397,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fhooks\u002Fuse-craft-auth-token#type",[469],{"id":565,"title":478,"titles":3743,"content":3744,"level":713},[],"Learn how to use the CraftPage component. The CraftPage component renders the mapped React page based on your queried data and the contentMapping.pages property in your craftInit() configuration. You can read more about configuring pages in the configuration docs. import { CraftPage } from '@query-api\u002Fnext'\nimport { CraftPageBase } from '@\u002Ftypes\u002Fbase'\n\nexport default async function CraftCatchPage() {\n  const { data, error } = await getCraftEntry\u003CCraftPageBase>().uri('__home__').one()\n  return \u003CCraftPage content={data} \u002F>\n} content: The queried data from Craft CMS. This should be an object containing the section handle and its corresponding data.",{"id":3746,"title":34,"titles":3747,"content":3748,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fcomponents\u002Fcraft-page#usage",[478],"Typically the CraftPage component is used within a catch-all route in your Next.js application. This allows it to handle all paths and render the appropriate page based on the queried data. If you are curious how to set this up, you can have a look into the manual setup guide.",{"id":3750,"title":3751,"titles":3752,"content":3753,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fcomponents\u002Fcraft-page#error-handling","Error Handling",[478],"If you're using a catch-all route, you can add a Error pages to your contentMapping.pages mapping.\nThis ensures that any unmapped or erroneous sections gracefully display an error page, improving user experience and preventing unexpected behavior. You can read more about error pages in the configuration docs. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":568,"title":482,"titles":3755,"content":3756,"level":713},[],"Learn how to use the CraftArea component. The CraftArea component renders the mapped React component based on your queried data and the contentMapping.components property in your craftInit() configuration. You can read more about configuring components in the configuration docs. import { CraftArea } from '@query-api\u002Fnext'\nimport { CraftPageHome } from '@\u002Ftypes\u002Fbase'\n\nexport default function Home(props: CraftPageHome) {\n  return (\n    \u003Cdiv>\n      \u003CCraftArea content={props.contentBuilder} \u002F>\n    \u003C\u002Fdiv>\n  )\n} content: The queried data from Craft CMS. This should be an array of objects containing the block types and their corresponding data.",{"id":3758,"title":34,"titles":3759,"content":3760,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fcomponents\u002Fcraft-area#usage",[482],"Typically the CraftArea component is used within a Next.js page to render matrix blocks. If you are curious how to set this up, you can have a look into the quick start guide. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":571,"title":486,"titles":3762,"content":3763,"level":713},[],"Learn how to use the CraftNotImplemented component. The CraftNotImplemented component is a small development helper with the following purposes: Display Unimplemented Components or Pages: Shows a message indicating any block type that hasn’t been implemented yet.Show the data: Outputs the data in a readable format for easier debugging.",{"id":3765,"title":34,"titles":3766,"content":3767,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fcomponents\u002Fcraft-not-implemented#usage",[486],"You can use the CraftNotImplemented component in your contentMapping configuration to handle cases where a specific page or component has not been implemented yet. import { craftInit, CraftNotImplemented } from '@query-api\u002Fnext'\n\ncraftInit({\n  ...otherConfig,\n  contentMapping: {\n    pages: {\n      home: CraftNotImplemented,\n    },\n    components: {\n      imageText: CraftNotImplemented,\n    },\n  },\n}) html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":579,"title":574,"titles":3769,"content":3770,"level":713},[],"Learn how you can use all middleware functions. import { createQueryApiMiddleware } from '@query-api\u002Fnext\u002Fserver'\n\nexport default createQueryApiMiddleware()\n\nexport const config = {\n  \u002F\u002F Match all pathnames except for\n  \u002F\u002F - … if they start with `\u002Fapi`, `\u002Ftrpc`, `\u002F_next` or `\u002F_vercel`\n  \u002F\u002F - … the ones containing a dot (e.g. `favicon.ico`)\n  matcher: '\u002F((?!api|trpc|_next|_vercel|.*\\\\..*).*)',\n} The middleware intercepts every incoming page request before it reaches your Server Components. Its primary job is to: Read the Request URL: It extracts key information from the URL, such as the page path (e.g., \u002Fabout-us, \u002Fnews\u002Fmy-article) and any Craft CMS preview parameters (e.g., ?token=..., ?x-craft-preview=...).Write to Headers: It copies this information into the response headers. For example, it might set a header like craft-path: \u002Fnews\u002Fmy-article.",{"id":3772,"title":3773,"titles":3774,"content":3775,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fmiddleware\u002Fmiddleware#why-its-necessary","Why It's Necessary:",[574],"The middleware is essential because of a core design principle in the Next.js App Router: Server Components cannot directly access the incoming request object. This means a Server Component has no way of knowing the URL path or its query parameters. However, Server Components can read request headers. The middleware solves this problem by acting as a bridge. It translates the request URL information into headers, making that data accessible to Server Components so they know which content to fetch and render.",{"id":3777,"title":3778,"titles":3779,"content":3780,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fmiddleware\u002Fmiddleware#how-helper-functions-work","How Helper Functions Work",[574],"Functions like getCraftUri(), getCraftCurrentSite(), and getCraftEntry() are designed to work with the middleware automatically. The connection is the headers() function provided by next\u002Fheaders. Here’s the simple workflow: Middleware (The Writer): The middleware intercepts a request and writes the URL path to a header. Think of it like putting a sticky note on a file.Helper Function (The Reader): When you call a function like getCraftUri() in a Server Component, it uses the Next.js headers() function to find and read that \"sticky note.\" It knows exactly which header to look for. This provides a clean and simple developer experience. You don't need to manage headers manually; you just call a function, and it automatically gets the context it needs from the headers set by the middleware.",{"id":3782,"title":3783,"titles":3784,"content":3785,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fmiddleware\u002Fmiddleware#middleware-examples","Middleware examples",[574],"Here is the most straight forward example. The createQueryApiMiddleware function creates a middleware and sets all headers that are needed. import { createQueryApiMiddleware } from '@query-api\u002Fnext\u002Fserver'\n\nexport default createQueryApiMiddleware()\n\nexport const config = {\n  \u002F\u002F Match all pathnames except for\n  \u002F\u002F - … if they start with `\u002Fapi`, `\u002Ftrpc`, `\u002F_next` or `\u002F_vercel`\n  \u002F\u002F - … the ones containing a dot (e.g. `favicon.ico`)\n  matcher: '\u002F((?!api|trpc|_next|_vercel|.*\\\\..*).*)',\n} If you need more control you can use the setCraftHeaders function.\nThis function will return a response that you can use to modify further. import { setCraftHeaders } from '@query-api\u002Fnext\u002Fserver'\nimport { NextRequest, NextResponse } from 'next\u002Fserver'\n\nexport default function middleware(req: NextRequest) {\n  let res = NextResponse.next()\n  res = setCraftHeaders(res, req)\n  return res\n}\n\nexport const config = {\n  \u002F\u002F Match all pathnames except for\n  \u002F\u002F - … if they start with `\u002Fapi`, `\u002Ftrpc`, `\u002F_next` or `\u002F_vercel`\n  \u002F\u002F - … the ones containing a dot (e.g. `favicon.ico`)\n  matcher: '\u002F((?!api|trpc|_next|_vercel|.*\\\\..*).*)',\n}",{"id":3787,"title":3788,"titles":3789,"content":3790,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fmiddleware\u002Fmiddleware#matcher-config","Matcher Config",[574],"The middleware is intended to run only on pages, not on static files like \u002Ffavicon.ico. A popular strategy is to match all routes that don’t start with certain segments (e.g. \u002F_next) and also none that include a dot (.) since these typically indicate static files. However, if you have some routes where a dot is expected (e.g. \u002Fusers\u002Fjane.doe), you should explicitly provide a matcher for these. export const config = {\n  \u002F\u002F Matcher entries are linked with a logical \"or\", therefore\n  \u002F\u002F if one of them matches, the middleware will be invoked.\n  matcher: [\n    \u002F\u002F Match all pathnames except for\n    \u002F\u002F - … if they start with `\u002Fapi`, `\u002Ftrpc`, `\u002F_next` or `\u002F_vercel`\n    \u002F\u002F - … the ones containing a dot (e.g. `favicon.ico`)\n    '\u002F((?!api|_next|_vercel|.*\\\\..*).*)',\n \n    \u002F\u002F However, match all pathnames within `\u002Fusers`, optionally with a locale prefix\n    '\u002F([\\\\w-]+)?\u002Fusers\u002F(.+)'\n  ]\n};",{"id":3792,"title":3793,"titles":3794,"content":3795,"level":719},"\u002Flibraries\u002Fquery-api-next\u002Fmiddleware\u002Fmiddleware#get-craft-headers","Get Craft Headers",[574],"If you ever need to access some of the headers that the Query API SDK sets, you can use the following functions:",{"id":3797,"title":3798,"titles":3799,"content":3800,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fmiddleware\u002Fmiddleware#getcraftsiteheaders","getCraftSiteHeaders()",[574,3793],"This will return an object with all relevant request context data. import { getCraftSiteHeaders } from '@query-api\u002Fnext\u002Fserver'\n\nexport default async function News() {\n  const siteHeaders = await getCraftSiteHeaders()\n  return \u003Cp>{JSON.stringify(siteHeaders)}\u003C\u002Fp>\n}",{"id":3802,"title":3328,"titles":3803,"content":3804,"level":2800},"\u002Flibraries\u002Fquery-api-next\u002Fmiddleware\u002Fmiddleware#type",[574,3793,3798],"export async function getCraftSiteHeaders(): Promise\u003C{\n    origin: string | null;\n    path: string | null;\n    url: string | null;\n}>",{"id":3806,"title":3807,"titles":3808,"content":3809,"level":740},"\u002Flibraries\u002Fquery-api-next\u002Fmiddleware\u002Fmiddleware#getcraftpreviewheaders","getCraftPreviewHeaders()",[574,3793],"This will return an object with all preview parameters in the current request context. import { getCraftPreviewHeaders } from '@query-api\u002Fnext\u002Fserver'\n\nexport default async function News() {\n  const previewHeaders = await getCraftPreviewHeaders()\n  return \u003Cp>{JSON.stringify(previewHeaders)}\u003C\u002Fp>\n}",{"id":3811,"title":3328,"titles":3812,"content":3813,"level":2800},"\u002Flibraries\u002Fquery-api-next\u002Fmiddleware\u002Fmiddleware#type-1",[574,3793,3807],"\u002F\u002F key is always one of the PREVIEW_PARAMS and value is the actual query param value\n\u002F\u002F const PREVIEW_PARAMS = ['token', 'x-craft-preview', 'x-craft-live-preview']\n\nexport async function getCraftPreviewHeaders(): Promise\u003CRecord\u003Cstring, string>> html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}",{"id":583,"title":582,"titles":3815,"content":3816,"level":713},[],"A library for using the Craft CMS query builder in React.",{"id":3818,"title":1168,"titles":3819,"content":3820,"level":719},"\u002Flibraries\u002Fquery-api-react#features",[582],"Query builder: Easily build and execute queries directly from Next.js, enabling flexible, real-time data retrieval from Craft CMSData Driven Components: Connect your data directly with your Vue components, to speed up development.Get Only the Data You Need: Avoid overfetching by using a custom function in the query builder to select only the fields you require.Pretty JSON: JSON transformers are in place to format the response for better readability.Support for Main Element Types: Query addresses, assets, entries and users.Full TypeScript Support: A fully-typed query builder for Craft CMS. Pretty cool, huh? 😎Multisite Helpers: Built-in helpers to support Craft Multisites.",{"id":3822,"title":440,"titles":3823,"content":3824,"level":719},"\u002Flibraries\u002Fquery-api-react#examples",[582],"Want to see how it works? const { data, loading, error } = useCraftEntry()\n  .section('news')\n  .fields(['title']) \u002F\u002F add more field handles if you like\n  .limit(3)\n  .all() It is as simple as that. 🚀 The response will contain three entries from the 'news' section.",{"id":3826,"title":2974,"titles":3827,"content":3828,"level":719},"\u002Flibraries\u002Fquery-api-react#further-resources",[582],"Craft Query API: A Craft CMS Plugin, that powers this great stuff.Next SDK: A package to use the query builder in Next.js.JS SDK: Foundation to build a query builder with your preferred JS framework. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":591,"title":274,"titles":3830,"content":3831,"level":713},[],"Learn how to use the @query-api\u002Freact library in React. The @query-api\u002Freact package provides a powerful query builder for React, enabling you to build URLs for fetching data from Craft CMS in a way similar to Twig queries. It allows you to connect your Craft CMS sections and entry types to React components, making it easy to render dynamic content in your React applications.",{"id":3833,"title":716,"titles":3834,"content":3835,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fintroduction#requirements",[274],"The Craft Query API plugin must be installed and properly configured in Craft CMS.",{"id":3837,"title":2532,"titles":3838,"content":3839,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fintroduction#supported-element-types",[274],"The library supports building urls for the following Craft CMS element types: AddressesAssetsEntriesUsers",{"id":3841,"title":2537,"titles":3842,"content":2539,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fintroduction#need-help",[274],{"id":594,"title":414,"titles":3844,"content":3845,"level":713},[],"Use the create-query-api CLI to scaffold a new @query-api\u002Freact project.",{"id":3847,"title":716,"titles":3848,"content":3428,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fquick-start#requirements",[414],{"id":3850,"title":107,"titles":3851,"content":3852,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fquick-start#installation",[414],"The fastest way to get started is with the create-query-api command-line tool. It scaffolds a complete project for you, including a pre-configured Craft CMS and a React frontend. Open your terminal and run the following command: npx create-query-api@latest query-api-react --template react-vite",{"id":3854,"title":3093,"titles":3855,"content":3856,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fquick-start#manual-installation",[414],"If you want to integrate the @query-api\u002Freact-vite SDK into an existing React project or want to understand the setup process step by step, you can head over to the Manual Setup Guide html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":597,"title":418,"titles":3858,"content":3859,"level":713},[],"Learn how to install and configure the @query-api\u002Fnext package for your React project. This guide is for developers who want to integrate the Query API into an existing React project or for those who want to understand the setup process step-by-step. If you prefer to dive straight into code, you can check out the React demo project on GitHub.",{"id":3861,"title":1390,"titles":3862,"content":3102,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fmanual-setup#prerequisites",[418],{"id":3864,"title":3865,"titles":3866,"content":3867,"level":740},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fmanual-setup#_2-react-app","2. React App",[418,1390],"You'll need a React application. If you're starting from scratch, you can create one inside your Craft project's root folder. npm create vite@latest frontend -- --template react-ts If you set up your Craft CMS project with the starter cli craft-only template, ensure that the\ndev server url (https:\u002F\u002Flocalhost:5173) matches the WEBSITE_URL environment variable in the .env of your Craft CMS project. You can now open the frontend directory in your code editor to begin the setup.",{"id":3869,"title":3870,"titles":3871,"content":3872,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fmanual-setup#installations-and-folder-structure","Installations and Folder Structure",[418],"First, install the @query-api\u002Freact SDK and react-router in your React project. npm install @query-api\u002Freact react-router Next, create the following folder and file structure inside your src directory. This structure helps organize your code by separating concerns. ├── src\n│   ├── components\n│   │   ├── content\n│   │   │   ├── BlockHeadline.tsx\n│   │   │   ├── ViewHome.tsx\n│   ├── libs\n│   │   └── query-api.ts\n│   ├── types\n│   │   └── base.ts\n│   ├── App.tsx\n│   ├── CraftRouter.tsx\n│   ├── main.tsx\n│   └── vite-env.d.ts\n├── .env",{"id":3874,"title":3115,"titles":3875,"content":3876,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fmanual-setup#environment-variables",[418],"Create a .env file in the root of your Next.js project to store your Craft CMS connection details. # The base URL of your Craft CMS backend.\nVITE_CRAFT_BASE_URL=https:\u002F\u002Fquery-api-starter.ddev.site\n\n# The bearer token you generated in the Query API plugin settings.\nVITE_CRAFT_AUTH_TOKEN=\"Bearer sqKTlMFsky_OeJVeDfnps75b2Gny4NBG\" # Default of create-query-api starter template You can find\u002Fcreate the bearer token under \u002Fadmin\u002Fquery-api\u002Ftokens in the control panel.",{"id":3878,"title":3120,"titles":3879,"content":734,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fmanual-setup#generate-types",[418],{"id":3881,"title":432,"titles":3882,"content":3883,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fmanual-setup#content-driven-components",[418],"These are the React components that will render your Craft CMS content. We recommend placing them in a dedicated components\u002Fcontent directory to distinguish them from general-purpose UI components. Here is an example of a component for a headline entry type that is used in a matrix block. import type { CraftEntryTypeHeadline } from '..\u002F..\u002Ftypes\u002Fbase'\n\n\u002F\u002F This component renders a headline from a Matrix block.\n\u002F\u002F The props are fully typed based on the generated `base.ts` file.\nexport default function Headline(props: CraftEntryTypeHeadline) {\n  \u002F\u002F The `selectHeadlineTag` field is a dropdown in Craft,\n  \u002F\u002F allowing content editors to choose the HTML tag (e.g., h1, h2).\n  const Tag = props.selectHeadlineTag.value\n  return \u003CTag>{props.title}\u003C\u002FTag>\n} Next, create the main view component for your home section. import { CraftArea } from '@query-api\u002Freact'\nimport type { CraftPageHome } from '..\u002F..\u002Ftypes\u002Fbase'\n\n\u002F\u002F This component renders the \"Home\" page.\nexport default function Home(props: CraftPageHome) {\n  return (\n    \u003Cdiv>\n      {\u002F* `translatablePlainText` is a field from our Craft entry. *\u002F}\n      \u003Ch1>{props.translatablePlainText}\u003C\u002Fh1>\n\n      {\u002F* The CraftArea component dynamically renders Matrix blocks. *\u002F}\n      {\u002F* It takes the `contentBuilder` field (a Matrix field) and maps each block *\u002F}\n      {\u002F* to the corresponding component defined in `query-api.ts`. *\u002F}\n      \u003CCraftArea content={props.contentBuilder} \u002F>\n    \u003C\u002Fdiv>\n  )\n}",{"id":3885,"title":3124,"titles":3886,"content":3887,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fmanual-setup#query-api-configuration",[418],"This file initializes the Query API client and defines the contentMapping, which tells the library which React components to use for different Craft CMS pages and entry types. import { craftInit, CraftNotImplemented } from '@query-api\u002Freact'\n\n\u002F\u002F Import the components that will render Craft CMS content.\nimport ViewHome from '..\u002Fcomponents\u002Fcontent\u002FViewHome'\nimport BlockHeadline from '..\u002Fcomponents\u002Fcontent\u002FBlockHeadline'\n\nexport const craftConfig = craftInit({\n  baseUrl: import.meta.env.VITE_CRAFT_BASE_URL,\n  authToken: import.meta.env.VITE_CRAFT_AUTH_TOKEN,\n  \n  \u002F\u002F Define a site map for multi-site setups.\n  siteMap: [\n    { handle: 'en', path: '\u002F', origin: 'http:\u002F\u002Flocalhost:5173', id: 1 },\n    { handle: 'de', path: '\u002Fde', origin: 'http:\u002F\u002Flocalhost:5173', id: 2 },\n    { handle: 'es', path: '\u002Fes', origin: 'http:\u002F\u002Flocalhost:5173', id: 3 },\n  ],\n\n  \u002F\u002F The contentMapping connects Craft handles to your React components.\n  contentMapping: {\n    \u002F\u002F `pages` maps a section handle (e.g., \"home\") to a view component.\n    pages: {\n      home: ViewHome,\n    },\n    \u002F\u002F `components` maps a block type handle (e.g., \"headline\") to a component.\n    \u002F\u002F This is typically used for Matrix blocks.\n    components: {\n      headline: BlockHeadline,\n      \u002F\u002F Use CraftNotImplemented as a placeholder for components you haven't created yet.\n      text: CraftNotImplemented,\n      imageAndText: CraftNotImplemented,\n      image: CraftNotImplemented,\n    }\n  }\n})",{"id":3889,"title":3890,"titles":3891,"content":3892,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fmanual-setup#router-setup","Router Setup",[418],"We need to use the useLocation() hook in the App later on, that's why we need to wrap the \u003CApp \u002F> with the BrowserRouter Provider. import { StrictMode } from 'react'\nimport { BrowserRouter } from 'react-router'\nimport * as ReactDOM from 'react-dom\u002Fclient'\nimport App from '.\u002FApp'\n\nconst root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)\nroot.render(\n  \u003CStrictMode>\n    \u003CBrowserRouter>\n      \u003CApp \u002F>\n    \u003C\u002FBrowserRouter>\n  \u003C\u002FStrictMode>\n)",{"id":3894,"title":3895,"titles":3896,"content":3897,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fmanual-setup#catch-all-component","Catch-All Component",[418],"This component will be the router for all Craft CMS pages.\nWe basically query the data based on the current url and render the matching React Component. import {\n  CraftPage,\n  useCraftCurrentSite,\n  useCraftEntry,\n  useCraftUri,\n} from '@query-api\u002Freact'\nimport type { CraftPageBase } from '.\u002Ftypes\u002Fbase'\n\nexport default function CraftRouter() {\n  const uri = useCraftUri()\n  const { id: siteId } = useCraftCurrentSite()\n\n  const { data, loading, error } = useCraftEntry\u003CCraftPageBase>()\n    .uri(uri)\n    .siteId(siteId)\n    .one()\n\n  if (error) {\n    console.error(error)\n  }\n  return \u003Cdiv>{!loading && data && \u003CCraftPage content={data} \u002F>}\u003C\u002Fdiv>\n}",{"id":3899,"title":3900,"titles":3901,"content":3902,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fmanual-setup#app-setup","App Setup",[418],"The CraftProvider must wrap your root layout to make the configuration available to all components. import { Route, Routes, Link, useLocation } from 'react-router'\nimport CraftRouter from '.\u002FCraftRouter'\nimport { CraftProvider, getCraftLocation } from '@query-api\u002Freact'\nimport { craftConfig } from '.\u002Flibs\u002Fquery-api'\n\nexport function App() {\n  const location = getCraftLocation(useLocation())\n  return (\n    \u003CCraftProvider config={craftConfig} location={location}>\n      \u003Cdiv>\n        \u003Cnav>\n          \u003Cul>\n            \u003Cli>\u003CLink to=\"\u002F\">Home\u003C\u002FLink>\u003C\u002Fli>\n            \u003Cli>\u003CLink to=\"\u002Fde\">Home DE\u003C\u002FLink>\u003C\u002Fli>\n            \u003Cli>\u003CLink to=\"\u002Fes\">Home ES\u003C\u002FLink>\u003C\u002Fli>\n          \u003C\u002Ful>\n        \u003C\u002Fnav>\n        \u003CRoutes>\n          \u003CRoute path=\"*\" element={\u003CCraftRouter \u002F>} \u002F>\n        \u003C\u002FRoutes>\n      \u003C\u002Fdiv>\n    \u003C\u002FCraftProvider>\n  )\n}\n\nexport default App With this setup, navigating to any page on your React site will trigger a fetch to your Craft CMS backend, and the correct content will be rendered automatically. It's as simple as that! 🚀",{"id":3904,"title":3143,"titles":3905,"content":3906,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fmanual-setup#anything-missing",[418],"If you have questions, run into issues, or have ideas for improvements, your feedback is very welcome! Please don't hesitate to open an issue on GitHub. Whether it's a bug report, a feature request, or a general suggestion, your input helps make this project better for everyone. html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}",{"id":600,"title":29,"titles":3908,"content":3909,"level":713},[],"Learn how to configure the @query-api\u002Freact package for your React application. The @query-api\u002Freact package is configured by calling the craftInit function. This function initializes the Query API client with your Craft CMS backend details and maps your React components to Craft CMS entries and blocks. Typically, you will do this in a dedicated file, such as libs\u002Fquery-api.ts, to keep your configuration organized and easily accessible.",{"id":3911,"title":3151,"titles":3912,"content":3504,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fconfiguration#example-configuration",[29],{"id":3914,"title":3156,"titles":3915,"content":734,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fconfiguration#configuration-options",[29],{"id":3917,"title":3160,"titles":3918,"content":3162,"level":740},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fconfiguration#baseurl",[29,3156],{"id":3920,"title":3165,"titles":3921,"content":3167,"level":740},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fconfiguration#authtoken",[29,3156],{"id":3923,"title":3516,"titles":3924,"content":3925,"level":740},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fconfiguration#contentmapping",[29,3156],"The contentMapping option lets you connect your Craft CMS sections and entry types to React components. In pages, use sectionHandle:entryTypeHandle (e.g., news:home) to map to a React page. If the entry type is the same as the section handle or is default, just use the section handle (e.g., home). To turn off sectionHandle:entryTypeHandle mapping, set enableEntryTypeMapping: false in craftInit. In components, map entry types to React components. This is useful for things like matrix blocks. Type: objectDefault: { pages: {}, components: {} }Example: contentMapping: {\n  pages: {\n    home: Home, \u002F\u002F Maps section home entry with entry type home to the Home component.\n    'news:home': News, \u002F\u002F Maps section news entry with entry type home to the News component.\n  },\n  components: {\n    headline: Headline, \u002F\u002F Entry type headline will be rendered with the Headline component.\n    imageText: CraftNotImplemented,\n  },\n}",{"id":3927,"title":3521,"titles":3928,"content":3929,"level":2800},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fconfiguration#error-pages",[29,3156,3516],"You can also map error pages by providing special keys in the contentMapping.pages object. This allows you to render custom React components for specific error scenarios. page404: For 404 Not Found errors.page500: For 500 Internal Server Error responses from Craft.error: A general fallback for other errors.",{"id":3931,"title":3170,"titles":3932,"content":3172,"level":740},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fconfiguration#sitemap",[29,3156],{"id":3934,"title":902,"titles":3935,"content":3176,"level":740},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fconfiguration#debug",[29,3156],{"id":3937,"title":3179,"titles":3938,"content":3181,"level":740},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fconfiguration#enableentrytypemapping",[29,3156],{"id":3940,"title":3184,"titles":3941,"content":3186,"level":740},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fconfiguration#sitedetectionmode",[29,3156],{"id":3943,"title":3194,"titles":3944,"content":3945,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fget-started\u002Fconfiguration#default-configuration",[29],"This is the default configuration for the @query-api\u002Freact package. export const defaultCraftOptions {\n  baseUrl: '',\n  authToken: '',\n  contentMapping: { pages: {}, components: {} },\n  debug: false,\n  enableEntryTypeMapping: true,\n  siteDetectionMode: siteDetectionModes.PATH,\n  siteMap: [],\n} html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}",{"id":607,"title":449,"titles":3947,"content":3948,"level":713},[],"Learn how to use the useCraftQuery hook. This hook provides a simple way to fetch data from your Craft CMS Backend.\nIt leverages the JS SDK to build query URLs and the fetch Web API for fetching data in Client Components.",{"id":3950,"title":3282,"titles":3951,"content":3664,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-query#element-types",[449],{"id":3953,"title":3287,"titles":3954,"content":3668,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-query#execute-query",[449],{"id":3956,"title":3292,"titles":3957,"content":3672,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-query#available-methods",[449],{"id":3959,"title":681,"titles":3960,"content":3961,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-query#example",[449],"\u002F\u002F fetch without type definition\nconst { data, error, loading } = useCraftQuery('entries')\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()\n\n\u002F\u002F with type definition\ntype CraftEntry = {\n  title: string\n}\nconst { data, error, loading } = useCraftQuery\u003CCraftEntry, 'entries'>('entries')\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()\n\n\u002F\u002F or using the shorthand\nconst { data, error, loading } = useCraftEntry\u003CCraftEntry>()\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .all()",{"id":3963,"title":3301,"titles":3964,"content":3680,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-query#types",[449],{"id":610,"title":548,"titles":3966,"content":3683,"level":713},[],{"id":3968,"title":34,"titles":3969,"content":3687,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-data#usage",[548],{"id":3971,"title":3328,"titles":3972,"content":3691,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-data#type",[548],{"id":613,"title":453,"titles":3974,"content":3694,"level":713},[],{"id":3976,"title":34,"titles":3977,"content":3698,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-current-site#usage",[453],{"id":3979,"title":3313,"titles":3980,"content":3702,"level":740},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-current-site#sitedetectionmode-path",[453,34],{"id":3982,"title":3318,"titles":3983,"content":3706,"level":740},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-current-site#sitedetectionmode-origin",[453,34],{"id":3985,"title":3323,"titles":3986,"content":3325,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-current-site#no-site-found",[453],{"id":3988,"title":3328,"titles":3989,"content":3713,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-current-site#type",[453],{"id":616,"title":457,"titles":3991,"content":3716,"level":713},[],{"id":3993,"title":34,"titles":3994,"content":3720,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-uri#usage",[457],{"id":3996,"title":3313,"titles":3997,"content":3724,"level":740},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-uri#sitedetectionmode-path",[457,34],{"id":3999,"title":3318,"titles":4000,"content":3728,"level":740},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-uri#sitedetectionmode-origin",[457,34],{"id":4002,"title":3328,"titles":4003,"content":3732,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-uri#type",[457],{"id":619,"title":469,"titles":4005,"content":3735,"level":713},[],{"id":4007,"title":34,"titles":4008,"content":3393,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-auth-token#usage",[469],{"id":4010,"title":3328,"titles":4011,"content":3397,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fhooks\u002Fuse-craft-auth-token#type",[469],{"id":626,"title":478,"titles":4013,"content":4014,"level":713},[],"Learn how to use the CraftPage component. The CraftPage component renders the mapped React page based on your queried data and the contentMapping.pages property in your craftInit() configuration. You can read more about configuring pages in the configuration docs. import { CraftPage, useCraftEntry } from '@query-api\u002Freact'\nimport type { CraftPageBase } from '.\u002Ftypes\u002Fbase'\n\nexport default function CraftRouter() {\n  const { data, loading, error } = useCraftEntry\u003CCraftPageBase>().uri('__home__').one()\n  return \u003Cdiv>{!loading && data && \u003CCraftPage content={data} \u002F>}\u003C\u002Fdiv>\n} content: The queried data from Craft CMS. This should be an object containing the section handle and its corresponding data.",{"id":4016,"title":34,"titles":4017,"content":4018,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fcomponents\u002Fcraft-page#usage",[478],"Typically the CraftPage component is used within a catch-all route in your React application. This allows it to handle all paths and render the appropriate page based on the queried data. If you are curious how to set this up, you can have a look into the manual setup guide.",{"id":4020,"title":3751,"titles":4021,"content":4022,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fcomponents\u002Fcraft-page#error-handling",[478],"If you're using a catch-all route, you can add a Error pages to your contentMapping.pages mapping.\nThis ensures that any unmapped or erroneous sections gracefully display an error page, improving user experience and preventing unexpected behavior. You can read more about error pages in the configuration docs. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":629,"title":482,"titles":4024,"content":4025,"level":713},[],"Learn how to use the CraftArea component. The CraftArea component renders the mapped React component based on your queried data and the contentMapping.components property in your craftInit() configuration. You can read more about configuring components in the configuration docs. import { CraftArea } from '@query-api\u002Freact'\nimport type { CraftPageHome } from '..\u002F..\u002Ftypes\u002Fbase'\n\n\u002F\u002F This component renders the \"Home\" page.\nexport default function Home(props: CraftPageHome) {\n  return (\n    \u003Cdiv>\n      {\u002F* The CraftArea component dynamically renders Matrix blocks. *\u002F}\n      {\u002F* It takes the `contentBuilder` field (a Matrix field) and maps each block *\u002F}\n      {\u002F* to the corresponding component defined in `query-api.ts`. *\u002F}\n      \u003CCraftArea content={props.contentBuilder} \u002F>\n    \u003C\u002Fdiv>\n  )\n} content: The queried data from Craft CMS. This should be an array of objects containing the block types and their corresponding data.",{"id":4027,"title":34,"titles":4028,"content":4029,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fcomponents\u002Fcraft-area#usage",[482],"Typically the CraftArea component is used within a Next.js page to render matrix blocks. If you are curious how to set this up, you can have a look into the  quick start guide. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":632,"title":486,"titles":4031,"content":3763,"level":713},[],{"id":4033,"title":34,"titles":4034,"content":4035,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Fcomponents\u002Fcraft-not-implemented#usage",[486],"You can use the CraftNotImplemented component in your contentMapping configuration to handle cases where a specific page or component has not been implemented yet. import { craftInit, CraftNotImplemented } from '@query-api\u002Freact'\n\ncraftInit({\n  ...otherConfig,\n  contentMapping: {\n    pages: {\n      home: CraftNotImplemented,\n    },\n    components: {\n      imageText: CraftNotImplemented,\n    },\n  },\n}) html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":640,"title":639,"titles":4037,"content":4038,"level":713},[],"Learn how to use the getCraftLocation function. You can use this function to get the current location of the request.\nTypically it should be used in the app.tsx where you define your CraftProvider. import { seLocation } from 'react-router'\n\nexport function App() {\n  const location = getCraftLocation(useLocation())\n  return (\n    \u003CCraftProvider location={location}>\n      \u003Cdiv>\u003C\u002Fdiv>\n    \u003C\u002FCraftProvider>\n  )\n}",{"id":4040,"title":3301,"titles":4041,"content":4042,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Ffunctions\u002Fget-craft-location#types",[639],"export function getCraftLocation(location: Location): {\n    pathname: string;\n    absoluteUrl: string;\n} html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":644,"title":643,"titles":4044,"content":4045,"level":713},[],"Learn how to get the Craft instance with getCraftInstance. This function provides access to the Craft instance, allowing you to retrieve configuration details like the base URL and authentication token. const craftInstance = getCraftInstance()",{"id":4047,"title":4048,"titles":4049,"content":4050,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Ffunctions\u002Fget-craft-instance#return-type","Return Type",[643],"type CraftOptions = {\n  baseUrl: string\n  authToken: string\n  contentMapping: ContentMapping\n  debug?: boolean\n  enableEntryTypeMapping?: boolean\n  siteMap?: CraftSites\n  siteDetectionMode?: SiteDetectionMode\n} html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":648,"title":647,"titles":4052,"content":4053,"level":713},[],"Learn how to get the contentMapping with getCraftContentMapping. If you just need the content mapping, you can use the getCraftContentMapping function: const contentMapping = getCraftContentMapping()",{"id":4055,"title":4048,"titles":4056,"content":4057,"level":719},"\u002Flibraries\u002Fquery-api-react\u002Ffunctions\u002Fget-craft-content-mapping#return-type",[647],"type ContentMapping = {\n  pages:\n  {\n    [key: string]: React.ElementType\n    page404: React.ElementType\n    page500: React.ElementType\n    error: React.ElementType\n  }\n  components: {\n    [key: string]: React.ElementType\n  }\n} html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":652,"title":651,"titles":4059,"content":4060,"level":713},[],"A library for using the Craft CMS query builder in Vue.",{"id":4062,"title":1168,"titles":4063,"content":4064,"level":719},"\u002Flibraries\u002Fvue-craftcms#features",[651],"Craft CMS query url builder: Easily build urls for the Craft Query API plugin directly from Vue, enabling flexible, real-time data retrieval from Craft CMSBuilt in Helper Components: Connect your data directly with your Vue components, to speed up development.Get Only the Data You Need: Avoid overfetching by using a custom function in the query builder to select only the fields you require.Pretty Json: Json Transformer are in place to prettify the response.Support for main Element Types: Query addresses, assets, entries and users.",{"id":4066,"title":440,"titles":4067,"content":4068,"level":719},"\u002Flibraries\u002Fvue-craftcms#examples",[651],"Want to see how it works? const queryUrl = useCraftUrlBuilder('entries')\n  .id(1)\n  .status('active')\n  .siteId(1)\n  .buildUrl('one') It is as simple as that. 🚀 The response will be the url that you can use to fetch your data.",{"id":4070,"title":2974,"titles":4071,"content":4072,"level":719},"\u002Flibraries\u002Fvue-craftcms#further-resources",[651],"Craft Query API: A Craft CMS Plugin, that powers this great stuff.Nuxt SDK: A package to use the query builder in Nuxt.JS SDK: Foundation to build a query builder with your preferred JS framework. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":660,"title":274,"titles":4074,"content":4075,"level":713},[],"Learn how to use the @query-api\u002Fvue library in Vue. The @query-api\u002Fvue package provides a powerful query builder for Vue, enabling you to build URLs for fetching data from Craft CMS in a way similar to Twig queries.",{"id":4077,"title":716,"titles":4078,"content":4079,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fget-started\u002Fintroduction#requirements",[274],"The Craft Query API plugin must be installed and properly configured in Craft CMS.Vue 3 is required.",{"id":4081,"title":2532,"titles":4082,"content":3839,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fget-started\u002Fintroduction#supported-element-types",[274],{"id":4084,"title":2537,"titles":4085,"content":2539,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fget-started\u002Fintroduction#need-help",[274],{"id":663,"title":107,"titles":4087,"content":4088,"level":713},[],"Learn how to install and configure the @query-api\u002Fvue package.",{"id":4090,"title":716,"titles":4091,"content":4079,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fget-started\u002Finstall#requirements",[107],{"id":4093,"title":2555,"titles":4094,"content":4095,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fget-started\u002Finstall#install",[107],"npm install @query-api\u002Fvue You can register @query-api\u002Fvue package with the craftcms property in your main.ts file. import { CraftCms } from '@query-api\u002Fvue';\nimport { createApp } from 'vue';\nimport App from '.\u002FApp.vue';\n\nconst app = createApp(App);\n\n\u002F* const defaults = {\n  baseUrl: '', \u002F\u002F Required\n  authToken: '', \u002F\u002F Required\n  registerComponents: true,\n  debug: false,\n  enableEntryTypeMapping: true,\n  siteMap: [],\n}; *\u002F\n\n\u002F\u002F A valid config could look like that\napp.use(CraftCms, {\n  baseUrl: 'https:\u002F\u002Fexample.ddev.site',\n  authToken: 'Bearer your-auth-token',\n  registerComponents: true,\n  debug: false,\n  enableEntryTypeMapping: true,\n  siteMap: [\n    {\n      handle: 'en',\n      origin: 'http:\u002F\u002Flocalhost:3000',\n      id: 1,\n    },\n    {\n      handle: 'de',\n      origin: 'http:\u002F\u002Flocalhost:3000\u002Fde',\n      id: 2,\n    },\n  ],\n});\n\napp.mount('#app'); baseUrl: Refers to the PRIMARY_SITE_URL of Craft CMS, without a trailing slash.authToken: Provide a valid access token. The token should look like that Bearer youlookgood.debug: Enables debug mode and log built urls.registerComponents: Globally register all components.enableEntryTypeMapping: This allows the CraftPage component to automatically detect your entries based on their section handle and entry type.siteMap: Define an array of sites to enable multisite support. Each site object must include a handle and an origin. Boom, finished. 🚀 html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"id":670,"title":394,"titles":4097,"content":4098,"level":713},[],"Learn how you can use the Vue SDK package. Let's dive in and use that thing! This package offers flexible methods for integrating Craft CMS data into your Vue application.",{"id":4100,"title":673,"titles":4101,"content":4102,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fbasic-usage#build-query-urls",[394],"This package does not include direct fetching from your Craft CMS backend to keep things flexible for you. Instead, you can use useCraftUrlBuilder() to create custom query URLs and implement your own fetch function as needed. You can build an url like that: const queryUrl = useCraftUrlBuilder('entries')\n  .id(1)\n  .status('active')\n  .buildUrl('one')\n\n\u002F\u002Fresult = https:\u002F\u002Fyour-primary-site-url\u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery?elementType=entries&id=1&status=active&one=1 You can find detailed instructions on how to build query urls here.",{"id":4104,"title":677,"titles":4105,"content":4106,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fbasic-usage#connect-components",[394],"You can map Craft CMS section handles and matrix block handles to Vue components, enabling the module to automatically render Vue pages and Vue blocks based on your content structure. This method simplifies data rendering by letting the package handle the content logic. You can find detailed instructions on how to connect your components here. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":674,"title":673,"titles":4108,"content":4109,"level":713},[],"Learn how to create custom query URLs for fetching data from Craft CMS. In this guide, you’ll learn to use the useCraftUrlBuilder() composable to build custom query URLs for your Craft CMS backend. This approach offers precise control over the data you retrieve, allowing you to specify fields and configure queries to suit your needs.",{"id":4111,"title":4112,"titles":4113,"content":4114,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fbuild-query-urls#build-an-url","Build an URL",[673],"The useCraftUrlBuilder() composable lets you construct a query URL step-by-step. Here’s how to set up a query URL to fetch a list of related news articles: const queryUrl = useCraftUrlBuilder('entries')\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .buildUrl('one')\n\n\u002F\u002Fresult = https:\u002F\u002Fyour-primary-site-url\u002Fv1\u002Fapi\u002FqueryApi\u002FcustomQuery?elementType=entries&id=1&status=active&one=1 Find out more about the available query methodes in the useCraftQuery() docs.",{"id":4116,"title":4117,"titles":4118,"content":4119,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fbuild-query-urls#fetch-with-query-urls","Fetch with Query URLs",[673],"After building the query URL, you can use it in a fetch function to retrieve data: For example: const queryUrl = useCraftUrlBuilder('entries')\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .buildUrl('one')\n\nconst data = ref(await fetchData(queryUrl)); Here is a small example fetch function with some error handling in place. export async function useCraftFetch(url: string) {\n  const { authToken } = useCraft()\n  const response = await fetch(url, {\n    headers: {\n      Authorization: authToken,\n    }\n  });\n\n  if (!response.ok) {\n    throw new Error(`Failed to fetch data from ${url}: ${response.statusText}`);\n  }\n\n  return await response.json();\n} html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"id":678,"title":677,"titles":4121,"content":4122,"level":713},[],"Learn how to integrate Craft CMS data with your Vue components. This guide explains the steps to connect your Vue components with data from Craft CMS. We’ll create a custom fetch function, mapping object for components, query data, and use the \u003CCraftPage\u002F> and \u003CCraftArea\u002F> components to display content dynamically.",{"id":4124,"title":4125,"titles":4126,"content":4127,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fconnect-components#custom-fetch-function","Custom Fetch Function",[677],"Before we can show data we should build a custom fetch function. For that you can make a new composable. export async function useCraftFetch(url: string) {\n  const { authToken } = useCraft()\n  const response = await fetch(url, {\n    headers: {\n      Authorization: authToken,\n    }\n  });\n\n  if (!response.ok) {\n    throw new Error(`Failed to fetch data from ${url}: ${response.statusText}`);\n  }\n\n  return await response.json();\n}",{"id":4129,"title":3214,"titles":4130,"content":4131,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fconnect-components#catch-all-route",[677],"To support dynamic URLs in your Vue app, add a catch-all route by following this guide. Your router.ts file can look like that: import { createRouter, createWebHistory } from 'vue-router';\nimport CraftRouter from '.\u002FCraftRouter.vue'; \u002F\u002F next step\n\nexport const router = createRouter({\n  history: createWebHistory(),\n  routes: [{ path: '\u002F:pathMatch(.*)*', component: CraftRouter }],\n});",{"id":4133,"title":4134,"titles":4135,"content":4136,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fconnect-components#craftrouter-component","CraftRouter Component",[677],"To handle the routing correctly you should now make a CraftRouter.vue. This file is there to handle the routing Logic based on the router uri. We watch if the uri changes and if so we update the uri variable.\nThis is neccessary for the correct fetch to Craft CMS. \u003Cscript setup lang=\"ts\">\n  import { ref, watch } from 'vue';\n  import { useRoute } from 'vue-router';\n\n  const route = useRoute();\n  const uri = ref(route.params.pathMatch || '__home__');\n\n  watch(\n    () => route.fullPath,\n    async () => {\n      uri.value = route.params.pathMatch || '__home__';\n    },\n  );\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    {{ uri }}\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>",{"id":4138,"title":3219,"titles":4139,"content":4140,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fconnect-components#mapping-object",[677],"Define a mapping object in the CraftRouter.vue file. This object connects each Craft CMS section handle to a Vue page component and each field handle to a specific Vue component. This setup allows the correct component to render based on the Craft CMS data. For example: \u003Cscript setup lang=\"ts\">\n  import { ref, watch } from 'vue';\n  import { useRoute } from 'vue-router';\n\n  \u002F\u002F some dummy components \n  import Home from '.\u002Fviews\u002Fhome.vue';\n  import News from '.\u002Fviews\u002Fnews.vue';\n  import Headline from '.\u002Fcomponents\u002Fheadline.vue';\n\n  \u002F\u002F that's how you connect Craft with Vue\n  const mapping: ContentMapping = {\n    pages: {\n      home: Home,\n      news: News,\n    },\n    components: {\n      headline: Headline,\n      imageText: CraftNotImplemented,\n    },\n  };\n\n  const route = useRoute();\n  const uri = ref(route.params.pathMatch || '__home__');\n\n  watch(\n    () => route.fullPath,\n    async () => {\n      uri.value = route.params.pathMatch || '__home__';\n    },\n  );\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    {{ uri }}\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>",{"id":4142,"title":3224,"titles":4143,"content":4144,"level":740},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fconnect-components#working-with-entry-types",[677,3219],"When enableEntryTypeMapping is set to true in your configuration in your main.ts, you can link your Craft entries using the format sectionHandle:entryTypeHandle. If the entry type handle is default or matches the section handle, you don’t need to explicitly define the :entryTypeHandle. const mapping: ContentMapping = {\n  pages: {\n    home: Home, \u002F\u002F equivalent to home:default or home:home\n    'news:default': News, \u002F\u002F equivalent to news or news:news\n    'news:reference': News, \u002F\u002F section handle = news, entry type handle = reference\n  },\n  components: {\n    \u002F\u002F additional components\n  },\n};",{"id":4146,"title":3234,"titles":4147,"content":4148,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fconnect-components#display-page",[677],"Use the useCraftFetch() helper to retrieve data from Craft CMS, and display the page content using the \u003CCraftPage\u002F> component within CraftRouter.vue. This component automatically renders the defined pages based on the mapping configuration and the data fetched from Craft CMS. To find out more about the \u003CCraftPage\u002F> check out the craft page docs. Here’s how your CraftRouter.vue looks now. \u003Cscript setup lang=\"ts\">\n  import { ref, watch } from 'vue';\n  import { useRoute } from 'vue-router';\n  import { useCraftUrlBuilder, CraftNotImplemented, CraftPage, type ContentMapping } from '@query-api\u002Fvue';\n  import { useCraftFetch } from '.\u002Fcomposables\u002FuseCraftFetch';\n\n  import Home from '.\u002Fviews\u002Fhome.vue';\n  import News from '.\u002Fviews\u002Fnews.vue';\n  import Headline from '.\u002Fcomponents\u002Fheadline.vue';\n\n  const mapping: ContentMapping = {\n    pages: {\n      home: Home,\n      news: News,\n    },\n    components: {\n      headline: Headline,\n      imageText: CraftNotImplemented,\n    },\n  };\n\n  const route = useRoute();\n  const uri = ref(route.params.pathMatch || '__home__');\n  const urlBuilder = useCraftUrlBuilder('entries'); \u002F\u002F init here to use it in the right Vue context\n  const data = ref(await useCraftFetch(urlBuilder.uri(uri.value).buildUrl('one'))); \u002F\u002F on initial load\n\n  watch(\n    () => route.fullPath,\n    async () => {\n      uri.value = route.params.pathMatch || '__home__';\n      data.value = await useCraftFetch(urlBuilder.uri(uri.value).buildUrl('one')); \u002F\u002F on route change\n    },\n  );\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003C!-- Let the CraftPage handle the rest -->\n    \u003CCraftPage :config=\"mapping\" :content=\"data\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate> This setup should render the correct Vue page based on your defined mapping object. To verify the data structure Craft CMS sends to your page, you can add the following code to inspect the data in .\u002Fviews\u002Fhome.vue: \u003Ctemplate>\n  \u003Ch1>Home\u003C\u002Fh1>\n  \u003Cpre>\n    {{ $attrs }}\n  \u003C\u002Fpre>\n\u003C\u002Ftemplate>",{"id":4150,"title":3239,"titles":4151,"content":4152,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fconnect-components#display-components",[677],"To connect Matrix blocks with Vue components, use the \u003CCraftArea\u002F> component. This component will dynamically render Vue components based on the content provided from Craft CMS. Example: \u003Cscript setup lang=\"ts\">\n  const props = defineProps({\n    metadata: {\n      type: Object,\n      required: true,\n    },\n    contentBuilder: {\n      type: Object,\n      required: true,\n    },\n    sectionHandle: {\n      type: String,\n      required: true,\n    },\n    title: {\n      type: String,\n      required: true,\n    },\n  });\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Ch1>{{ props.title }}\u003C\u002Fh1>\n    \u003CCraftArea v-if=\"props.contentBuilder\" :content=\"props.contentBuilder\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate> To find out more about the \u003CCraftArea\u002F> check out the docs. html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}",{"id":682,"title":681,"titles":4154,"content":4155,"level":713},[],"Learn how to use the Vue SDK through an example.",{"id":4157,"title":4158,"titles":4159,"content":4160,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fusage\u002Fexample#playground","Playground",[681],"Get a quick overview by exploring the playground in the library.",{"id":690,"title":689,"titles":4162,"content":4163,"level":713},[],"Learn how to use the useCraftUrlBuilder composable. This composable provides a simple way to build urls to query from your Craft CMS Backend.\nIt leverages js-craftcms-api to build query URLs.",{"id":4165,"title":3282,"titles":4166,"content":4167,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fcomposables\u002Fuse-craft-url-builder#element-types",[689],"\u003Cscript setup lang=\"ts\">\n  \u002F\u002F url for addresses query\n  const url = useCraftUrlBuilder('addresses').id(1).buildUrl('one')\n\n  \u002F\u002F url for assets query\n  const url = useCraftUrlBuilder('assets').id(1).buildUrl('one')\n\n  \u002F\u002F url for entry query\n  const url = useCraftUrlBuilder('entries').id(1).buildUrl('one')\n\n  \u002F\u002F url for users query\n  const url = useCraftUrlBuilder('users').id(1).buildUrl('one')\n\u003C\u002Fscript>",{"id":4169,"title":4170,"titles":4171,"content":4172,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fcomposables\u002Fuse-craft-url-builder#generate-url","Generate URL",[689],"By using the one or the all as function parameters of the buildUrl() method you can build the url. const query = useCraftUrlBuilder('entries').section('news')\n\n\u002F\u002F Generates a url to fetch one entry\nconst url = query.buildUrl('one')\n\n\u002F\u002F Generates a url to fetch all entries\nconst url = query.buildUrl('all')",{"id":4174,"title":3292,"titles":4175,"content":4176,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fcomposables\u002Fuse-craft-url-builder#available-methods",[689],"useCraftUrlBuilder supports all methods from js-craftcms-api. For the full list of available methods, see the documentation here. In addition, the following Vue-specific methods are available: MethodDescriptionTypebuildUrlGenerate an urlone or all",{"id":4178,"title":681,"titles":4179,"content":4180,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fcomposables\u002Fuse-craft-url-builder#example",[689],"const url = useCraftUrlBuilder('entries')\n  .section('news')\n  .fields(['title'])\n  .limit(3)\n  .buildUrl('all') html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":694,"title":693,"titles":4182,"content":4183,"level":713},[],"Learn how to use the useCraft composable. This composable returns the instance of the plugin. This is useful if you need sites or the base cp url. \u003Cscript setup lang=\"ts\">\n  import { useCraft } from '@query-api\u002Fvue';\n  const { baseUrl, siteMap } = useCraft();\n\u003C\u002Fscript> html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":701,"title":478,"titles":4185,"content":4186,"level":713},[],"Learn how to use the CraftPage component. The CraftPage component renders the mapped Vue view based on your queried data and the config.pages prop. \u003Cscript setup lang=\"ts\">\n  import { CraftPage, type ContentMapping } from '@query-api\u002Fvue';\n  import Home from '.\u002Fviews\u002Fhome.vue';\n  import Headline from '.\u002Fcomponents\u002Fheadline.vue';\n\n  const mapping: ContentMapping = {\n    pages: {\n      home: Home,\n    },\n    components: {\n      headline: Headline,\n    },\n  };\n  const data = { sectionHandle: \"home\", metadata: { entryType: \"default\" } }\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CCraftPage :config=\"mapping\" :content=\"data\" \u002F>\n\u003C\u002Ftemplate>",{"id":4188,"title":4189,"titles":4190,"content":4191,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fcomponents\u002Fcraft-page#config","config",[478],"The config option lets you connect your Craft CMS sections and entry types to Vue components. In pages, use sectionHandle:entryTypeHandle (e.g., news:home) to map to a Vue page. If the entry type handle is the same as the section handle, or if it's the default entry type for that section, you can simply use the section handle as the key (e.g., home). To turn off sectionHandle:entryTypeHandle mapping, set enableEntryTypeMapping: false in craftInit. In components, map entry types to Vue components. This is useful for things like matrix blocks. This is used in the CraftArea component later on.\nIf you prefer to define the component mapping directly when using the CraftArea component you can do that as well. Type: objectDefault: { pages: {}, components: {} }Example: contentMapping: {\n  pages: {\n    home: Home, \u002F\u002F Maps section home entry with entry type home to the Home component.\n    'news:home': News, \u002F\u002F Maps section news entry with entry type home to the News component.\n  },\n  components: {\n    headline: Headline, \u002F\u002F Entry type headline will be rendered with the Headline component.\n    imageText: CraftNotImplemented,\n  },\n}",{"id":4193,"title":3521,"titles":4194,"content":4195,"level":2800},"\u002Flibraries\u002Fvue-craftcms\u002Fcomponents\u002Fcraft-page#error-pages",[478,4189],"You can also map error pages by providing special keys in the contentMapping.pages object. This allows you to render custom Next.js components for specific error scenarios. page404: For 404 Not Found errors.error: A general fallback for other errors.",{"id":4197,"title":4198,"titles":4199,"content":4200,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fcomponents\u002Fcraft-page#content","content",[478],"The actual content data returned from a Craft CMS query, such as one created with useCraftEntry(). It should at least contain the sectionHandle and entryType. html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"id":704,"title":482,"titles":4202,"content":4203,"level":713},[],"Learn how to use the CraftArea component. The CraftArea component maps field handles defined in Craft CMS to components in Nuxt \u002F Vue defined in the config prop of the CraftPage.\nThe content prop receives the actual data from your Craft CMS query, typically an array of Matrix Field data. \u003Cscript setup lang=\"ts\">\n  import { CraftArea, CraftNotImplemented } from '@query-api\u002Fvue'\n  import Headline from '.\u002Fcomponents\u002Fheadline.vue'\n\n  const contentBuilder = [\n    {\n      type: 'headline',\n      someField: 'Example Headline',\n    },\n    {\n      type: 'richText',\n      someField: 'Example Rich Text',\n    },\n  ]\n\n  \u002F\u002F optional\n  const blockMapping = {\n    headline: Headline, \u002F\u002F Entry type headline will be rendered with the Headline component.\n    richText: CraftNotImplemented,\n  }\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003CCraftArea :content=\"contentBuilder\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>",{"id":4205,"title":4198,"titles":4206,"content":4207,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fcomponents\u002Fcraft-area#content",[482],"This prop accepts an array of objects. Each Object should contain a key named type.\nThe type represents the entry type of the entry in the matrix field. This value is used to find the correct Vue component based on the contentMapping defined in the CraftPage.",{"id":4209,"title":4210,"titles":4211,"content":4212,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fcomponents\u002Fcraft-area#block-mapping","block-mapping",[482],"This optional prop accepts an object that contains the type as the key and a Vue component that you want to render for the given type.\nYou can also define this mapping where you include the CraftPage component. html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":707,"title":486,"titles":4214,"content":4215,"level":713},[],"Learn how to use the CraftNotImplemented component. The CraftNotImplemented componentis a small development helper with the following purposes: Display Unimplemented Block Types: Shows a message indicating any block type that hasn’t been implemented yet.Debug Block Attributes: Outputs the block’s attributes in a readable format for easier debugging. The NotImplemented component helps quickly identify unmapped or unsupported block types, enhancing flexibility and streamlining your Nuxt\u002FVue integration.",{"id":4217,"title":4218,"titles":4219,"content":4220,"level":719},"\u002Flibraries\u002Fvue-craftcms\u002Fcomponents\u002Fcraft-not-implemented#usage-with-mapping","Usage with Mapping",[486],"Example: \u003Cscript setup lang=\"ts\">\n  import type { ContentMapping } from '@query-api\u002Fvue'\n  import { CraftPage, CraftNotImplemented } from '@query-api\u002Fvue'\n  import Home from '~\u002Ftemplates\u002Fpages\u002Fhome.vue'\n  import News from '~\u002Ftemplates\u002Fpages\u002Fnews.vue'\n\n  import ImageText from '~\u002Ftemplates\u002Fcomponents\u002FimageText.vue'\n  import Headline from '~\u002Ftemplates\u002Fcomponents\u002Fheadline.vue'\n\n  const mapping: ContentMapping = {\n    pages: {\n      home: Home,\n      news: News,\n    },\n    components: {\n      imageText: ImageText,\n      headline: CraftNotImplemented, \u002F\u002F Use it like that or in templated directly\n    },\n  }\n\n  const { data, error } = await useCraftQuery('entries').uri('__home__').one()\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003CCraftPage\n      v-if=\"data\"\n      :config=\"mapping\"\n      :content=\"data\"\n    \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate> Simple Example in a Component: \u003Ctemplate>\n  \u003CCraftNotImplemented \u002F>\n\u003C\u002Ftemplate> html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",[4222,4224],{"title":486,"path":571,"stem":572,"description":4223,"children":-1},"Learn how to use the CraftNotImplemented component.",{"title":582,"path":583,"stem":584,"description":3816,"children":-1},{"id":4226,"title":574,"badge":23,"body":4227,"description":5150,"extension":5151,"head":23,"icon":23,"meta":5152,"navigation":4263,"ogImage":23,"path":579,"robots":23,"schemaOrg":23,"seo":5153,"sitemap":5154,"stem":580,"type":23,"__hash__":5155},"docs\u002F2.libraries\u002Fquery-api-next\u002F6.middleware\u002Fmiddleware.md",{"type":4228,"value":4229,"toc":5140},"minimark",[4230,4345,4349,4385,4389,4392,4397,4405,4412,4415,4429,4441,4444,4464,4467,4470,4477,4549,4556,4709,4712,4715,4718,4806,4809,4811,4817,4820,4911,4915,4995,5000,5003,5080,5083,5136],[4231,4232,4237],"pre",{"className":4233,"code":4234,"filename":4235,"language":4236,"meta":734,"style":734},"language-ts shiki shiki-themes github-light github-dark github-dark","import { createQueryApiMiddleware } from '@query-api\u002Fnext\u002Fserver'\n\nexport default createQueryApiMiddleware()\n\nexport const config = {\n  \u002F\u002F Match all pathnames except for\n  \u002F\u002F - … if they start with `\u002Fapi`, `\u002Ftrpc`, `\u002F_next` or `\u002F_vercel`\n  \u002F\u002F - … the ones containing a dot (e.g. `favicon.ico`)\n  matcher: '\u002F((?!api|trpc|_next|_vercel|.*\\\\..*).*)',\n}\n","middleware.ts","ts",[4238,4239,4240,4259,4265,4280,4284,4302,4309,4315,4321,4339],"code",{"__ignoreMap":734},[4241,4242,4244,4248,4252,4255],"span",{"class":4243,"line":713},"line",[4241,4245,4247],{"class":4246},"so5gQ","import",[4241,4249,4251],{"class":4250},"slsVL"," { createQueryApiMiddleware } ",[4241,4253,4254],{"class":4246},"from",[4241,4256,4258],{"class":4257},"sfrk1"," '@query-api\u002Fnext\u002Fserver'\n",[4241,4260,4261],{"class":4243,"line":719},[4241,4262,4264],{"emptyLinePlaceholder":4263},true,"\n",[4241,4266,4267,4270,4273,4277],{"class":4243,"line":740},[4241,4268,4269],{"class":4246},"export",[4241,4271,4272],{"class":4246}," default",[4241,4274,4276],{"class":4275},"shcOC"," createQueryApiMiddleware",[4241,4278,4279],{"class":4250},"()\n",[4241,4281,4282],{"class":4243,"line":2800},[4241,4283,4264],{"emptyLinePlaceholder":4263},[4241,4285,4287,4289,4292,4296,4299],{"class":4243,"line":4286},5,[4241,4288,4269],{"class":4246},[4241,4290,4291],{"class":4246}," const",[4241,4293,4295],{"class":4294},"suiK_"," config",[4241,4297,4298],{"class":4246}," =",[4241,4300,4301],{"class":4250}," {\n",[4241,4303,4305],{"class":4243,"line":4304},6,[4241,4306,4308],{"class":4307},"sCsY4","  \u002F\u002F Match all pathnames except for\n",[4241,4310,4312],{"class":4243,"line":4311},7,[4241,4313,4314],{"class":4307},"  \u002F\u002F - … if they start with `\u002Fapi`, `\u002Ftrpc`, `\u002F_next` or `\u002F_vercel`\n",[4241,4316,4318],{"class":4243,"line":4317},8,[4241,4319,4320],{"class":4307},"  \u002F\u002F - … the ones containing a dot (e.g. `favicon.ico`)\n",[4241,4322,4324,4327,4330,4333,4336],{"class":4243,"line":4323},9,[4241,4325,4326],{"class":4250},"  matcher: ",[4241,4328,4329],{"class":4257},"'\u002F((?!api|trpc|_next|_vercel|.*",[4241,4331,4332],{"class":4294},"\\\\",[4241,4334,4335],{"class":4257},"..*).*)'",[4241,4337,4338],{"class":4250},",\n",[4241,4340,4342],{"class":4243,"line":4341},10,[4241,4343,4344],{"class":4250},"}\n",[4346,4347,4348],"p",{},"The middleware intercepts every incoming page request before it reaches your Server Components. Its primary job is to:",[4350,4351,4352,4375],"ol",{},[4353,4354,4355,4359,4360,4363,4364,4367,4368,4363,4371,4374],"li",{},[4356,4357,4358],"strong",{},"Read the Request URL:"," It extracts key information from the URL, such as the page path (e.g., ",[4238,4361,4362],{},"\u002Fabout-us",", ",[4238,4365,4366],{},"\u002Fnews\u002Fmy-article",") and any Craft CMS preview parameters (e.g., ",[4238,4369,4370],{},"?token=...",[4238,4372,4373],{},"?x-craft-preview=...",").",[4353,4376,4377,4380,4381,4384],{},[4356,4378,4379],{},"Write to Headers:"," It copies this information into the response headers. For example, it might set a header like ",[4238,4382,4383],{},"craft-path: \u002Fnews\u002Fmy-article",".",[4386,4387,3773],"h2",{"id":4388},"why-its-necessary",[4346,4390,4391],{},"The middleware is essential because of a core design principle in the Next.js App Router:",[4346,4393,4394],{},[4356,4395,4396],{},"Server Components cannot directly access the incoming request object.",[4346,4398,4399,4400,4404],{},"This means a Server Component has no way of knowing the URL path or its query parameters. However, Server Components ",[4401,4402,4403],"em",{},"can"," read request headers.",[4346,4406,4407,4408,4411],{},"The middleware solves this problem by acting as a ",[4356,4409,4410],{},"bridge",". It translates the request URL information into headers, making that data accessible to Server Components so they know which content to fetch and render.",[4386,4413,3778],{"id":4414},"how-helper-functions-work",[4346,4416,4417,4418,4363,4421,4424,4425,4428],{},"Functions like ",[4238,4419,4420],{},"getCraftUri()",[4238,4422,4423],{},"getCraftCurrentSite()",", and ",[4238,4426,4427],{},"getCraftEntry()"," are designed to work with the middleware automatically.",[4346,4430,4431,4432,4437,4438,4384],{},"The connection is the ",[4356,4433,4434],{},[4238,4435,4436],{},"headers()"," function provided by ",[4238,4439,4440],{},"next\u002Fheaders",[4346,4442,4443],{},"Here’s the simple workflow:",[4350,4445,4446,4452],{},[4353,4447,4448,4451],{},[4356,4449,4450],{},"Middleware (The Writer):"," The middleware intercepts a request and writes the URL path to a header. Think of it like putting a sticky note on a file.",[4353,4453,4454,4457,4458,4460,4461,4463],{},[4356,4455,4456],{},"Helper Function (The Reader):"," When you call a function like ",[4238,4459,4420],{}," in a Server Component, it uses the Next.js ",[4238,4462,4436],{}," function to find and read that \"sticky note.\" It knows exactly which header to look for.",[4346,4465,4466],{},"This provides a clean and simple developer experience. You don't need to manage headers manually; you just call a function, and it automatically gets the context it needs from the headers set by the middleware.",[4386,4468,3783],{"id":4469},"middleware-examples",[4346,4471,4472,4473,4476],{},"Here is the most straight forward example. The ",[4238,4474,4475],{},"createQueryApiMiddleware"," function creates a middleware and sets all headers that are needed.",[4231,4478,4479],{"className":4233,"code":4234,"filename":4235,"language":4236,"meta":734,"style":734},[4238,4480,4481,4491,4495,4505,4509,4521,4525,4529,4533,4545],{"__ignoreMap":734},[4241,4482,4483,4485,4487,4489],{"class":4243,"line":713},[4241,4484,4247],{"class":4246},[4241,4486,4251],{"class":4250},[4241,4488,4254],{"class":4246},[4241,4490,4258],{"class":4257},[4241,4492,4493],{"class":4243,"line":719},[4241,4494,4264],{"emptyLinePlaceholder":4263},[4241,4496,4497,4499,4501,4503],{"class":4243,"line":740},[4241,4498,4269],{"class":4246},[4241,4500,4272],{"class":4246},[4241,4502,4276],{"class":4275},[4241,4504,4279],{"class":4250},[4241,4506,4507],{"class":4243,"line":2800},[4241,4508,4264],{"emptyLinePlaceholder":4263},[4241,4510,4511,4513,4515,4517,4519],{"class":4243,"line":4286},[4241,4512,4269],{"class":4246},[4241,4514,4291],{"class":4246},[4241,4516,4295],{"class":4294},[4241,4518,4298],{"class":4246},[4241,4520,4301],{"class":4250},[4241,4522,4523],{"class":4243,"line":4304},[4241,4524,4308],{"class":4307},[4241,4526,4527],{"class":4243,"line":4311},[4241,4528,4314],{"class":4307},[4241,4530,4531],{"class":4243,"line":4317},[4241,4532,4320],{"class":4307},[4241,4534,4535,4537,4539,4541,4543],{"class":4243,"line":4323},[4241,4536,4326],{"class":4250},[4241,4538,4329],{"class":4257},[4241,4540,4332],{"class":4294},[4241,4542,4335],{"class":4257},[4241,4544,4338],{"class":4250},[4241,4546,4547],{"class":4243,"line":4341},[4241,4548,4344],{"class":4250},[4346,4550,4551,4552,4555],{},"If you need more control you can use the ",[4238,4553,4554],{},"setCraftHeaders"," function.\nThis function will return a response that you can use to modify further.",[4231,4557,4559],{"className":4233,"code":4558,"filename":4235,"language":4236,"meta":734,"style":734},"import { setCraftHeaders } from '@query-api\u002Fnext\u002Fserver'\nimport { NextRequest, NextResponse } from 'next\u002Fserver'\n\nexport default function middleware(req: NextRequest) {\n  let res = NextResponse.next()\n  res = setCraftHeaders(res, req)\n  return res\n}\n\nexport const config = {\n  \u002F\u002F Match all pathnames except for\n  \u002F\u002F - … if they start with `\u002Fapi`, `\u002Ftrpc`, `\u002F_next` or `\u002F_vercel`\n  \u002F\u002F - … the ones containing a dot (e.g. `favicon.ico`)\n  matcher: '\u002F((?!api|trpc|_next|_vercel|.*\\\\..*).*)',\n}\n",[4238,4560,4561,4572,4584,4588,4616,4635,4648,4656,4660,4664,4676,4681,4686,4691,4704],{"__ignoreMap":734},[4241,4562,4563,4565,4568,4570],{"class":4243,"line":713},[4241,4564,4247],{"class":4246},[4241,4566,4567],{"class":4250}," { setCraftHeaders } ",[4241,4569,4254],{"class":4246},[4241,4571,4258],{"class":4257},[4241,4573,4574,4576,4579,4581],{"class":4243,"line":719},[4241,4575,4247],{"class":4246},[4241,4577,4578],{"class":4250}," { NextRequest, NextResponse } ",[4241,4580,4254],{"class":4246},[4241,4582,4583],{"class":4257}," 'next\u002Fserver'\n",[4241,4585,4586],{"class":4243,"line":740},[4241,4587,4264],{"emptyLinePlaceholder":4263},[4241,4589,4590,4592,4594,4597,4600,4603,4607,4610,4613],{"class":4243,"line":2800},[4241,4591,4269],{"class":4246},[4241,4593,4272],{"class":4246},[4241,4595,4596],{"class":4246}," function",[4241,4598,4599],{"class":4275}," middleware",[4241,4601,4602],{"class":4250},"(",[4241,4604,4606],{"class":4605},"sQHwn","req",[4241,4608,4609],{"class":4246},":",[4241,4611,4612],{"class":4275}," NextRequest",[4241,4614,4615],{"class":4250},") {\n",[4241,4617,4618,4621,4624,4627,4630,4633],{"class":4243,"line":4286},[4241,4619,4620],{"class":4246},"  let",[4241,4622,4623],{"class":4250}," res ",[4241,4625,4626],{"class":4246},"=",[4241,4628,4629],{"class":4250}," NextResponse.",[4241,4631,4632],{"class":4275},"next",[4241,4634,4279],{"class":4250},[4241,4636,4637,4640,4642,4645],{"class":4243,"line":4304},[4241,4638,4639],{"class":4250},"  res ",[4241,4641,4626],{"class":4246},[4241,4643,4644],{"class":4275}," setCraftHeaders",[4241,4646,4647],{"class":4250},"(res, req)\n",[4241,4649,4650,4653],{"class":4243,"line":4311},[4241,4651,4652],{"class":4246},"  return",[4241,4654,4655],{"class":4250}," res\n",[4241,4657,4658],{"class":4243,"line":4317},[4241,4659,4344],{"class":4250},[4241,4661,4662],{"class":4243,"line":4323},[4241,4663,4264],{"emptyLinePlaceholder":4263},[4241,4665,4666,4668,4670,4672,4674],{"class":4243,"line":4341},[4241,4667,4269],{"class":4246},[4241,4669,4291],{"class":4246},[4241,4671,4295],{"class":4294},[4241,4673,4298],{"class":4246},[4241,4675,4301],{"class":4250},[4241,4677,4679],{"class":4243,"line":4678},11,[4241,4680,4308],{"class":4307},[4241,4682,4684],{"class":4243,"line":4683},12,[4241,4685,4314],{"class":4307},[4241,4687,4689],{"class":4243,"line":4688},13,[4241,4690,4320],{"class":4307},[4241,4692,4694,4696,4698,4700,4702],{"class":4243,"line":4693},14,[4241,4695,4326],{"class":4250},[4241,4697,4329],{"class":4257},[4241,4699,4332],{"class":4294},[4241,4701,4335],{"class":4257},[4241,4703,4338],{"class":4250},[4241,4705,4707],{"class":4243,"line":4706},15,[4241,4708,4344],{"class":4250},[4386,4710,3788],{"id":4711},"matcher-config",[4346,4713,4714],{},"The middleware is intended to run only on pages, not on static files like \u002Ffavicon.ico.",[4346,4716,4717],{},"A popular strategy is to match all routes that don’t start with certain segments (e.g. \u002F_next) and also none that include a dot (.) since these typically indicate static files. However, if you have some routes where a dot is expected (e.g. \u002Fusers\u002Fjane.doe), you should explicitly provide a matcher for these.",[4231,4719,4721],{"className":4233,"code":4720,"filename":4235,"language":4236,"meta":734,"style":734},"export const config = {\n  \u002F\u002F Matcher entries are linked with a logical \"or\", therefore\n  \u002F\u002F if one of them matches, the middleware will be invoked.\n  matcher: [\n    \u002F\u002F Match all pathnames except for\n    \u002F\u002F - … if they start with `\u002Fapi`, `\u002Ftrpc`, `\u002F_next` or `\u002F_vercel`\n    \u002F\u002F - … the ones containing a dot (e.g. `favicon.ico`)\n    '\u002F((?!api|_next|_vercel|.*\\\\..*).*)',\n \n    \u002F\u002F However, match all pathnames within `\u002Fusers`, optionally with a locale prefix\n    '\u002F([\\\\w-]+)?\u002Fusers\u002F(.+)'\n  ]\n};\n",[4238,4722,4723,4735,4740,4745,4750,4755,4760,4765,4776,4781,4786,4796,4801],{"__ignoreMap":734},[4241,4724,4725,4727,4729,4731,4733],{"class":4243,"line":713},[4241,4726,4269],{"class":4246},[4241,4728,4291],{"class":4246},[4241,4730,4295],{"class":4294},[4241,4732,4298],{"class":4246},[4241,4734,4301],{"class":4250},[4241,4736,4737],{"class":4243,"line":719},[4241,4738,4739],{"class":4307},"  \u002F\u002F Matcher entries are linked with a logical \"or\", therefore\n",[4241,4741,4742],{"class":4243,"line":740},[4241,4743,4744],{"class":4307},"  \u002F\u002F if one of them matches, the middleware will be invoked.\n",[4241,4746,4747],{"class":4243,"line":2800},[4241,4748,4749],{"class":4250},"  matcher: [\n",[4241,4751,4752],{"class":4243,"line":4286},[4241,4753,4754],{"class":4307},"    \u002F\u002F Match all pathnames except for\n",[4241,4756,4757],{"class":4243,"line":4304},[4241,4758,4759],{"class":4307},"    \u002F\u002F - … if they start with `\u002Fapi`, `\u002Ftrpc`, `\u002F_next` or `\u002F_vercel`\n",[4241,4761,4762],{"class":4243,"line":4311},[4241,4763,4764],{"class":4307},"    \u002F\u002F - … the ones containing a dot (e.g. `favicon.ico`)\n",[4241,4766,4767,4770,4772,4774],{"class":4243,"line":4317},[4241,4768,4769],{"class":4257},"    '\u002F((?!api|_next|_vercel|.*",[4241,4771,4332],{"class":4294},[4241,4773,4335],{"class":4257},[4241,4775,4338],{"class":4250},[4241,4777,4778],{"class":4243,"line":4323},[4241,4779,4780],{"class":4250}," \n",[4241,4782,4783],{"class":4243,"line":4341},[4241,4784,4785],{"class":4307},"    \u002F\u002F However, match all pathnames within `\u002Fusers`, optionally with a locale prefix\n",[4241,4787,4788,4791,4793],{"class":4243,"line":4678},[4241,4789,4790],{"class":4257},"    '\u002F([",[4241,4792,4332],{"class":4294},[4241,4794,4795],{"class":4257},"w-]+)?\u002Fusers\u002F(.+)'\n",[4241,4797,4798],{"class":4243,"line":4683},[4241,4799,4800],{"class":4250},"  ]\n",[4241,4802,4803],{"class":4243,"line":4688},[4241,4804,4805],{"class":4250},"};\n",[4386,4807,3793],{"id":4808},"get-craft-headers",[4346,4810,3795],{},[4812,4813,4815],"h3",{"id":4814},"getcraftsiteheaders",[4238,4816,3798],{},[4346,4818,4819],{},"This will return an object with all relevant request context data.",[4231,4821,4826],{"className":4822,"code":4823,"filename":4824,"language":4825,"meta":734,"style":734},"language-tsx shiki shiki-themes github-light github-dark github-dark","import { getCraftSiteHeaders } from '@query-api\u002Fnext\u002Fserver'\n\nexport default async function News() {\n  const siteHeaders = await getCraftSiteHeaders()\n  return \u003Cp>{JSON.stringify(siteHeaders)}\u003C\u002Fp>\n}\n","rsc.tsx","tsx",[4238,4827,4828,4839,4843,4860,4878,4907],{"__ignoreMap":734},[4241,4829,4830,4832,4835,4837],{"class":4243,"line":713},[4241,4831,4247],{"class":4246},[4241,4833,4834],{"class":4250}," { getCraftSiteHeaders } ",[4241,4836,4254],{"class":4246},[4241,4838,4258],{"class":4257},[4241,4840,4841],{"class":4243,"line":719},[4241,4842,4264],{"emptyLinePlaceholder":4263},[4241,4844,4845,4847,4849,4852,4854,4857],{"class":4243,"line":740},[4241,4846,4269],{"class":4246},[4241,4848,4272],{"class":4246},[4241,4850,4851],{"class":4246}," async",[4241,4853,4596],{"class":4246},[4241,4855,4856],{"class":4275}," News",[4241,4858,4859],{"class":4250},"() {\n",[4241,4861,4862,4865,4868,4870,4873,4876],{"class":4243,"line":2800},[4241,4863,4864],{"class":4246},"  const",[4241,4866,4867],{"class":4294}," siteHeaders",[4241,4869,4298],{"class":4246},[4241,4871,4872],{"class":4246}," await",[4241,4874,4875],{"class":4275}," getCraftSiteHeaders",[4241,4877,4279],{"class":4250},[4241,4879,4880,4882,4885,4888,4891,4894,4896,4899,4902,4904],{"class":4243,"line":4286},[4241,4881,4652],{"class":4246},[4241,4883,4884],{"class":4250}," \u003C",[4241,4886,4346],{"class":4887},"sByVh",[4241,4889,4890],{"class":4250},">{",[4241,4892,4893],{"class":4294},"JSON",[4241,4895,4384],{"class":4250},[4241,4897,4898],{"class":4275},"stringify",[4241,4900,4901],{"class":4250},"(siteHeaders)}\u003C\u002F",[4241,4903,4346],{"class":4887},[4241,4905,4906],{"class":4250},">\n",[4241,4908,4909],{"class":4243,"line":4304},[4241,4910,4344],{"class":4250},[4912,4913,3328],"h4",{"id":4914},"type",[4231,4916,4918],{"className":4233,"code":4917,"language":4236,"meta":734,"style":734},"export async function getCraftSiteHeaders(): Promise\u003C{\n    origin: string | null;\n    path: string | null;\n    url: string | null;\n}>\n",[4238,4919,4920,4941,4960,4975,4990],{"__ignoreMap":734},[4241,4921,4922,4924,4926,4928,4930,4933,4935,4938],{"class":4243,"line":713},[4241,4923,4269],{"class":4246},[4241,4925,4851],{"class":4246},[4241,4927,4596],{"class":4246},[4241,4929,4875],{"class":4275},[4241,4931,4932],{"class":4250},"()",[4241,4934,4609],{"class":4246},[4241,4936,4937],{"class":4275}," Promise",[4241,4939,4940],{"class":4250},"\u003C{\n",[4241,4942,4943,4946,4948,4951,4954,4957],{"class":4243,"line":719},[4241,4944,4945],{"class":4605},"    origin",[4241,4947,4609],{"class":4246},[4241,4949,4950],{"class":4294}," string",[4241,4952,4953],{"class":4246}," |",[4241,4955,4956],{"class":4294}," null",[4241,4958,4959],{"class":4250},";\n",[4241,4961,4962,4965,4967,4969,4971,4973],{"class":4243,"line":740},[4241,4963,4964],{"class":4605},"    path",[4241,4966,4609],{"class":4246},[4241,4968,4950],{"class":4294},[4241,4970,4953],{"class":4246},[4241,4972,4956],{"class":4294},[4241,4974,4959],{"class":4250},[4241,4976,4977,4980,4982,4984,4986,4988],{"class":4243,"line":2800},[4241,4978,4979],{"class":4605},"    url",[4241,4981,4609],{"class":4246},[4241,4983,4950],{"class":4294},[4241,4985,4953],{"class":4246},[4241,4987,4956],{"class":4294},[4241,4989,4959],{"class":4250},[4241,4991,4992],{"class":4243,"line":4286},[4241,4993,4994],{"class":4250},"}>\n",[4812,4996,4998],{"id":4997},"getcraftpreviewheaders",[4238,4999,3807],{},[4346,5001,5002],{},"This will return an object with all preview parameters in the current request context.",[4231,5004,5006],{"className":4822,"code":5005,"filename":4824,"language":4825,"meta":734,"style":734},"import { getCraftPreviewHeaders } from '@query-api\u002Fnext\u002Fserver'\n\nexport default async function News() {\n  const previewHeaders = await getCraftPreviewHeaders()\n  return \u003Cp>{JSON.stringify(previewHeaders)}\u003C\u002Fp>\n}\n",[4238,5007,5008,5019,5023,5037,5053,5076],{"__ignoreMap":734},[4241,5009,5010,5012,5015,5017],{"class":4243,"line":713},[4241,5011,4247],{"class":4246},[4241,5013,5014],{"class":4250}," { getCraftPreviewHeaders } ",[4241,5016,4254],{"class":4246},[4241,5018,4258],{"class":4257},[4241,5020,5021],{"class":4243,"line":719},[4241,5022,4264],{"emptyLinePlaceholder":4263},[4241,5024,5025,5027,5029,5031,5033,5035],{"class":4243,"line":740},[4241,5026,4269],{"class":4246},[4241,5028,4272],{"class":4246},[4241,5030,4851],{"class":4246},[4241,5032,4596],{"class":4246},[4241,5034,4856],{"class":4275},[4241,5036,4859],{"class":4250},[4241,5038,5039,5041,5044,5046,5048,5051],{"class":4243,"line":2800},[4241,5040,4864],{"class":4246},[4241,5042,5043],{"class":4294}," previewHeaders",[4241,5045,4298],{"class":4246},[4241,5047,4872],{"class":4246},[4241,5049,5050],{"class":4275}," getCraftPreviewHeaders",[4241,5052,4279],{"class":4250},[4241,5054,5055,5057,5059,5061,5063,5065,5067,5069,5072,5074],{"class":4243,"line":4286},[4241,5056,4652],{"class":4246},[4241,5058,4884],{"class":4250},[4241,5060,4346],{"class":4887},[4241,5062,4890],{"class":4250},[4241,5064,4893],{"class":4294},[4241,5066,4384],{"class":4250},[4241,5068,4898],{"class":4275},[4241,5070,5071],{"class":4250},"(previewHeaders)}\u003C\u002F",[4241,5073,4346],{"class":4887},[4241,5075,4906],{"class":4250},[4241,5077,5078],{"class":4243,"line":4304},[4241,5079,4344],{"class":4250},[4912,5081,3328],{"id":5082},"type-1",[4231,5084,5086],{"className":4233,"code":5085,"language":4236,"meta":734,"style":734},"\u002F\u002F key is always one of the PREVIEW_PARAMS and value is the actual query param value\n\u002F\u002F const PREVIEW_PARAMS = ['token', 'x-craft-preview', 'x-craft-live-preview']\n\nexport async function getCraftPreviewHeaders(): Promise\u003CRecord\u003Cstring, string>>\n",[4238,5087,5088,5093,5098,5102],{"__ignoreMap":734},[4241,5089,5090],{"class":4243,"line":713},[4241,5091,5092],{"class":4307},"\u002F\u002F key is always one of the PREVIEW_PARAMS and value is the actual query param value\n",[4241,5094,5095],{"class":4243,"line":719},[4241,5096,5097],{"class":4307},"\u002F\u002F const PREVIEW_PARAMS = ['token', 'x-craft-preview', 'x-craft-live-preview']\n",[4241,5099,5100],{"class":4243,"line":740},[4241,5101,4264],{"emptyLinePlaceholder":4263},[4241,5103,5104,5106,5108,5110,5112,5114,5116,5118,5121,5124,5126,5129,5131,5133],{"class":4243,"line":2800},[4241,5105,4269],{"class":4246},[4241,5107,4851],{"class":4246},[4241,5109,4596],{"class":4246},[4241,5111,5050],{"class":4275},[4241,5113,4932],{"class":4250},[4241,5115,4609],{"class":4246},[4241,5117,4937],{"class":4275},[4241,5119,5120],{"class":4250},"\u003C",[4241,5122,5123],{"class":4275},"Record",[4241,5125,5120],{"class":4250},[4241,5127,5128],{"class":4294},"string",[4241,5130,4363],{"class":4250},[4241,5132,5128],{"class":4294},[4241,5134,5135],{"class":4250},">>\n",[5137,5138,5139],"style",{},"html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}",{"title":734,"searchDepth":719,"depth":719,"links":5141},[5142,5143,5144,5145,5146],{"id":4388,"depth":719,"text":3773},{"id":4414,"depth":719,"text":3778},{"id":4469,"depth":719,"text":3783},{"id":4711,"depth":719,"text":3788},{"id":4808,"depth":719,"text":3793,"children":5147},[5148,5149],{"id":4814,"depth":740,"text":3798},{"id":4997,"depth":740,"text":3807},"Learn how you can use all middleware functions.","md",{},{"title":574,"description":5150},{"loc":579},"lTYNv1IcL2Fqa0KEn2YxDvkf2Yr4ym35L_i8K9I3oGs",1775995273400]