How-to: sitemap (live navigation editor)
Edit an existing model-driven app SiteMap's navigation tree in place — add or remove Areas, Groups, and SubAreas — without re-authoring the whole document. See the CLI reference for every flag.
These verbs complement app build-sitemap / app set-sitemap (which POST a whole
new SiteMapXml). They operate over a read-modify-write path: GET the live
sitemapxml, mutate the parsed XML tree, PATCH it back, then optionally publish.
Find the sitemap GUID
All sitemap verbs take a SITEMAP_ID positional argument — the sitemap record's
GUID. Retrieve it by name:
crm --json query odata sitemaps --select sitemapname,sitemapid
The sitemapid in data[] is what you pass as SITEMAP_ID.
Add an Area
crm --json sitemap add-area <SITEMAP_ID> \
--id cwx_sales --title "Sales" --publish
--id must match [a-zA-Z0-9_]+ and be unique across all node ids in the
document (every Area / Group / SubArea Id — so remove-node --id is never
ambiguous). A publisher prefix (e.g. cwx_) is recommended. --icon accepts a
path string or
the $webresource:<name> directive. --show-groups sets ShowGroups='true' on the
new Area.
Add a Group under an Area
crm --json sitemap add-group <SITEMAP_ID> \
--area cwx_sales --id cwx_salesgrp --title "Customers" --publish
--area is the Id of the parent Area (must already exist). The new Group Id must be
unique across all node ids in the document.
Add a SubArea under a Group
A SubArea requires exactly one content binding: --entity, --url, or
--dashboard. Passing more than one, or none, is a usage error.
# Bind a table by logical name (validated to exist in the org)
crm --json sitemap add-subarea <SITEMAP_ID> \
--area cwx_sales --group cwx_salesgrp \
--id cwx_accounts --entity account --title "Accounts" --publish
# Link to a URL (including an HTML web resource)
crm --json sitemap add-subarea <SITEMAP_ID> \
--area cwx_sales --group cwx_salesgrp \
--id cwx_dashboard --url "/WebResources/cwx_dashboard.html" --publish
# Open a dashboard by GUID (sets DefaultDashboard)
crm --json sitemap add-subarea <SITEMAP_ID> \
--area cwx_sales --group cwx_salesgrp \
--id cwx_pipe --dashboard <dashboard-guid> --publish
--entity is validated live — a logical name that does not exist in the org is
rejected before the PATCH, because a dangling Entity= silently hides the SubArea
in the UI.
There is no SubArea WebResource attribute. A web-resource-backed SubArea uses
--url pointing at the web resource URL. The $webresource: prefix is the --icon
directive only.
The new SubArea Id must be unique across all node ids in the document.
Move (reorder) a node
Reorder an existing Area, Group, or SubArea within its parent without touching its attributes or children. Exactly one destination mode is required:
# Move directly before a sibling (same parent and node type)
crm --json sitemap move-node <SITEMAP_ID> --id cwx_accounts --before cwx_contacts --publish
# Move directly after a sibling
crm --json sitemap move-node <SITEMAP_ID> --id cwx_accounts --after cwx_contacts --publish
# Move to a 0-based position among same-type siblings
crm --json sitemap move-node <SITEMAP_ID> --id cwx_accounts --index 0 --publish
The anchor for --before / --after must share the moved node's parent and node
type (e.g. you cannot anchor a Group move on an Area Id). --index must be in
range. A mismatch or out-of-range index is a clear error — no write is issued.
move-node is a pure permutation: it only repositions the node; its attributes,
children, and descendant structure are never modified.
Remove (or comment out) a node
# Hard delete — removes the node and its descendants
crm --json sitemap remove-node <SITEMAP_ID> --id cwx_accounts --publish
# Soft delete — replaces the node with a well-formed XML comment
crm --json sitemap remove-node <SITEMAP_ID> --id cwx_accounts --comment-out --publish
remove-node warns when the target is an Area or Group that has descendants
(cascade warning surfaced in meta.warnings). The command proceeds — pass
--dry-run first to preview exactly which subtree would be swept.
Publish-gated read-back — and why not to chain --no-publish edits
Gotcha —
sitemapxmlreads/writes go through the published layer. A Web API GET forsitemapxmlreturns the last published snapshot, not a staged edit (on on-prem v9.x especially). An edit written with--no-publishdoes not appear in a re-fetch untilPublishAllXmlruns.
This has a sharp consequence for multiple edits to the same sitemap: because
each verb reads sitemapxml fresh before mutating, a second --no-publish edit
re-reads the published layer (without the first edit) and PATCHes over it —
silently discarding the first unpublished edit. So do not chain
--no-publish edits against one sitemap.
Instead, let each edit publish before the next reads — --publish is the default
(it runs PublishAllXml and a T3 read-back inside the verb), so plain sequential
commands are safe:
crm --json sitemap add-area <SITEMAP_ID> --id cwx_ops --title "Operations"
crm --json sitemap add-group <SITEMAP_ID> --area cwx_ops --id cwx_opsgrp \
--title "Ops Group"
crm --json sitemap add-subarea <SITEMAP_ID> --area cwx_ops --group cwx_opsgrp \
--id cwx_contacts --entity contact
Reserve --no-publish for a single staged edit you publish yourself (e.g.
crm solution publish-all) — not for batching several edits to the same sitemap.
Solution scoping
crm --json sitemap add-area <SITEMAP_ID> \
--id cwx_ops --title "Operations" \
--solution cwx_crmworx --publish
--require-solution fails the command if no solution name resolves from --solution
or the profile default.
Preview without writing
The global --dry-run flag reads the live sitemap for real (to validate parent
references, check uniqueness, and resolve entities) but issues no PATCH:
crm --json --dry-run sitemap add-area <SITEMAP_ID> --id cwx_ops --title "Operations"