-
Notifications
You must be signed in to change notification settings - Fork 0
Home
cmscli is a standalone PHP CLI application for managing CMSMS installations from the command line. It provides automation-friendly access to common administration tasks without requiring a web browser. Distributed as a self-contained .phar file with 70 built-in commands.
Modules can extend cmscli with their own commands using the clicommands capability.
- Download
cmscli.pharfrom dev.cmsmadesimple.org - Upload it to your CMSMS root directory on the server (use binary/SFTP mode, not ASCII)
- SSH into your server and run:
cd /path/to/your/cmsms
mv cmscli.phar cmscli
chmod +x cmscli
./cmscli --helpThat's it. You run cmscli from inside your CMSMS root directory:
./cmscli site-info
./cmscli user-list
./cmscli module-list
# Or specify the CMSMS directory from elsewhere:
./cmscli --dir /path/to/cmsms site-infoIf you manage multiple CMSMS sites, place cmscli in your PATH:
mkdir -p ~/bin
cp cmscli.phar ~/bin/cmscli
chmod +x ~/bin/cmscli
# Use from any CMSMS root
cd /var/www/mysite
cmscli site-info
# Or specify the directory
cmscli --dir /var/www/mysite site-info| Option | Short | Description |
|---|---|---|
--dir <path> |
-d |
Specify CMSMS installation directory (default: current working directory) |
--help |
-h |
Display help or command list |
--nopermcheck |
-n |
Skip file ownership/permission checks |
--usestderr |
Send error messages to stderr instead of stdout | |
--version |
-V |
Display cmscli version |
| Command | Description |
|---|---|
cache-clear |
Clear the server cache |
| Command | Description |
|---|---|
config-get <var> |
Get a CMSMS config variable value |
config-set <var> <value> |
Set a CMSMS config variable |
| Command | Description |
|---|---|
content-list |
List content pages (-b brief, -D design, -p parent, -T template, -t type, -a active, -i inactive, -H hierarchy, -m show-in-menu) |
content-get <page> [property] |
Get a page property value. Defaults to content_en (-l list-props, -s smarty, -f file) |
content-create <title> |
Create a new content page (-p parent, -a alias, -T template, -t type, -c content, -f file, -m menutext, -I inactive, -M hide-from-menu) |
content-edit <page> |
Edit page properties (--title, -a alias, -T template, -p parent, -m menutext, --active, --showinmenu, -c content, -f file, -P prop=value) |
content-delete <page> |
Delete a page by alias or ID (-f force even with children) |
| Command | Description |
|---|---|
db-dump |
Generate mysqldump of CMSMS tables (-f full DB, -F file output) |
db-import |
Import SQL file into the CMSMS database (stdin) |
db-reset |
Drop tables from the CMSMS database |
| Command | Description |
|---|---|
design-list |
List designs (-b brief) |
design-export <name> |
Export design as XML (-f file) |
design-import <file> |
Import design from XML file |
| Command | Description |
|---|---|
event-list |
List system and module events with handler counts (-b brief, -o originator) |
event-send <Originator::EventName> |
Trigger an event (-p key=value for parameters, repeatable) |
| Command | Description |
|---|---|
gcb-list |
List Global Content Blocks (-b brief) |
gcb-get <name> |
Get GCB content (-f file) |
gcb-set <name> |
Set/update GCB content from file or stdin (-f file, -c create) |
| Command | Description |
|---|---|
group-add <name> |
Create a new admin group |
group-del <name> |
Remove an admin group |
group-list |
List admin groups |
group-perm-list <group> |
List permissions for a group |
| Command | Description |
|---|---|
jobs-list |
List queued background jobs with status (-b brief) |
jobs-run |
Process pending background jobs (-f force, -v verbose) |
| Command | Description |
|---|---|
log-list |
List admin log entries (--limit, -m source, -u user, -s search, -b brief) |
log-add <source> <action> |
Add an audit log entry (-i item-id, -u user-id) |
log-clear |
Clear log entries (--older-than, -m module, --all) |
| Command | Description |
|---|---|
mail-info |
Show mailer configuration |
mail-test <email> |
Send a test email (-s subject, -B body) |
| Command | Description |
|---|---|
module-activate <name> |
Activate a module |
module-deactivate <name> |
Deactivate a module |
module-hide <name> |
Hide a module from admin panel |
module-unhide <name> |
Un-hide a module |
module-install <name> |
Install a module (--forge download from Forge, --with-deps resolve dependencies) |
module-install-xml <file> |
Install a module from a local XML package file |
module-uninstall <name> |
Uninstall a module, keep files on disk (-f force) |
module-purge <name> |
Uninstall a module and delete its files (-f force) |
module-upgrade <name> |
Upgrade a module to latest version |
module-list |
List installed modules (-b brief) |
module-list-hidden |
List hidden modules |
module-package-xml <name> |
Package module into XML distribution file (-o dir, --stdout) |
| Command | Description |
|---|---|
pref-get [name] |
Get a site preference value (-l list all, -s search by pattern) |
pref-set <name> <value> |
Set/create a site preference |
module-pref-get <module> [name] |
Get a module preference via GetPreference() (-l list, -s search) |
module-pref-set <module> <name> <value> |
Set a module preference via SetPreference() |
| Command | Description |
|---|---|
route-list |
List custom routes (-b brief, -m module) |
route-add <pattern> <module> |
Add a static route (--absolute, --key2, --key3) |
route-delete <pattern> |
Delete a static route (-m module) |
| Command | Description |
|---|---|
site-info |
Display site name, version, schema version |
site-down |
Set maintenance mode (-c complete shutdown) |
site-up |
Remove maintenance mode |
site-checksum-generate |
Generate checksum file (--core, --noindexes) |
site-checksum-verify |
Verify installation integrity |
| Command | Description |
|---|---|
stylesheet-list |
List stylesheets (-b brief, -D design) |
stylesheet-export <name> |
Export stylesheet (-f file) |
stylesheet-import <name> |
Import stylesheet (-f file, -c create) |
| Command | Description |
|---|---|
template-list |
List templates (-b brief, -D design, -t type) |
template-export <name> |
Export template (-f file) |
template-import <name> |
Import template (-f file, -c create) |
template-file-export [name] |
Export template(s) to file-based editing in assets/templates/ (--all, -t type, -m module, -D design) |
template-file-import [name] |
Import template(s) from file back into database (--all, -k keep file) |
| Command | Description |
|---|---|
udt-list |
List User Defined Tags (-b brief) |
udt-export <name> |
Export UDT code (-f file) |
udt-import <name> |
Import/update UDT code (-f file, -c create, -D description) |
| Command | Description |
|---|---|
user-list |
List admin users |
user-add <username> <email> <password> |
Create new admin user (-g group) |
user-edit <username> |
Edit admin account details (--email, --firstname, --lastname) |
user-password <username> <password> |
Change an admin user's password |
user-activate <username> |
Activate an admin account |
user-deactivate <username> |
Deactivate an admin account |
user-del <username> |
Remove an admin user |
user-group <username> <group> |
Add/remove user from groups (--add, --remove) |
| Command | Description |
|---|---|
about |
Display installation/usage information |
cmsms-latestversion |
Get latest CMSMS version number |
cmsms-download |
Download latest CMSMS installation assistant |
# Display site info
cmscli site-info
# Maintenance mode
cmscli site-down # Standard maintenance page
cmscli site-down -c # Complete shutdown (no output at all)
cmscli site-up
# Clear cache
cmscli cache-clear
# Integrity verification
cmscli site-checksum-generate # All files
cmscli site-checksum-generate --core # Core files only
cmscli site-checksum-verifycmscli config-get db_prefix # Output: cms_
cmscli config-get root_url # Output: https://www.mysite.com
cmscli config-set root_url https://www.mysite.com# List pages
cmscli content-list # Full tabular list
cmscli content-list -b # Brief: aliases only
cmscli content-list -p home # Children of 'home' page
cmscli content-list -t content # Filter by type
cmscli content-list -T "My Template" # Filter by template
cmscli content-list -a # Active pages only
# Get page content
cmscli content-get home # Default: outputs content_en
cmscli content-get home extra1 # Custom content block
cmscli content-get home -l # List available properties
cmscli content-get home -s # Process through Smarty first
cmscli content-get home -f output.html # Write to file
# Create pages
cmscli content-create "My New Page"
cmscli content-create "My New Page" -p home -T "Page Template"
cmscli content-create "My New Page" -c "<p>Hello</p>"
cmscli content-create "My New Page" -f content.html -I -M
# Edit pages
cmscli content-edit my-page --title "New Title"
cmscli content-edit my-page -T "Other Template"
cmscli content-edit my-page -c "<p>Updated</p>"
cmscli content-edit my-page -P extra1="Custom value"
# Delete pages
cmscli content-delete my-page
cmscli content-delete my-page -f # Force: delete even with children# List
cmscli template-list
cmscli template-list -D "My Design" # Filter by design
cmscli template-list -t __CORE__::page # Filter by type
cmscli stylesheet-list -b # Brief: names only
# Export/Import
cmscli template-export "My Template" -f output.tpl
cmscli template-import "My Template" -f input.tpl
cmscli template-import "New Template" -f input.tpl -c # Create new
cmscli stylesheet-export "My Stylesheet" -f output.css
cmscli stylesheet-import "My Stylesheet" -f styles.css
# File-based editing workflow
cmscli template-file-export --all # Export all to assets/templates/
cmscli template-file-export -m News # All News module templates
cmscli template-file-export -D "My Design" # All in a design
# Edit .tpl files in your IDE...
cmscli template-file-import --all # Import all back to database
cmscli template-file-import "My Template" -k # Keep file after importcmscli design-list
cmscli design-export "My Design" -f design.xml
cmscli design-import design.xml# User Defined Tags
cmscli udt-list
cmscli udt-export my_tag -f my_tag.php
cmscli udt-import my_tag -f my_tag.php
cmscli udt-import new_tag -f code.php --create -D "My helper tag"
# Global Content Blocks
cmscli gcb-list
cmscli gcb-get footer -f footer.tpl
cmscli gcb-set footer -f footer.tpl
cmscli gcb-set "new block" -f block.tpl --create# Events
cmscli event-list # All events
cmscli event-list -o Core # Filter by originator
cmscli event-send Core::ContentPostRender
cmscli event-send MyModule::MyEvent -p key1=value1 -p key2=value2
# Preferences
cmscli pref-get sitename
cmscli pref-get --list # List all preference names
cmscli pref-get --search sitename # Search by pattern
cmscli pref-set sitename "My Site"
# Module Preferences
cmscli module-pref-get StoreFrontPayPal --list # List all prefs for module
cmscli module-pref-get StoreFrontPayPal paypal_testmode # Get single value
cmscli module-pref-get StoreFrontPayPal --search sandbox # Search by pattern
cmscli module-pref-set StoreFrontPayPal paypal_testmode 0# List routes
cmscli route-list # All routes
cmscli route-list -m News # Filter by module
# Add routes
cmscli route-add '/products/(?P<slug>[a-z0-9-]+)$' StoreFront
cmscli route-add '/api/callback' MyModule --absolute
cmscli route-add '/webhook' MyModule --key2 handler
# Delete routes
cmscli route-delete '/products/(?P<slug>[a-z0-9-]+)$'
cmscli route-delete '/test' -m News# List log entries
cmscli log-list # Last 50 entries
cmscli log-list --limit 10 # Last 10
cmscli log-list --source Core # Filter by source
cmscli log-list -m MeetSimple # Short form
cmscli log-list --user 1 # Filter by user_id
cmscli log-list --search "password" # Search action text
cmscli log-list -b # Brief: timestamp + action only
# Add log entry
cmscli log-add MyModule "Deployed new version"
cmscli log-add cmscli "Ran backup script" --item-id 42
# Clear log entries
cmscli log-clear --older-than 30 # Older than 30 days
cmscli log-clear --module Core # All entries from source
cmscli log-clear --older-than 7 --module News # Combined
cmscli log-clear --all # Delete ALL# List modules
cmscli module-list
cmscli module-list -b # Brief: names only
cmscli module-list-hidden
# Install from disk
cmscli module-install MyModule
# Install from Forge
cmscli module-install MyModule --forge
# Install with all dependencies resolved
cmscli module-install CGSmartImage --with-deps
# Install from local XML package
cmscli module-install-xml /path/to/MyModule-1.0.xml
# Lifecycle
cmscli module-activate MyModule
cmscli module-deactivate MyModule
cmscli module-upgrade MyModule
cmscli module-uninstall MyModule # Keep files
cmscli module-purge MyModule # Remove everything
# Package for distribution
cmscli module-package-xml MyModule
cmscli module-package-xml MyModule -o /tmp
cmscli module-package-xml MyModule --stdout # Output XML to stdout.distignore support: Place a .distignore file in your module root to exclude files from packaging (same syntax as .gitignore). Example:
.git
.kiro
releases/
tests/
The following are always excluded regardless of .distignore:
- Git:
.git,.gitignore,.gitattributes,.gitmodules,.gitkeep - AI agents:
.kiro,.claude,.amazonq,.cursor,.copilot - IDEs:
.vscode,.vs,.idea - Meta:
.distignore
#### Database
```bash
cmscli db-dump # Dump to stdout
cmscli db-dump -F dump.sql # Dump to file
cmscli db-dump -f # Full database (not just CMSMS tables)
cmscli db-import < dump.sql # Import from file
# Users
cmscli user-list
cmscli user-add jdoe john@example.com password123
cmscli user-add jdoe john@example.com password123 -g "Editor"
cmscli user-edit jdoe --email new@email.com --firstname John
cmscli user-password jdoe newpassword
cmscli user-activate jdoe
cmscli user-deactivate jdoe
cmscli user-del jdoe
cmscli user-group jdoe "Editor" --add
cmscli user-group jdoe "Editor" --remove
# Groups
cmscli group-list
cmscli group-add "My Group"
cmscli group-del "My Group"
cmscli group-perm-list "Editor"cmscli jobs-list # Full table with status
cmscli jobs-list -b # Brief: names only
cmscli jobs-run # Process if throttle allows
cmscli jobs-run --force # Ignore frequency throttle
cmscli jobs-run --force --verbose # Show per-job progressRecommended cron entry for low-traffic sites:
*/3 * * * * cd /var/www/mysite && php cmscli.phar jobs-run --force 2>/dev/nullBackup script:
#!/bin/bash
cd /var/www/mysite
cmscli site-down
cmscli db-dump -F tmp/dump.sql
tar zcf ../backup-$(date +%Y%m%d).tar.gz .
cmscli site-upDeploy workflow:
cd /var/www/mysite
cmscli site-down
git pull
cmscli cache-clear
cmscli template-file-import --all
cmscli site-upFile-based template editing:
# Export templates to disk for IDE editing
cmscli template-file-export --all
# Edit .tpl files in assets/templates/ with your editor...
# Import changes back to database
cmscli template-file-import --allAny module can contribute commands to cmscli by declaring the clicommands capability and implementing get_cli_commands().
In your main module class, override HasCapability():
public function HasCapability($capability, $params = [])
{
if ($capability == 'clicommands') return true;
return parent::HasCapability($capability, $params);
}Implement get_cli_commands() to return an array of command objects:
public function get_cli_commands(\CMSMS\CLI\App $app)
{
return [
new MyModule\Commands\ItemListCommand($app),
new MyModule\Commands\ItemExportCommand($app),
];
}Each command extends \CMSMS\CLI\GetOptExt\Command. Place them in your module's lib/Commands/ directory.
<?php
namespace MyModule\Commands;
use CMSMS\CLI\App;
use CMSMS\CLI\GetOptExt\Command;
use CMSMS\CLI\GetOptExt\Option;
use CMSMS\CLI\GetOptExt\GetOpt;
use GetOpt\Operand;
class ItemListCommand extends Command
{
public function __construct(App $app)
{
parent::__construct($app, 'mymodule-item-list');
$this->addOption(
Option::Create('b', 'brief')
->setDescription('Output only item names')
);
$this->addOption(
Option::Create('t', 'type', GetOpt::REQUIRED_ARGUMENT)
->setDescription('Filter by type')
);
$this->addOperand(
Operand::create('pattern', Operand::OPTIONAL)
);
}
public function getShortDescription()
{
return 'List items managed by MyModule';
}
public function getLongDescription()
{
return <<<EOT
Lists all items in MyModule. Use --brief for names only.
Use --type to filter by item type.
EOT;
}
public function handle()
{
$brief = $this->getOption('brief')->getValue();
$type = $this->getOption('type')->getValue();
$pattern = $this->getOperand('pattern')->getValue();
$db = $this->getDb();
$sql = 'SELECT * FROM ' . \CMS_DB_PREFIX . 'mod_mymodule_items';
$params = [];
if ($type) {
$sql .= ' WHERE type = ?';
$params[] = $type;
}
$rows = $db->GetArray($sql, $params);
if (empty($rows)) return;
if ($brief) {
foreach ($rows as $row) {
echo $row['name'] . "\n";
}
return;
}
$fmt = "%-6s %-40s %-20s\n";
echo sprintf($fmt, 'ID', 'Name', 'Type');
echo sprintf($fmt, '--', '----', '----');
foreach ($rows as $row) {
echo sprintf($fmt, $row['id'], $row['name'], $row['type']);
}
}
}parent::__construct(App $app, string $command_name, bool $requires_cmsms = true);The third parameter controls whether this command needs a CMSMS installation. Set to false only for commands that work independently (rare for module commands).
| Method | Returns | Description |
|---|---|---|
$this->getApp() |
App |
The cmscli application instance |
$this->getDb() |
Connection |
The CMSMS database connection |
$this->getOption('name') |
Option |
Get an option by name (call ->getValue() for the value) |
$this->getOperand('name') |
Operand |
Get an operand by name (call ->getValue() for the value) |
// Flag (boolean option, no argument)
$this->addOption(Option::Create('v', 'verbose')->setDescription('Verbose output'));
// Option with required argument
$this->addOption(Option::Create('f', 'file', GetOpt::REQUIRED_ARGUMENT)
->setDescription('Output file path'));
// Option with optional argument and default
$this->addOption(Option::Create('l', 'limit', GetOpt::OPTIONAL_ARGUMENT)
->setDescription('Result limit')
->setDefaultValue('50'));
// Required operand
$this->addOperand(Operand::create('name', Operand::REQUIRED));
// Optional operand
$this->addOperand(Operand::create('filter', Operand::OPTIONAL));- Write output to stdout with
echo. - Throw
\RuntimeExceptionfor errors (cmscli catches and displays them). - Exit codes: 0 for success (automatic), non-zero for errors (from exception code).
- Design for automation: minimal output, machine-parseable where possible.
Prefix your command names with the module name or a short identifier to avoid collisions:
mymodule-item-listmymodule-item-exportmymodule-sync
modules/MyModule/
lib/
Commands/
class.ItemListCommand.php
class.ItemExportCommand.php
class.SyncCommand.php
Use your module's namespace for the command classes and let CMSMS autoloading handle them.
Run your commands from the CMSMS root:
./cmscli --nopermcheck mymodule-item-list
./cmscli --nopermcheck mymodule-item-list --brief
./cmscli --nopermcheck mymodule-item-list --type articleUse --nopermcheck during development to skip file ownership checks.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1+ | Error (message printed to stdout or stderr) |