modx revolution docs 20101007

298
MODx Official Documentation 1. Home . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.1 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.1.1 Server Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.1.1.1 MySQL 5.0.51 Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.1.2 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.1.2.1 Basic Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.1.2.1.1 MODx Revolution on Debian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.1.2.1.2 Lighttpd Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.1.2.1.3 Problems with WAMPServer 2.0i . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.1.2.2 Advanced Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.1.2.3 Git Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 1.1.2.4 Troubleshooting Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 1.1.2.5 Successful Installation, Now What Do I Do? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 1.1.2.6 Using MODx Revolution from SVN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 1.1.3 An Overview of MODx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 1.1.3.1 Glossary of Revolution Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 1.1.3.1.1 Explanation of Directory Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 1.1.3.2 Roadmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 1.2 Making Sites with MODx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 1.2.1 Structuring Your Site . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 1.2.1.1 Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 1.2.1.1.1 Content Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 1.2.1.1.2 Named Anchor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 1.2.1.1.3 Static Resource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 1.2.1.1.4 Symlink . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 1.2.1.1.5 Weblink . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 1.2.1.2 Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 1.2.1.3 Chunks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 1.2.1.4 Using Snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 1.2.2 Tag Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 1.2.3 Customizing Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 1.2.3.1 Template Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 1.2.3.1.1 Creating a Template Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 1.2.3.1.2 Bindings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 1.2.3.1.3 Template Variable Output Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 1.2.3.1.4 Adding a Custom TV Input Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 1.2.3.1.5 Adding a Custom TV Output Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 1.2.3.2 Properties and Property Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 1.2.3.3 Input and Output Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 1.3 Administering Your Site . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 1.3.1 Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 1.3.1.1 System Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 1.3.1.1.1 allow_duplicate_alias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 1.3.1.1.2 allow_multiple_emails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 1.3.1.1.3 allow_tags_in_post . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 1.3.1.1.4 auto_check_pkg_updates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 1.3.1.1.5 auto_check_pkg_updates_cache_expire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 1.3.1.1.6 auto_menuindex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 1.3.1.1.7 blocked_minutes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 1.3.1.1.8 cache_action_map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 1.3.1.1.9 cache_context_settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 1.3.1.1.10 cache_db . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 1.3.1.1.11 cache_db_expires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 1.3.1.1.12 cache_default . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 1.3.1.1.13 cache_disabled . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 1.3.1.1.14 cache_handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 1.3.1.1.15 cache_json . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 1.3.1.1.16 cache_json_expires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 1.3.1.1.17 cache_lexicon_topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 1.3.1.1.18 cache_noncore_lexicon_topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 1.3.1.1.19 cache_resource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 1.3.1.1.20 cache_resource_expires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 1.3.1.1.21 cache_scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 1.3.1.1.22 compress_css . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 1.3.1.1.23 compress_js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 1.3.1.1.24 concat_js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 1.3.1.1.25 container_suffix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 1.3.1.1.26 cultureKey . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 1.3.1.1.27 custom_resource_classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 1.3.1.1.28 default_template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 1.3.1.1.29 editor_css_path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 1.3.1.1.30 editor_css_selectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 1.3.1.1.31 emailsender . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 1.3.1.1.32 emailsubject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

Upload: shambalic

Post on 18-Apr-2015

1.291 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: ModX Revolution Docs 20101007

MODx Official Documentation1. Home . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

1.1 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.1.1 Server Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.1.1.1 MySQL 5.0.51 Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71.1.2 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

1.1.2.1 Basic Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81.1.2.1.1 MODx Revolution on Debian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111.1.2.1.2 Lighttpd Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121.1.2.1.3 Problems with WAMPServer 2.0i . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

1.1.2.2 Advanced Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131.1.2.3 Git Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171.1.2.4 Troubleshooting Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191.1.2.5 Successful Installation, Now What Do I Do? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211.1.2.6 Using MODx Revolution from SVN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

1.1.3 An Overview of MODx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241.1.3.1 Glossary of Revolution Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

1.1.3.1.1 Explanation of Directory Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301.1.3.2 Roadmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

1.2 Making Sites with MODx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351.2.1 Structuring Your Site . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

1.2.1.1 Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351.2.1.1.1 Content Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381.2.1.1.2 Named Anchor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391.2.1.1.3 Static Resource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391.2.1.1.4 Symlink . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401.2.1.1.5 Weblink . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

1.2.1.2 Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421.2.1.3 Chunks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431.2.1.4 Using Snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

1.2.2 Tag Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461.2.3 Customizing Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

1.2.3.1 Template Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471.2.3.1.1 Creating a Template Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481.2.3.1.2 Bindings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501.2.3.1.3 Template Variable Output Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561.2.3.1.4 Adding a Custom TV Input Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581.2.3.1.5 Adding a Custom TV Output Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

1.2.3.2 Properties and Property Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 621.2.3.3 Input and Output Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

1.3 Administering Your Site . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671.3.1 Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

1.3.1.1 System Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691.3.1.1.1 allow_duplicate_alias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691.3.1.1.2 allow_multiple_emails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691.3.1.1.3 allow_tags_in_post . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691.3.1.1.4 auto_check_pkg_updates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701.3.1.1.5 auto_check_pkg_updates_cache_expire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701.3.1.1.6 auto_menuindex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701.3.1.1.7 blocked_minutes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701.3.1.1.8 cache_action_map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701.3.1.1.9 cache_context_settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 701.3.1.1.10 cache_db . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711.3.1.1.11 cache_db_expires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711.3.1.1.12 cache_default . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711.3.1.1.13 cache_disabled . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711.3.1.1.14 cache_handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711.3.1.1.15 cache_json . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721.3.1.1.16 cache_json_expires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721.3.1.1.17 cache_lexicon_topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721.3.1.1.18 cache_noncore_lexicon_topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721.3.1.1.19 cache_resource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721.3.1.1.20 cache_resource_expires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721.3.1.1.21 cache_scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 731.3.1.1.22 compress_css . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 731.3.1.1.23 compress_js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 731.3.1.1.24 concat_js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 731.3.1.1.25 container_suffix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 731.3.1.1.26 cultureKey . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 741.3.1.1.27 custom_resource_classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 741.3.1.1.28 default_template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 741.3.1.1.29 editor_css_path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 741.3.1.1.30 editor_css_selectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 741.3.1.1.31 emailsender . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751.3.1.1.32 emailsubject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

Page 2: ModX Revolution Docs 20101007

1.3.1.1.33 error_page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751.3.1.1.34 failed_login_attempts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751.3.1.1.35 fe_editor_lang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751.3.1.1.36 feed_modx_news . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751.3.1.1.37 feed_modx_news_enabled . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 761.3.1.1.38 feed_modx_security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 761.3.1.1.39 feed_modx_security_enabled . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 761.3.1.1.40 filemanager_path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 761.3.1.1.41 friendly_alias_urls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 761.3.1.1.42 friendly_url_prefix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 771.3.1.1.43 friendly_url_suffix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 771.3.1.1.44 friendly_urls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 771.3.1.1.45 mail_charset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 771.3.1.1.46 mail_encoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 771.3.1.1.47 mail_smtp_auth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781.3.1.1.48 mail_smtp_helo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781.3.1.1.49 mail_smtp_hosts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781.3.1.1.50 mail_smtp_keepalive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781.3.1.1.51 mail_smtp_pass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781.3.1.1.52 mail_smtp_port . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781.3.1.1.53 mail_smtp_prefix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781.3.1.1.54 mail_smtp_single_to . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791.3.1.1.55 mail_smtp_timeout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791.3.1.1.56 mail_smtp_user . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791.3.1.1.57 mail_use_smtp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791.3.1.1.58 manager_date_format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791.3.1.1.59 manager_direction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791.3.1.1.60 manager_lang_attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801.3.1.1.61 manager_language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801.3.1.1.62 manager_theme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801.3.1.1.63 manager_time_format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801.3.1.1.64 modx_charset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801.3.1.1.65 new_file_permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801.3.1.1.66 new_folder_permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 801.3.1.1.67 password_generated_length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 811.3.1.1.68 password_min_length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 811.3.1.1.69 phpthumb_cache_maxage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 811.3.1.1.70 phpthumb_cache_maxfiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 811.3.1.1.71 phpthumb_cache_maxsize . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 811.3.1.1.72 phpthumb_cache_source_enabled . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 811.3.1.1.73 phpthumb_far . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821.3.1.1.74 phpthumb_zoomcrop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821.3.1.1.75 proxy_auth_type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821.3.1.1.76 proxy_host . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821.3.1.1.77 proxy_password . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821.3.1.1.78 proxy_port . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821.3.1.1.79 proxy_username . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821.3.1.1.80 publish_default . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831.3.1.1.81 rb_base_dir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831.3.1.1.82 rb_base_url . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831.3.1.1.83 request_controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831.3.1.1.84 request_param_alias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831.3.1.1.85 request_param_id . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841.3.1.1.86 search_default . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841.3.1.1.87 server_offset_time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841.3.1.1.88 server_protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841.3.1.1.89 session_cookie_domain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841.3.1.1.90 session_cookie_lifetime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841.3.1.1.91 session_cookie_path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 851.3.1.1.92 session_cookie_secure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 851.3.1.1.93 session_handler_class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 851.3.1.1.94 session_name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 851.3.1.1.95 settings_version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 851.3.1.1.96 signupemail_message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 861.3.1.1.97 site_name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 861.3.1.1.98 site_start . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 861.3.1.1.99 site_status . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 871.3.1.1.100 site_unavailable_message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 871.3.1.1.101 site_unavailable_page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 871.3.1.1.102 strip_image_paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 871.3.1.1.103 tree_root_id . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 881.3.1.1.104 udperms_allowroot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 881.3.1.1.105 unauthorized_page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 881.3.1.1.106 upload_maxsize . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 881.3.1.1.107 use_alias_path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

Page 3: ModX Revolution Docs 20101007

1.3.1.1.108 use_browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 891.3.1.1.109 use_editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 891.3.1.1.110 use_multibyte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 891.3.1.1.111 welcome_screen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 891.3.1.1.112 which_editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 891.3.1.1.113 which_element_editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90

1.3.2 Using Friendly URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 901.3.3 Contexts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

1.3.3.1 Creating a Subdomain from a Folder using Virtual Hosts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921.3.3.2 Using One Gateway Plugin to Manage Multiple Domains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

1.3.4 Customizing the Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 941.3.4.1 Form Customization Pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

1.3.4.1.1 FC-Resource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 951.3.4.1.2 FC-Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 961.3.4.1.3 FC-Chunk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 971.3.4.1.4 FC-Snippet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 971.3.4.1.5 FC-Plugin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97

1.3.4.2 Form Customization Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 971.3.4.2.1 Field Default . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 991.3.4.2.2 Field Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1001.3.4.2.3 Field Visible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1011.3.4.2.4 Move TV to Tab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1021.3.4.2.5 New Tab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1031.3.4.2.6 Tab Title . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1051.3.4.2.7 Tab Visible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1061.3.4.2.8 TV Default . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1061.3.4.2.9 TV Title . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1071.3.4.2.10 TV Visible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

1.3.5 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1091.3.5.1 Users . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1101.3.5.2 User Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1121.3.5.3 Resource Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1121.3.5.4 Roles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1131.3.5.5 Policies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115

1.3.5.5.1 Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1171.3.5.5.2 ACLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120

1.3.5.6 Security Tutorials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1211.3.5.6.1 Giving a User Manager Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1211.3.5.6.2 Making Member-Only Pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

1.3.6 Installing a Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1241.3.6.1 Troubleshooting Package Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126

1.3.7 Upgrading MODx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1261.3.7.1 Upgrading from MODx Evolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127

1.3.7.1.1 Functional Changes from Evolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1281.3.7.2 Upgrading to Revolution 2.0.0-rc-2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129

1.3.8 Moving Your Site to a New Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1301.4 Developing in MODx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132

1.4.1 Code Standards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1321.4.2 Overview of MODx Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143

1.4.2.1 Developer Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1431.4.2.1.1 Getting Started Developing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

1.4.2.2 Extras Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1461.4.2.3 Setting up a Development Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146

1.4.3 Basic Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1481.4.3.1 Snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

1.4.3.1.1 Templating Your Snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1511.4.3.1.2 Adding CSS and JS to Your Pages Through Snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154

1.4.3.2 Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1551.4.3.2.1 System Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

1.4.3.3 xPDO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1931.4.4 Advanced Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193

1.4.4.1 Namespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1931.4.4.2 Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1941.4.4.3 Custom Manager Pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195

1.4.4.3.1 Actions and Menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2001.4.4.3.2 Custom Manager Pages Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2011.4.4.3.3 MODExt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203

1.4.4.4 Internationalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2081.4.4.4.1 Creating Lexicons for Your Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211

1.4.4.5 MODx Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2111.4.4.5.1 modMail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211

1.4.4.6 Package Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2121.4.4.6.1 Transport Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2141.4.4.6.2 Providers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2161.4.4.6.3 Creating a 3rd Party Component Build Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218

Page 4: ModX Revolution Docs 20101007

1.4.4.7 Extending modUser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2311.4.5 Other Development Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235

1.4.5.1 Loading MODx Externally . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2351.4.5.2 API Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2361.4.5.3 Class Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236

1.4.5.3.1 modX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2361.4.5.3.2 modChunk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2611.4.5.3.3 modUser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262

1.5 Case Studies and Tutorials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2681.5.1 Using Custom Database Tables in your 3rd Party Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2681.5.2 Creating a Blog in MODx Revolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2731.5.3 PHP Coding in MODx Revolution, Pt. I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2831.5.4 PHP Coding in MODx Revolution, Pt. II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2851.5.5 PHP Coding in MODx Revolution, Pt. III . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2861.5.6 Loading Pages in the Front-End via AJAX and jQuery Tabs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2881.5.7 Managing Resources and Elements via SVN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2901.5.8 xPDO XML Schema File vs. Table Structure Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2911.5.9 Adding Custom Fields to Manager Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293

1.6 MODx Community Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2941.6.1 Getting a MODx Account . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2941.6.2 Filing Bug Reports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2941.6.3 Becoming a Core Contributor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295

1.6.3.1 Development Environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2961.6.3.2 MODx PHP Coding Standards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297

1.6.4 Using GitHub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298

Page 5: ModX Revolution Docs 20101007

Home

MODx RevolutionBeen stuck with a bloated portal system that doesn't fit your site's mold? Tired of hacking away at existing CMSes to get things the way you want?Look no further: MODx is here.

The long-awaited MODx Revolution version power-packs all sorts of new features that the MODx community asked for, such as site contexts,improved caching, increased flexibility, transport packaging, a brand-new revamped manager interface and much more.

You asked. We listened. Here is our answer: Revolution.

Want to contribute to Revolution development or testing? See our page.Becoming a Core Contributor

Revolution 2.0 Official DocumentationThis is the official documentation space for MODx Revolution 2.0.

Getting Started

Making Sites with MODx

Administering Your Site

Developing in MODx

Case Studies and Tutorials

MODx Community Information

You can download the documentation in , as of July 21st, 2010.PDF format

Page 6: ModX Revolution Docs 20101007

Getting Started

Welcome to MODx Revolution. This section provides installation tutorials, beginning concepts around MODx, and general information aboutMODx to get you started.

Server Requirements

Supported Operating Systems

Linux x86, x86-64Mac OS XWindows XP, Server

Supported Web Servers

Apache 1.3.x - 2.2.x (uses htaccess for Friendly URLs by default)IIS 6.0lighttpd ( )Setup and Friendly URL GuideZeus

PHP Compatibility

5.1.1 and above (excluding 5.1.6 and 5.2.0)Required extensions:

zlibJSON (or PECL library)mod_rewrite (for friendly URLs/.htaccess)GD lib (required for captcha and file browser)PDO, specifically pdo_mysql (for xPDO)SimpleXML

Safe_mode offRegister_globals offPHP memory_limit 24MB or more, depending on your server

PHP Configuration Options

./configure --with-apxs2=/usr/local/bin/apxs --with-mysql --prefix=/usr/local --with-pdo-mysql--with-zlib

MySQL Database Requirements

4.1.20 or newer, with the following permissions:SELECT, INSERT, UPDATE, DELETE are required for normal operationCREATE, ALTER, INDEX, DROP are required for installation/upgrades and potentially for various add-onsCREATE TEMPORARY TABLES may be used my some 3rd party add-ons

excludes version 5.0.51 ( )Why not 5.0.51?InnoDB storage engineMyISAM storage engine

Supported Browsers (for Backend Manager Interface)

Mozilla Firefox 3.0 and aboveApple Safari 3.1.2 and aboveMicrosoft Internet Explorer 8 and above

IE7 is not fully supported at this time, but may be in a feature release. You are free to use it, but might experience bugs hereand there.

Page 7: ModX Revolution Docs 20101007

MySQL 5.0.51 Issues

Why does MODx not support MySQL server version 5.0.51?

MySQL 5.0.51, including 5.0.51a, has serious bugs with PDO, specifically grouping, ordering and prepare statements.

It will cause uncorrectable errors in normal queries in MODx, as well as other open source applications, and therefore MODx does not supportinstallations with MySQL 5.0.51 installed. Please upgrade your MySQL installation.

MySQL 5.0.51 Server Buglist

Here are just some of the bugs that occur:

http://bugs.mysql.com/bug.php?id=32202http://bugs.php.net/bug.php?id=47655http://bugs.mysql.com/bug.php?id=36406

Installation

This page is for New Installations only. If you're looking to upgrade, see .Upgrading MODx

Downloading MODx

First off, you'll want to download MODx Revolution 2.0. Currently, there are two ways you can do so:

From the MODx Site

The quickest way to get your Revolution site up and running is to grab a copy directly from the page. There you will findMODx Downloadsdownloads for MODx Revolution.

It's worth noting that these packages are basically snapshots from Git, our version control software, at the time they were packaged. A lot mayhave changed since then, including bugfixes and the addition of new features. Note the release date for each package. Git will always have thelatest up-to-date snapshot of Revolution.

"Normal" vs. "Advanced"

You have probably noticed that there are a few different of packages to choose from. Some are labeled as "Advanced," others are just atypesplain old "modx-2.0.0-xxxx-#.zip". So what do these labels mean?

Normal - These packages are pre-built snapshots from Git. You can simply extract the files to your server and follow the Basic Installationguide to install MODx. Most users should choose this version.

Advanced - These packages are slightly less than half the size of the "Regular" downloads, since the "core" contents are compressed.MODx Setup will try to unpack or "build" this package during install. It's recommended you only use this if you plan to move the core,manager or connectors directories, and you have SSH access and are familiar with making folders writable. Please follow the Advanced

document for this distribution.Installation

From Git

MODx Revolution 2.0.0 is managed on . Please read the document to learn how to use MODx Revolution from Git.GitHub Git Installation

Installing MODx

MODx comes with multiple distributions for download. Installation steps will differ in each distribution, so please select the distribution's installationguide below:

Normal Distribution: Basic InstallationAdvanced Distribution: Advanced InstallationBuilding from Git: Git Installation

Page 8: ModX Revolution Docs 20101007

After finishing installation, if you are still having issues, please read the page.Troubleshooting Installation

Basic Installation

Beginning SetupInstall OptionsDatabase Options

Collations and CharsetsCreating an Administrator User

Pre-Installation ChecksPost-Installation SummaryAdditional Info

WAMPServer 2.0iMAMP on MacOSXDebianVista and XAMPPInstalling PackagesSee Also

Beginning Setup

After you've MODx Revolution, start the install process by loading your web browser and running the setup script by navigating to thedownloaded folder.setup/

You might want to check the page first. If you're still having issues installing, please read the Server Requirements page.Troubleshooting Installation

Before running setup, make sure your core/cache/ and core/config/ directories are writable by PHP.

From there you will be asked to choose a language, and be presented with a welcome screen. Click Next when you're ready.

Install Options

After this, you'll be presented with a screen with some Install Options:

Page 9: ModX Revolution Docs 20101007

The New Installation option should be the only available option for you to choose. If you need to adjust the file permissions for your webserver,you can do so in the textfields below. Most servers will be fine with the default values.

When you're finished, click Next to proceed.

Database Options

From here, you will get a form asking you for your database information:

Add in your database hostname, which is the URL at which your database is located. For most users, this will be 'localhost'. If you have yourMySQL server on a different port, specify it like so: "my.database.com;port=3307", with the ;port= appending the IP/hostname.

Also, if you want, you can specify a different table prefix here. This tells MODx to prefix the tables with this value - this is useful should you want tomake multiple MODx installations on one database.

When finished, click the 'Test database server connection and view collations' link. Should you have any errors, they will show below. If you dohave errors, check to make sure your database username and password are correct. Also, if your user does not have access to create adatabase, you might need to do that manually.

Collations and Charsets

This will then popup another form for setting your database charset and collation:

Page 10: ModX Revolution Docs 20101007

1.

2. 3.

4.

For most users you can leave these values at what they are. However, if you need to change them, the collation matches the charset.make sureClick the 'Create or test selection of your database.' after you've finished.

Creating an Administrator User

This form will now present you with a few fields for setting up your administrator user. Specify a username that you want to be the administratorusername.

MODx recommends using 'admin', as this is a common administrator username and is often the first username hackersnotcheck.

From there, put in your email (or the email of your administrator) and specify a password. Click next when you're finished.

Pre-Installation Checks

MODx will then proceed with a list of checks to verify that your system is ready for installing. If any of these fail, you'll need to proceed with thedirections that it suggests to make sure your environment meets the and has the correct directories writable.Server Requirements

Once you're ready, and all the checks pass, click 'Install' to proceed.

If you get a blank screen or cannot proceed after clicking 'Install', verify these steps:

Make sure the directories "/[root]", "/core/packages","/core/cache", and "/core/export" are writable. (root will be theactual directory you are installing to.)Make sure your php.ini setting sets memory_limit to 128M, and max_execution_time to 120Create a blank file "/core/config/config.inc.php" and make it writable. DO NOT COPY config.inc.tpl! Just make it ablank file!Post a message in the regarding your issue. State your server setup and installation info, and we'll tryRevolution forumand help you find a solution.

Post-Installation Summary

MODx will then let you know if any errors occurred during install, and prompt you to attempt reinstallation should any of those errors haveoccurred.

When install is successful, click 'Next' to proceed, and you'll be presented with one final option:

Page 11: ModX Revolution Docs 20101007

MODx recommends that you make sure to remove the setup/ directory after installing, to safeguard your site from anyone else trying to run setupon your site. You can do this by clicking the 'Check this to DELETE the setup directory from the filesystem.' checkbox.

When ready, click 'Login' to be presented with the Login form for the manager interface. You're finished!

Additional Info

Some other special cases:

WAMPServer 2.0i

Please see this article: Problems with WAMPServer 2.0i

MAMP on MacOSX

MAMP (including latest 1.8.4) works fine with MODx Revolution, with one exception. You cannot use eAccelerator as the caching system, as thedrivers compiled with MAMP are faulty with regards to PDO and will cause Apache kernel errors. Select the 'xCache' caching drivers to remedythis.

Debian

Debian uses outdated MySQL drivers for its PHP build that will need to be updated; please see the article for moreMODx Revolution on Debianinformation.

Vista and XAMPP

There have been reported problems with installing Revolution on 64-bit Vista with XAMPP. We cannot guarantee a working solution on that OSand setup at this time.

Some users have reported that applying a fix found here: will fixhttp://www.apachefriends.org/f/viewtopic.php?f=16&t=32617Apache crashing errors with PDO support in XAMPP.

Installing Packages

For information on installing 3rd-party packages, see the article.How to Install Packages

See Also

MODx Revolution on Debian

MODx Revolution on Debian

Debian packages in old versions of MySQL drivers in, so to get it up-to-date and working with the PDO drivers in MODx Revolution, you'll have to

Page 12: ModX Revolution Docs 20101007

1. 2.

do the following:

Update the server MySQL drivers. You can do this manually on debian, or use apt-get.Update the client MySQL drivers. The easiest way to do this is by updating PHP, like so:

vi /etc/apt/sources.list (you can choose a different mirror): deb http://packages.dotdeb.org stable alldeb-src http://packages.dotdeb.org stable alldeb http://php53.dotdeb.org stable alldeb-src http://php53.dotdeb.org stable all

apt-get updateapt-get upgrade php5

vi /etc/php5/apache2/php.ini date.timezone = Europe/Amsterdam

/etc/init.d/apache2 reload

Lighttpd Guide

Lighttpd Guide for Setup and Friendly URLs.Friendly URL Setup

Lighttpd Guide for Setup and Friendly URLs.

This is still a work in progress, and currently only covers the URL rewriting aspect.This guide assumes you already have a working lighttpd, mysql, and PHP installation.This guide only covers proper settings and the use of friendly URL Rewriting.

Friendly URL Setup

lighttpd does not use the same system, or even same idea as Apache does for URL rewriting. All URL rewriting is done in thelighttpd.conf file

First we need to make sure that the URL rewriting module is enabled.So open your lighttpd.conf config file (In Linux it is usually located in /etc/lighttpd/lighttpd.conf)Look for the directive server.modules.Under this directive, look for an entry named "mod_rewrite",.By default it has a # in front of it. This is a comment symbol. Please remove the # from the line and save the file.

Next we need to find the location in which to put the friendly URL code.So lets search for something that looks like this:

$SERVER[ ] == {"socket" ":80" $HTTP[ ] =~ {"host" "yourdomainname.com" server.document-root = "/path/to/your/doc/root" server.name = "yourservername"

Directly under this you should add the following code.

url.rewrite-once = ( => ,"^/(assets|manager|core|connectors)(.*)$" "/$1/$2" => ,"^/(?!index(?:-ajax)?\.php)(.*)\?(.*)$" "/index.php?q=$1&$2" => "^/(?!index(?:-ajax)?\.php)(.*)$" "/index.php?q=$1" )

Page 13: ModX Revolution Docs 20101007

This does not mean you are done! Lighttpd handles url-rewrites a bit differently. You HAVE to exclude any files or folders you donot want rewritten in the config file. Excluded dirs/files in the example above are (assets|manager|core|connectors). If you wishto add more to these, simple add another | followed by the folder or filename you wish to omit from url rewriting.

After this is done, you will have working friendly URLs again in lighttpd.

Problems with WAMPServer 2.0i

How to get WAMPServer 2.0i working on MODx Revolution

Mary (einsteinsboi) has a great blog post about using WAMPServer 2.0i with MODx Revolution, and some problems you might encounter.

http://codingpad.maryspad.com/2010/01/11/modx-revolution-and-wamp/

A short summary and explanation is below.

WAMPServer uses mismatched MySQL Server and Client builds

Usually it is best to make sure in any server configuration that your MySQL server and client build versions are the same. WAMPServer allowsyou to start your stack with different versions of PHP/MySQL combinations.

The problem child comes in WAMPServer 2.0i's PHP 5.2.11 version. It sets its server version at 5.1.36, but its client version at 5.0.51a. MODx , and therefore will not install with this configuration.does not support 5.0.51a

The Solution

To fix it, simply start WAMPServer with the PHP 5.3.0 build. WAMPServer 2.0i will set the server to 5.1.36, and the client to 5.0.5-dev. While stillnot optimal, this will allow Revolution to run smoothly without MySQL hiccups.

Advanced Installation

Installation Pre-StepsRenaming or Moving the CoreChanging the Configuration Key

Advanced OptionsDatabase Options

Collations and CharsetsCreating an Administrator User

Context ConfigurationPre-Installation ChecksPost-Installation SummarySee Also

This is the tutorial for the advanced distribution of MODx. It is recommended to only install this distribution if:

You plan on renaming the manager/ or connectors/ directories, or move the core/ directoryYou have SSH access or can easily move/make writable directories on your server.

You might want to check the page first. If after reading this, you're still having issues installing, pleaseServer Requirementsread the page.Troubleshooting Installation

Installation Pre-Steps

After you've MODx Revolution's advanced distribution, upload and extract it to your server. You should be left with two directories -downloadedcore/ and setup/. From here, if you plan on moving the core/ directory, proceed to the next section. If you're not going to do so, or rename theconfig key, browse to in your browser and skip to the section of this document.setup/ Advanced Options

Renaming or Moving the Core

Page 14: ModX Revolution Docs 20101007

MODx Revolution allows you to rename and/or move the core/ directory to enhance your level of security. You can also move the core/ directoryoutside of the webroot to further secure your MODx installation.

Should you choose to rename or move the core, MODx recommends doing so before installing. Simply rename or move the core, and setup/ - atthe beginning - will present you with a page asking for the new location of the core:

Enter into the textfield the absolute path to where you have moved the core directory. If MODx is able to find the core from there, you will proceednormally with the installation. If MODx still cannot find the directory from the path you specified, check if you have typed it correctly, that it is anabsolute path, and that you've made the directory readable (and the core/cache/ file writable).

MODx might also ask you to make the setup/includes/core.config.php file writable. This is required to change the core path, and you should do sobefore proceeding.

Changing the Configuration Key

From here, MODx will ask you to choose a language. Do so at this time. MODx will then prompt you with a welcome page, and below will ask ifyou want to change the MODx Configuration Key. This allows you to run multiple sites with a shared core, as each individual site will need its ownunique configuration key.

To change it, simply click the link the install tells you to change the config key, and you'll be presented with a textfield:

Specify a custom, unique config key and click next.

Advanced Options

You will now be presented with some options for install, similar to the screen, but with two extra options at the bottom. 'NewBasic InstallationInstallation' will be your only radio option available to check, which is what you want. Below that, you can choose to adjust the permissions forcreating new files or folders in your MODx installation. The defaults should work fine, but if on a more restrictive server, you can change thefolder/file perms to 0775/0664, respectively.

Below that, you will be presented with two checkbox options:

Page 15: ModX Revolution Docs 20101007

These will be grayed out during new installations. (During upgrades, it is recommended that you uncheck these as well.) Click 'Next' to proceed tothe next step.

Database Options

From here, you will get a form asking you for your database information:

Add in your database hostname, which is the URL at which your database is located. For most users, this will be 'localhost'. If you have yourMySQL server on a different port, specify it like so: "my.database.com;port=3307", with the ;port= appending the IP/hostname.

Also, if you want, you can specify a different table prefix here. This tells MODx to prefix the tables with this value - this is useful should you want tomake multiple MODx installations on one database.

When finished, click the 'Test database server connection and view collations' link. Should you have any errors, they will show below. If you dohave errors, check to make sure your database username and password are correct. Also, if your user does not have access to create adatabase, you might need to do that manually.

Collations and Charsets

This will then popup another form for setting your database charset and collation:

For most users you can leave these values at what they are. However, if you need to change them, the collation matches the charset.make sureClick the 'Create or test selection of your database.' after you've finished.

Creating an Administrator User

Page 16: ModX Revolution Docs 20101007

1.

2. 3.

4.

This form will now present you with a few fields for setting up your administrator user. Specify a username that you want to be the administratorusername.

MODx recommends using 'admin', as this is a common administrator username and is often the first username hackersnotcheck.

From there, put in your email (or the email of your administrator) and specify a password. Click next when you're finished.

Context Configuration

MODx will now present you with a detailed context installation screen. This is where you can configure the paths to your web context (the maincontext), as well as the directories for your connectors/ and manager/ folders. MODx recommends leaving the web/ context paths as they are,unless you have a special reason not to.

Renaming your manager/ and connectors/ directories, however, can add an extra level of security to your site. Simply change the paths and URLsin the textfields provided. Note: If you do change the directories, the directories any of those paths must be writable to allow MODx to writeabovethe manager/ and/or connectors/ directories to them.

Make sure you change the path and URL!both

When done, click 'Next' to proceed.

Pre-Installation Checks

MODx will then proceed with a list of checks to verify that your system is ready for installing. If any of these fail, you'll need to proceed with thedirections that it suggests to make sure your environment meets the and has the correct directories writable.Server Requirements

Once you're ready, and all the checks pass, click 'Install' to proceed.

If you get a blank screen or cannot proceed after clicking 'Install', verify these steps:

Make sure the directories "/[root]", "/core/config", "/core/packages","/core/cache", and "/core/export" are writable. (rootwill be the actual directory you are installing to.)Make sure your php.ini setting sets memory_limit to 128M, and max_execution_time to 120Ensure that MODx can create the manager and connectors directories; this is done by making the parents of thosedirectories writable (since you can change where they are installed)Post a message in the regarding your issue. State your server setup and installation info, and we'll tryRevolution forumand help you find a solution.

Post-Installation Summary

MODx will then let you know if any errors occurred during install, and prompt you to attempt reinstallation should any of those errors haveoccurred.

When install is successful, click 'Next' to proceed, and you'll be presented with one final option:

Page 17: ModX Revolution Docs 20101007

MODx recommends that you make sure to remove the setup/ directory after installing, to safeguard your site from anyone else trying to run setupon your site. You can do this by clicking the 'Check this to DELETE the setup directory from the filesystem.' checkbox.

When ready, click 'Login' to be presented with the Login form for the manager interface. You're finished!

See Also

Git Installation

Installation ProcessGit Location

Stable BranchesDevelopment Branches

Run the BuildRun Setup

Upgrading Your Local Git Repository After CommitsSending Pull RequestsSwitching Branches

Additional InformationUsing MAMP on Mac OS X

Installation Process

Here are some notes on participating in MODx Revolution testing and/or development. Unlike previous versions of MODx, Revolution will notinstall directly from Git. Because of the nature of the new packaging and installation system, you must first create the core installation packageusing a PHP build script before running the setup.

Git Location

Git clone the revolution repository on GitHub at: using this syntax:http://github.com/modxcms/revolution/

git clone http://github.com/modxcms/revolution.git

Or, if you'd like to contribute back, and clone that repository with:fork it in your GitHub repository

git clone [email protected]:yourgitusernamehere/revolution.git

Forking it with your GitHub account will allow you to contribute back to MODx by sending pull requests by clicking the "Pull Request" button onyour GitHub page. (You'll need to before we can accept your code, though.)submit a CLA

If you're not familiar with Git, please read the excellent tutorial from and view the .GitHub GitHub help pages

From there, make sure you are working on the branch, if you're wanting the latest bugfix release. There are three current branches in the2.0modxcms/revolution GitHub repository:

Stable Branches

master - This will usually match the latest release; ie, 2.0.0-pl. It is the stable branch, and is only changed during releases.

Page 18: ModX Revolution Docs 20101007

Development Branches

2.0 - The latest development branch for 2.0.x releases; all patches (not new features) are committed to here.2.1 - For new features for 2.1. All feature branches eventually integrate into this branch. Patches from the 2.0 branch are merged to herefrom time to time.

To create a local tracking branch from one in the origin remote; after cloning, just type:

git checkout -b 2.0 origin/2.0

And git will handle the rest.

There will be other branches in the future, centered around new features. New branches will be feature-specific and merged intothe 2.1 branch when they are complete and stable.

Run the Build

If this is the first time you are building from Git, copy the file _build/build.config.sample.php to _build/build.config.php and edit the properties topoint at a valid database with proper credentials. NOTE that this database does not have to contain anything; the build script just needs to be ableto make a connection to a MySQL database.

From the command line, change your working directory to _build/ and execute the command "php transport.core.php". If the PHP executable isnot in your path, you will need to either edit the path or give the full path to the PHP executable in the command line. The build process may takean extended period of time (10 to 30 seconds likely), so be patient. (Note: on Mac Mini (1.66Ghz Intel Core Duo with 2GB RAM) running theLeopard development environment as outlined below, this only takes 5-10 seconds.)

Note that you can also do this from the browser by browsing to the _build/transport.core.php directory, if that directory isaccessible in your web server setup.

Once that script is finished executing, confirm that you now have a file named core/packages/core.transport.zip and a directorycore/packages/core/ containing a manifest.php and many other files/directories.

Run Setup

Now you are ready to execute the new setup script at the setup/ URL (e.g. if installed in a subdirectory of the webhttp://localhost/modxrevo/setup/root named modxrevo/).

Make sure you check both the "Core package has been manually unpacked" and "Files are already in-place" options wheninstalling from Git.

If you change any paths on the Context Paths setup step, make sure and move the corresponding directories as appropriate; this is intended forinstalls from the core package with files not already in-place, where the installer will place the files in the specified locations (assuming thelocations allow the PHP process to write to them).

The actual install process requires more than the default 8M of memory allocated to PHP in many default php.ini files; if you geta blank page when you click "install", try increasing the memory_limit configuration to 32M or more (16M may work, but why notgive php a little space, eh?).

Upgrading Your Local Git Repository After Commits

Simply run these two commands:

git fetch origingit rebase origin/2.0

And Git will update your install. (Substitute '2.0' for '2.1' or 'master' if you're running from another branch.)

When a commit is made, this message might show up in the commit:

[ReUp] - If your updates require a core transport rebuild (such as anything modified in the _build directory, database model changes, or

Page 19: ModX Revolution Docs 20101007

default data changes), then prefix your commit message with this. If you see this message, simply rebuild the core transport and runsetup/ again.

If this message does not show up, you're done after you fetch and rebase.

Sending Pull Requests

If you've fixed a bug or added an improvement, and you're working on a fork of the revolution repository, you can send a pull request to MODxand one of the Integration Managers will review your patch. you are sending pull requests to the development branches, ie 2.0 forMake surepatches or 2.1 for new features. Pull requests to master will be ignored.

You'll need to before we can accept your code.submit a CLA

Switching Branches

If you want to switch to a different branch, simply type these commands:

git fetch origingit checkout 2.1

Of course, replacing 2.1 with the name of the branch you want to switch to. After you've done so, run the build and run setup/ again, sincedifferent branches might have different databases.

Switching is not always recommended; ie, switching from 2.1 to 2.0, since database changes don't alwaysbackwardsnecessarily 'backport'. While no major issues should occur, be careful when doing this.

Additional Information

Using MAMP on Mac OS X

If you use MAMP on Mac OS X, you may get problems (errors about DYLD libraries not being included) when trying to execute''transport.core.php'' from the terminal. This is because the MAMP PHP libraries won't be on the dynamic linker path by default.

To adjust the dynamic linker library path to include the MAMP PHP libraries, run the following command via the terminal:

export DYLD_LIBRARY_PATH=/Applications/MAMP/Library/lib:$\{DYLD_LIBRARY_PATH\}

You can then execute ''transport.core.php'' by using the absolute path to the MAMP PHP executable:

/Applications/MAMP/bin/php5/bin/php transport.core.php

Troubleshooting Installation

Common ProblemsPDO Error MessagesCommon Error Messages

"I get a blank white screen instead of the options page!""I clicked install and got a blank white screen!""Cannot connect to database" in the database options pageWarning: PDO::__construct() [pdo.--construct]: [2002] Argument invalid (trying to connect via unix://) OR "Checkingdatabase:Could not connect to the mysql server."The login page keeps redirecting me back to the login screen with no errorThings sometimes don't load, the page flakes out, etc (eAccelerator)Resource / Elements / File tree not appearingI can't login to the manager after installing!

Still Having Issues?

Common Problems

Page 20: ModX Revolution Docs 20101007

First off, make sure:

You have eAccelerator disabled during install. eAccelerator can cause problems when doing the heavy lifting during the install process.You followed all the directions for your distribution.hereYou are using at least PHP 5.1.1+, but not 5.1.6 or 5.2.0You are using MySQL later than 4.1.20, but not any iteration of MySQL 5.0.51 (including 5.0.51a).

PDO Error Messages

If you are getting PDO-related error messages during install, before proceeding to specific error messages as below, please confirm that yourPDO configuration is setup correctly. You can do so by running this code (replace user/password/database/host with your setup):

<?php/* Connect to an ODBC database using driver invocation */$dsn = 'mysql:dbname=testdb;host=localhost';$user = 'dbuser';$password = 'dbpass';

{try $dbh = PDO($dsn, $user, $password);new} (PDOException $e) {catch echo 'Connection failed: ' . $e->getMessage();}?>

If this fails, then your PDO setup is not configured correctly.

Common Error Messages

Here are some common problems that might occur during installation and their solutions:

"I get a blank white screen instead of the options page!"

You probably copied config.inc.tpl to config.inc.php, which is incorrect. Make the config.inc.php file an empty, writable file.

If you renamed the config.inc.tpl to config.inc.php, rename it back to config.inc.tpl and create a blank file named config.inc.php that is writable.

"I clicked install and got a blank white screen!"

Make sure your 'memory_limit' setting in php.ini is set to at least 32M. For slower servers, you might need to up it to 64M.

"Cannot connect to database" in the database options page

One of the common causes of this problem is that you're using a non-standard port for MySQL. Try putting this syntax into the hostname field(replacing the data with your mysql server's host and port):

my.database.com;port=3307

Warning: PDO::__construct() [pdo.--construct]: [2002] Argument invalid (trying to connect via unix://) OR "Checkingdatabase:Could not connect to the mysql server."

This means your MySQL socket is incorrectly configured. Usually this can be remedied by adding to (or updating) your php.ini:

mysql.default_socket=/path/to/my/mysql.sockmysqli.default_socket=/path/to/my/mysql.sockpdo_mysql.default_socket=/path/to/my/mysql.sock

The login page keeps redirecting me back to the login screen with no error

This can happen with older Revolution beta installs. To fix it, delete the following 3 system settings from the DB table `prefix_system_settings`(where prefix is your table prefix):

session_namesession_cookie_pathsession_cookie_domain

Page 21: ModX Revolution Docs 20101007

1. 2. 3. 4.

Then delete the core/cache/config.cache.php file.

Unless, of course, you've changed these explicitly for some purpose of your own.

Things sometimes don't load, the page flakes out, etc (eAccelerator)

Are you running eAccelerator? In some server configurations, this can cause problems. You might need to disable it. You can do so via yourphp.ini:

eaccelerator.enable = 0;eaccelerator.optimizer = 0;eaccelerator.debug = 0;

or in your .htaccess in the modx root directory, if your server supports php_flag server directives:

php_flag eaccelerator.enable 0php_flag eaccelerator.optimizer 0php_flag eaccelerator.debug 0

Resource / Elements / File tree not appearing

Additional, page "flake outs" may stem from items stored within your own browser's cache, which may result with the resource / elements / filetree not appearing due to old versions of javascript and other files being utilized on the client side.  This can be verified by accessing the managerwith a browser not previously utilized in doing so. 

The simple fix: clear your browser's cache, and log back into the manager.

A more complete solution: 

Under System Clear CacheUnder Security Flush Permissions and then Flush SessionsThis will dump everything and log you outLast step Clear your browser cache

I can't login to the manager after installing!

If you're redirecting back to the login screen every time, try setting this in your .htaccess file in the root of your MODx install:

php_value session.auto_start 0

More common issues to come...

Still Having Issues?

If you're still having problems, post your error and your server environment information in , and we'll try and address your issue asour forums heresoon as possible.

Successful Installation, Now What Do I Do?

Creating the first pageCreating a Template

After a successful installation, you'll be presented with the Manager login page. Use the login and password you specified during the installation,log in. You will be presented with something like this

Page 22: ModX Revolution Docs 20101007

Since Revolution RC1 doesn't come with any default content, there aren't any pages, which is why this list of error messages. Therefore, the firstthing to do is create a page to make these errors go away.

Creating the first page

This being MODx, there are several ways to create a new resource (document). The main Site menu has a "New Document" menu item, the TreeView block on the left will have the first section, Web Resources, open (if it's not open, click on the Web Resources bar to open it) with its menubar so you can use the Create Resource button (the third from the left, the yellow folder with the green plus sign on it), or you can right-click onthe web context icon, choose Create, then Create a Document Here.

The New Document window will appear. On the right, taking up most of the page, will be the document's fields. To begin with, just give thedocument a title, Home, a Menu Title, First Document, and some content. Make sure to check the Published check box. Click on the floating Savebutton to save your new document.

And now, if you view the tree on the left, you'll see your new document listed. Go to the main Site menu, click the Preview menu item, and viewyour page in all its glory!

Creating a Template

Obviously, the page alone is missing something. We need to create a template to give it some structure and style. Click on the Tree View's'Elements' tab. This will open a selection of elements you can create and manage to add dynamic content to your page. Right-click on theTemplate element, and you'll see two choices for creating a new template, New Template and Quick Create Template.

The Quick Create Template opens a pop-up window to allow for quickly creating a template without moving from the page you're workingon.The New Template changes the right panel to a more complex form for creating a new template.

In either case, give the template a name, My Template, a description, First Revolution Template, and then the HTML code for the template. MODxtemplates are basically just HTML pages, with the content parts replaced with MODx tags. So to begin with, let's just create a really simpletemplate.

Page 23: ModX Revolution Docs 20101007

<!DOCTYPE html PUBLIC "-  //W3C//DTD XHTML 1.1//EN""http: >//www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"<html xmlns="http: xml:lang= >//www.w3.org/1999/xhtml" "en"<head>    <title>My First Revolutionary Page</title>    <meta http-equiv= content= />"Content-Type" "text/html; charset=utf-8"    <style type= media= >"text/css" "screen"        #content{width:80%;margin:auto;border:5px groove #a484ce;}        #content h1{color:#a484ce;padding:10px 20px;text-align:center;}        #content p{padding:20px;text-align:center;}    </style></head><body> <div id= >"content" [[*content]] </div></body></html>

Save the new template. Now if you open your first document for editing, you'll see that it's been assigned the template (since it's the only one, andthe document didn't have one). Go back to the site and refresh the page. And now, if you click the main Home menu, you'll get the Manager homepage without that long list of errors!

Using MODx Revolution from SVN

Installation ProcessSVN LocationsRun the BuildRun Setup

Upgrading After CommitsUsing MAMP on Mac OS X

Installation Process

Here are some notes on participating in MODx Revolution testing and/or development. Unlike previous versions of MODx, Revolution will notinstall directly from SVN. Because of the nature of the new packaging and installation system, you must first create the core installation packageusing a PHP build script before running the setup.

SVN Locations

Checkout or export the latest Revolution code from SVN at the URL:

http://svn.modxcms.com/svn/tattoo/tattoo/branches/2.0/ - Latest 2.0 devhttp://svn.modxcms.com/svn/tattoo/tattoo/branches/2.0-ui/ - For default mgr UI/design work

Run the Build

If this is the first time you are building from SVN, copy the file build.config.sample.php to build.config.php and edit the properties to point at a validdatabase with proper credentials. NOTE that this database does not have to contain anything; the build script just needs to be able to make aconnection to a MySQL database.

From the command line, change your working directory to _build/ and execute the command "php transport.core.php". If the PHP executable isnot in your path, you will need to either edit the path or give the full path to the PHP executable in the command line. The build process may takean extended period of time (10 to 30 seconds likely), so be patient. (Note: on Mac Mini (1.66Ghz Intel Core Duo with 2GB RAM) running theLeopard development environment as outlined below, this only takes 5-10 seconds.)

Note that you can also do this from the browser by browsing to the _build/transport.core.php directory, if that directory isaccessible in your web server setup.

Once that script is finished executing, confirm that you now have a file named core/packages/core.transport.zip and a directorycore/packages/core/ containing a manifest.php and many other files/directories.

Run Setup

Page 24: ModX Revolution Docs 20101007

Now you are ready to execute the new setup script at the setup/ URL (e.g. if installed in a subdirectory of the webhttp://localhost/modxrevo/setup/root named modxrevo/).

Make sure you check both the "Core package has been manually unpacked" and "Files are already in-place" options wheninstalling from SVN.

If you change any paths on the Context Paths setup step, make sure and move the corresponding directories as appropriate; this is intended forinstalls from the core package with files not already in-place, where the installer will place the files in the specified locations (assuming thelocations allow the PHP process to write to them).

The actual install process requires more than the default 8M of memory allocated to PHP in many default php.ini files; if you geta blank page when you click "install", try increasing the memory_limit configuration to 32M or more (16M may work, but why notgive php a little space, eh?).

Only the absolute required minimal data is included; there are no documents or add-ons installed by default, etc. as of this time.

Give it a try at your earliest convenience and record any issues or problems you encounter. There is a lot of work going on still, and plenty left togo, so expect the unexpected as we work through changes, fixes and refactorings.

See for recommended tools and setups for contributing directly to MODx core code.Development Environments

Upgrading After Commits

When a commit is made to an SVN branch, one of two messages might show up in the commit.

[REBUILD/UPGRADE REQUIRED] - If your updates require a core transport rebuild (such as anything modified in the _build directory,database model changes, or default data changes), then prefix your commit message with this. If you see this message, simply rebuildthe core transport and run setup/ again.

If neither of these messages show up, you simply need to svn update, and you're done.

Using MAMP on Mac OS X

If you use MAMP on Mac OS X, you may get problems (errors about DYLD libraries not being included) when trying to execute''transport.core.php'' from the terminal. This is because the MAMP PHP libraries won't be on the dynamic linker path by default.

To adjust the dynamic linker library path to include the MAMP PHP libraries, run the following command via the terminal:

export DYLD_LIBRARY_PATH=/Applications/MAMP/Library/lib:${DYLD_LIBRARY_PATH}

You can then execute ''transport.core.php'' by using the absolute path to the MAMP PHP executable:

/Applications/MAMP/bin/php5/bin/php transport.core.php

An Overview of MODx

What is MODx?

MODx is a Content Application Platform. What does this mean? Well, that depends on who you are:

End-Users (Average Joe)

MODx offers you a system that lets you publish your offline content onto the web in any form, shape or presence you want. It alsooffers a completely customizable backend interface that you can make as simple (or as complex) as you like.

You can setup everything from a simple site, to a blog, to a full-scale web presence with MODx, and keep your admin interface

Page 25: ModX Revolution Docs 20101007

simple and usable. Drag and drop your webpages around to reorder and move them. Get a full WYSIWYG view of your Resources.Leave Resources unpublished before you finish them. Schedule Resources to publish at certain times.

MODx helps you organize your content the way you want it, and get stellar built-in SEO results. MODx is fully, 100% Friendly URLcompatible, so getting mysite.com/my/own/custom/url.html is incredibly simple, and as easy as structuring your site that way.

Designers (Cool Carl)

Ever wanted complete freedom with your HTML and CSS? Tired of hacking existing systems to get your design towork the way you comp'ed it? MODx does not generate one single line of HTML - it leaves the front-end design upto you.

You can use MODx as your Content Management System (CMS) of choice, as MODx offers completely flexibletemplating and no-holds-barred content delivery. Put your CSS and images where you want them. And once you'redone designing, either hand off the development duties to your developer, or point-and-click install Extras straightfrom within the manager. Simple.

Developers (Badass Billy)

You've looked at different CMSes, but have found developing in them to be either a mishmash of too manyunconnected code pieces, or simply not powerful or elegant enough. You've looked at PHP frameworks, and havefound they have the power, but don't do Content Management nor have a good enough UI for your clients. Youwant the power and flexibility of a framework, with the UI and content management of a CMS.

Enter MODx Revolution. A completely flexible, powerful and robust API, built on OOP principles and using aPDO-powered Object Relational Model (ORM) called . Add in a rich, -powered UI for your clients,xPDO Senchathat's fully customizable. Custom properties and sets. Internationalization support. Package distribution built-in soyou can pack up your code, and distribute it across any Revolution install. Add custom manager pages to run entireapplications within MODx.

Basic Concepts

MODx, in essence, has a ton of moving parts. But the basics parts are:

Resources

Resources are basically a webpage location. It can be actual HTML content, or a file, forwarding link, or a symlink, or anything else.

Templates

Templates are the house a Resource lives in. They usually contain the footer and header for a page.

Template Variables

Template Variables (TVs) are custom fields for a Template that allow the user to assign dynamic values to a Resource. A great example would bea 'tags' TV that allows you to specify tags for a Resource. You can have an unlimited number of TVs per page.

Chunks

Chunks are simply small blocks of content, be it whatever you want inside it. They can contain , or any other Element type (Snippet,SnippetsChunk, TV, etc).

Snippets

Snippets are dynamic bits of PHP code that run when the page is loaded. They can do anything you can code, including building custom menus,grabbing custom data, tagging elements, processing forms, grabbing tweets, etc.

Plugins

Plugins are event hooks that run whenever an event is fired. They are usually used for extending the Revolution core to do something during apart of the loading process - such as stripping out bad words in content, adding dictionary links to words, managing redirects for old pages, etc.

So What Happens on a Request?

MODx loads the requested , fetches that Resource's , and then places the Resource's content in that Template. MODx thenResource Templateparses the resulting combined content, including any tags that might be in it, in the order they are reached. From there, it outputs the response tothe user's browser.

Page 26: ModX Revolution Docs 20101007

See Also

Glossary of Revolution Terms

Add-onAssetBack-endCategoryChunk TagsComponentContent ElementContent TypeContextContext SettingCore WorkspaceDocumentDocument IdentifierExtensionFile ResolverLanguage TagsLexiconLexicon Topic (formerly Foci)Link TagsManagerNamespacePlaceholder TagsResource FieldPropertyProperty SetResourceResource IdentifierResource TagsResolver (for xPDOVehicles)Setting TagsSnippet TagsStatic ResourceSymlinkSystem SettingTemplate VariablesTransport PackageTransport Provider (formerly Provisioner)Transport VehiclesUser SettingWeblinkValidator (for xPDOVehicles)xPDOVehicle

Add-on

A MODx Third-party Component (3PC) that does not modify the Core or extend any of its classes, but yet still provides extra functionality to theMODx instance.

Asset

Any type of file resource that is usually located in the /assets directory, as defined by the constant MODX_ASSETS_PATH; can includeThird-party Components, libraries, image files, css files, JavaScript files, class files, etc.

Back-end

A synonym for the MODx manager interface.

Page 27: ModX Revolution Docs 20101007

Category

An optional classifying name that can be attached to any Element or PropertySet (and other objects in later versions of Revolution) that separatesit from other similar objects.

Chunk Tags

Tags in the form [[$ChunkName]] that can be used in reference to Chunks.

Component

Also called "Third-party Component", or 3PC, a Component usually provides extra functionality to MODx, usually in the form of an Add-on, CoreExtension, or Template.

Content Element

Also called just "Element", a single Template, Template Variable, Chunk, Snippet, Plugin, Category, or Property Set visible in the ManagerElements tree.

Content Type

Sets the extension, mime-type and binary setting for any Resource.

Context

A delineator of resources and settings that can be used for a variety of reasons; usually used to create multiple-context sites, such assubdomains, multi-language sites, etc.

Context Setting

A single setting for that Context that either creates a new setting or overrides a System Setting.

Core Workspace

Each unique MODx Core is represented by a named Workspace. When you install Revolution initially, the MODx Core used by the setupapplication is recorded into the MODx database as the Default MODx Workspace. In future MODx Revolution releases, there will be an ability tomanage multiple Workspaces from a single database, directly from the manager application. This will make it easy to isolate upgrades to theMODx Core; by quickly adding a new Core Workspace and selecting a menu option, you'll be able to apply an entire new MODx Core installationto production sites after testing on a staging site, or quickly revert to a previous Core Workspace you know works. This will be especially importantfor multi-site configurations running on shared MODx Core installations.

Document

A specific type of Resource, usually pertaining to a normal website page.

Document Identifier

See Resource Identifier.

Extension

Also called "Core Extension". A MODx Third-party Component that modifies the MODx Core, such as a custom User or authentication class,caching mechanisms, or context manipulation classes.

File Resolver

Page 28: ModX Revolution Docs 20101007

A type of xPDOVehicle Resolver that copies files from the source location to the target location in a Transport Package.

Language Tags

Tags in the form [[%LanguageStringKey]] that reference MODx Lexicon entries.

Lexicon

A Lexicon is a dictionary of words and phrases organized by Culture (more specific than language, i.e. en-UK) that is used to internationalize themanager application and can be used by Add-On and Core Extension developers to provide localization facilities for their own components. Thisreplaces the legacy MODx language files and allows customization of the entries directly from the manager application.

Lexicon Topic (formerly Foci)

A set of Lexicon Entries focused on a particular subject. Revolution only loads Lexicon Entries as it needs them, by their Topic, to reduce loadtimes.

Link Tags

Tags in the form [[~ResourceId]] that reference the URL of a particular Resource.

Manager

The back-end of the MODx interface.

Namespace

An organizational tag for Components to use to identify Lexicon Entries, Settings, and other objects related to the Component in a Revolution site.Also specifies an absolute path in which the Component may be found.

Placeholder Tags

Tags in the form [[+PlaceholderName]] that reference MODx Placeholders, usually set with $modx->setPlaceholder('placeholderName','value') ina Snippet or Plugin.

Resource Field

Any of the fields of the site_content table, such as title, longtitle, introtext, alias, menuindex, etc. Some fields are available on the DocumentCreate/Edit screen and via Resource Tags; Others can only be accessed via the documentObject.

Property

A single variable for an Element; used to set a specific parameter for the Element.

Property Set

A collection of variables used for a particular purpose with an Element. Property Sets are attached to Elements and pass in the Properties thatthey carry as parameters to the Element. An example is a custom Property Set for a Snippet that passes in specific parameters to the Element,overriding the default behavior.

Resource

A type of container that is interpreted by the Parser to fetch content. Can have any number of derivative classes; the most common is aDocument.

Page 29: ModX Revolution Docs 20101007

Resource Identifier

Also called a Document ID, Resource ID, or Document Identifier; the number in parenthesis in the MODx Resource Tree in the Manager thatuniquely identifies the Resource specified.

Resource Tags

Tags in the form [[*ResourceField/TV]], which can be used to refer to Resource Fields, or Template Variables.

Resolver (for xPDOVehicles)

Post-processor: a script or predefined action that is evaluated after a Vehicle is installed or uninstalled. Resolvers always occur after the vehicle'sobject is save()'d, and can then perform actions on MODx before anything else happens in the install/uninstall process.

An example of a PHP Resolver is one that attaches Plugin Events to a newly-installed Plugin.

An example of a file Resolver is one that copies the assets/ditto directory in the xPDOVehicle path to /modx/assets/ditto.

Setting Tags

Tags in the form [[++SettingName]] that reference MODx System Settings, Context Settings, and User Settings.

Snippet Tags

Tags in the form [[SnippetName]], also referred to as Snippet Calls.

Static Resource

A specific type of Resource that is a direct reference to a specific file on the MODx site. The content is replaced with the contents of that file.

Symlink

A type of Resource that references a single, local MODx Resource; the Resource's content will replace the Symlink's content.

System Setting

A site-wide variable accessible to the MODx site. Can be overridden by Context Settings and User Settings.

Template Variables

Custom Resource Fields created by the user on the Document Create/Edit Screen and referenced using Content Tags.

Transport Package

A packaged and zipped collection of Transport Vehicles, that can be easily distributed ("transported") from one Core Workspace to another.

Transport Provider (formerly Provisioner)

A web service that enables remote installation of Transport Packages directly from the MODx manager application.

Transport Vehicles

An intelligent container that encapsulates any artifact that can be distributed in a Transport Package. Transport Vehicles store their payloads in a

Page 30: ModX Revolution Docs 20101007

portable format.

User Setting

A user-specific setting that either creates a new setting or overrides the similar Context Setting and System Setting. Used to provide uniquesettings to that user.

Weblink

A type of Resource that references a specific URL or MODx Resource, redirecting the visitor to that URL or Resource.

Validator (for xPDOVehicles)

Pre-processor: a script or predefined action that executes prior to the vehicle being installed or uninstalled. If the validator returns true, theinstall/uninstall action will proceed as normal. If the validator returns false, MODx will not uninstall or install the package.

A Validator could be used to determine if a directory exists and is writable, to see if other modx elements are already installed, or to determine if acertain version of MySQL and PHP are used on a server.

xPDOVehicle

The base Transport Vehicle class, xPDOVehicle, stores xPDOObject instances (which represent a row of data in a table) in it's payload, alongwith various attributes that control how the object is installed/uninstalled in a Core Workspace (see xPDOVehicle Validators and xPDOVehicleResolvers).

Explanation of Directory Structure

The root directory of MODx is split into several subdirectories, each with its own set of responsibilities and tasks. Some of these directories can berenamed and moved, and their locations can be configured during setup.

connectors/Notable Files

core/core/cache/

core/cache/logs/core/cache/mgr/core/cache/rss/core/cache/web/

core/components/core/config/core/docs/core/error/core/export/core/import/core/lexicon/core/model/

core/model/modx/core/model/modx/mysql/core/model/modx/processors/

core/model/schema/core/model/smarty/

core/packages/core/xpdo/Notable Files

manager/manager/assets/manager/assets/controllers/manager/assets/templates/Notable Files

setup/_build/

Notable Filesassets/

assets/components/

Page 31: ModX Revolution Docs 20101007

connectors/

Connectors are essentially entry points for AJAX requests in MODx. They don't do any database manipulation on their own; they simply load upthe main MODx class, sanitize any request data, and then handle the request by pointing to the appropriate Processor file.

For example, when we create a resource, we request connectors/resource/index.php?action=create. The index.php file will include the baseconnector file (connectors/index.php) which instantiates the main MODx object, handle any custom switching, and sanitize the GET orContextPOST request. The connectors/resource/index.php will then "handle" the request and call the correct Processor file, which we will discuss later.

Notable Files

connectors/index.php - This file is particularly useful in creating your own connectors. Simply include this file in your connectors, andthen handle the request using $modx->request->handleRequest();

core/

The Core is what makes MODx, MODx. It is the base for all the libraries for Revolution. Most everything you need, with the exception of themanager files and the setup files, are in this directory.

core/cache/

The cache directory contains all of the cache files generated by MODx. Lexicons, elements, resources, RSS, and Smarty data are generatedon-demand by MODx, meaning that they are only cached after being accessed for the first time.

core/cache/logs/

All file logging in MODx is done here. You will find the error.log file here, which contains the date, time, file, and error which was logged by MODx.

To log an entry to this file, you can use the $modx->log() method.

core/cache/mgr/

This directory contains cache data for the mgr (Manager) context. Like every context cache, it will cache any context settings that have beenoverridden from their default System Settings.

core/cache/rss/

A cache of every RSS feed in MODx.

core/cache/web/

Unlike the cache in MODx Evolution, the MODx Revolution cache is split up into several parts. Every context (ie. web and mgr) has acontext.cache.php file. This file is like the config.cache.php file, except that it only caches settings that have been overridden from their defaultSystem Setting. Any context can override a system setting.

Additionally, the web context cache will contain separate directories for resources and elements. A resource with ID 12 will be found atcache/web/resources/12.cache.php. This new caching mechanism means that loading times will decrease, and the limit on the number ofcacheable resources will disappear.

core/components/

When you install a package using the , a core/components/<component_name>/ directory will be created to hold any filesPackage Managernecessary for the installed component to run. Typically, any files needed to run in the Manager, such as controllers, model/schema data,processors and class files, should be stored here, as well as files you don't want web-accessible.

core/config/

This directory contains the configuration file for MODx Revolution. It sets up database credentials and a number of MODX_ constants for theproper operation of your site.

core/docs/

This directory contains the changelog.txt file, the GPL license, and any tutorials that have been created for Revolution.

core/error/

This contains default templating for error response messages in Revolution's front-end. You can customize those pages here.

core/export/

Page 32: ModX Revolution Docs 20101007

1.

2.

After running the Export function in MODx Revolution, the exported HTML files for your site will be located here.

core/import/

To run the Import function in MODx Revolution, you need to move your HTML files into this directory.

core/lexicon/

Lexicons in Revolution are different from language files in Evolution for two main reasons.

First, in Revolution, lexicon files are split up into separate directories, depending on their two-digit IANA code (for example, English lexicons arestored in /core/lexicon/en/). Inside these subdirectories are multiple files, in the format "topic.inc.php". A "topic" is simply a single lexicon file.Splitting lexicons into topics means that only the language strings are loaded, saving memory and loading time.required

Second, all lexicons are stored in the MODx database, and later cached on-demand. This makes it possible to manage lexicons directly from theManager, inside the Lexicon Management area.

To load a lexicon, one would use a format such as this:

$modx->lexicon->load( 'lang:namespace:topic' );

# - the 2-digit IANA code. This is optional, and defaults to 'en'.lang

namespace - Each lexicon has its own . The built-in namespace for MODx is "core". Package creators will also be able toNamespacecreate a custom namespace, and Manager users can also create their own namespaces as well.topic - The specific topic/file you want to load.

core/model/

This is the model. What's a model, you say? Well, it's the M in MVC (model-view-controller), which is an OO paradigm that states that thereshould be at least three parts to an application. The Model, which contains the structure of the database and the hooks into it; the View, which isthe GUI part of the application that contains no logic - just presentation; and the Controllers, which connect the model to the view.

So, MODx does model sort-of similar. We actually do a MVC/C model, in which we add a Connector access point and Processors to the model.We'll explain those as we come to them. What you need to know is that the model contains all the PHP classes that run Revolution, including theprocessors that handle specific functions - such as saving snippets, removing chunks, etc.

core/model/modx/

"Wait! I thought we were already in a modx dir? Why another modx subdirectory?" Good question. Well, MODx Revolution uses xPDO for itsdatabase management. xPDO uses the idea of 'packages' for different connections to different models. So, if I wanted to create my customtables, I'd create a new xPDO package, and add it in at runtime. This way I could use the maps and classes created without having to modify theMODx core. This is shown in the tutorial.Creating a 3rd Party Component

So, that said, it can be inferred that the core/model/modx directory is referring to the "modx" package. Let's go inside it, and you'll see a ton ofclasses. These are the classes that are either xPDOObjects - which are PHP classes that represent tables in the DB (ie, modsnippet.class.php isa PHP class that is an object of modx_site_snippets), or they are functional classes, such as modcachemanager.class.php.

The subdirectories in this folder - not including mysql or processors - are subcategories of classes, that are loaded like:$modx->loadClass('transport.modPackageBuilder'); with the "." being the separation of directories.

core/model/modx/mysql/

This directory contains the class and map files for each xPDO object. Maps are simply PHP arrays containing the structure of the database tablethey reference.

Other database platforms such as pgsql, mssql, and others would also appear here.

core/model/modx/processors/

This directory contains the individual processor files used in database manipulation. They are never accessed directly, and instead are accessedthrough connectors. This allows you to lock them down to prevent unauthorized access.

core/model/schema/

The schema is the XML representation of the MODx database. This is used in building new maps and classes, but is never actually read orparsed when MODx is running. For the most part, you can ignore this directory, as it is mainly used for development work. The tutorials on

teach more about schemas.creating 3rd party components

core/model/smarty/

Page 33: ModX Revolution Docs 20101007

This contains the Smarty libraries. It's simply an extraction of the Smarty files you can get from . Nothing in this folder ishttp://smarty.php.netcustomized for MODx - that happens elsewhere.

Smarty is an intelligent, object-oriented templating engine that uses dynamic, modifiable placeholders. Most pages seen in the Manager andduring Setup are Smarty template (.tpl) files that MODx interacts with.

When you edit a resource (often a document) in the Manager, for example, you're looking at a page generated by the controller atmanager/controllers/resource/staticresource/update.php. After setting the characteristics of the resource in the $resource array, this code rendersthe page:

$modx->smarty->assign('resource',$resource); $modx->smarty->fetch('resource/staticresource/update.tpl');return

The Smarty placeholders in update.tpl are filled in with the data held in the $resource array.

core/packages/

Here you will find any transport packages you've downloaded via the section of Revolution, such as TinyMCE, Ditto, etc.Package ManagementThe core package is also found here as well. This allows for easy installation and removal, as well as remote updating of installed packages.

When you build a package (for example, after checking out from SVN), the transport package will be stored here.

core/xpdo/

MODx Revolution was designed to use OpenExpedio (xPDO), an extension to PDO. It provides a uniform interface for manipulating databases,and makes it possible for MODx to support various database platforms besides MySQL.

This directory contains all of the class files needed by xPDO to do everything from query caching, to building transport packages and outputtingdata as a convenient JSON object.

These classes are used by MODx internally, and developers should never need to deal with them directly.

Notable Files

core/cache/config.cache.php - This is the cache file for all of the in MODx. Their database equivalents are found in theSystem Settings_system_settings table, and their xPDO equivalents are modSystemSetting objects.

Tip - If you ever get locked out by the CAPTCHA component, you can edit this file and set to '0' to disableuse_captchaCAPTCHA. Then you can log in and disable CAPTCHA in .System Settings

core/cache/sitePublishing.idx.php - In MODx Evolution, this file contained the cache data for all documents, chunks, and snippets. InRevolution, this is no longer the case, and this file now keeps track of cache refresh intervals.core/cache/mgr/actions.cache.php - a map of all modAction objects.

manager/

The Manager is the MODx backend or administration area for creating resources, managing users, and performing overall site maintenancetasks.

manager/assets/

This directory contains the libraries, as well as the custom ModExt implementation. ModExt extends the original ExtJS library, to makeExtJSdevelopment more convenient for users.

manager/assets/controllers/

Controllers are the PHP files tied to modActions. They simply fetch data and return or output it to the browser for rendering and display. Wheneveryou load a page in the Manager, you are in effect telling MODx to load a particular Controller, which simply loads a Smarty template and outputsany necessary JavaScript to the browser.

manager/assets/templates/

This directory contains the template files for each manager page. They do not contain PHP code, but rather are used to organize HTML. If you arelooking for the Smarty .tpl file for a particular manager page, check in the manager/templates/default/ directory.

Notable Files

manager/assets/ext2/ext-all.js - This is the main Ext library file, which must be included on all Manager pages (or any page using Ext).It's compressed to save space, decrease download time, and speed up page loads. However, if you're doing a lot of JavaScript work,you're bound to run into some cryptic errors because of the compression. The best way to deal with this is to simply rename this file, and

Page 34: ModX Revolution Docs 20101007

then rename the ext-all.js file to ext-all-debug.js to use the uncompressed version during development. Just be sure to switch them backafterwards!

setup/

This directory is the equivalent of the "install" directory in MODx Evolution. It contains the necessary files needed to run Setup and perform a or an .Fresh Installation Upgrade

_build/

This directory is only present in version of MODx Revolution downloaded from the subversion server (as well as the "SDK" distribution). Itcontains the packaged MODx core data files necessary to install MODx to a database.

Notable Files

_build/transport.core.php - This file must be executed after downloading MODx Revolution, and prior to running Setup. Aftercompletion, you should notice a "core" directory inside your core/packages/ directory, which will contain all of the necessary Vehicles forinstalling MODx Revolution.

assets/

This directory is not present in MODx Revolution by default, but like in MODx Evolution, it is common to place images, CSS, JavaScript, and othermedia in here.

assets/components/

When you install a package using the , an assets/components/<component_name>/ directory will be created to hold anyPackage Managernecessary component files, such as JavaScript or images.

Roadmap

This is a work-in-progress roadmap for MODx Revolution.

Tasks in are already finished in Git.purple

Revolution 2.0

After PL release, the core team will concentrate on creating distributions for different 2.0.0-pl implementations. Migration of the Revolutioncodebase to Git will also occur at this time.

Revolution 2.0.1

Fix any major issues in JIRA

Revolution 2.1

Add Custom DashboardsSimplify setup/ processMore API methods

Revolution 2.2

Transport Package dependenciesAdd Static ElementsAdd Heirarchical Elements

Revolution 2.3

Permissions/ACLs for specific UsersUser Group Settings

Revolution 3.0

Page 35: ModX Revolution Docs 20101007

Add native VersioningAdd Content Element supportAdd Workflow supportRedo manager into an actual 'mgr' context where pages are modx resources

See Also

Making Sites with MODx

This section contains information on creating your site using MODx.

Structuring Your Site

This section contains information about MODx objects that are used in the structure of your website.

Resources

What is a Resource?Managing Resources

Resource FieldsGeneral Resource FieldsSettings Resource FieldsUsing Resource FieldsAccessing Resource Fields in a Snippet

Linking to a ResourceURL Parameters for Resource TagsURL Schemes in Resource Tags

See Also

What is a Resource?

A resource is a representation of a page in MODx. There are different types of Resources, such as documents, weblinks, symlinks, actual files, ormany other things. The default Resource type is a Document, and simply represents a webpage on your site.

There are 4 total types of Resources, and they are Documents, , , and .Weblinks Symlinks Static Resources

Each Resource also has a unique ID, or "Resource Identifier". This lets MODx know what Resource to fetch when you are loading a webpage.Also, when you're wanting to link between Rsources, you will use this ID to do so, which allows MODx to not have to worry about the resultingURL. You can move, rename, alter or even change the type of a Resource, and the ID will stay the same - meaning that any changes you maketo the Resource wont affect your links to it.

Managing Resources

Resources are shown in the Resources tree in the left-hand navigation of the manager. To edit one, simply click on the page you would like toedit. You can alternatively right-click the Resource and click 'Edit Resource'. This will load the Resource Edit page:

Page 36: ModX Revolution Docs 20101007

The content of the Resource can then be edited in the large content field in the bottom area. Other fields related to each Resource can also beedited via the tabs on the top of the page.

Resource Fields

Resources come packaged with a list of predetermined fields by default. They are:

General Resource Fields

Name Description

id The ID of the Resource.

template A reference to the that this Resource is usingTemplate

published If the Resource is Published, or viewable on the front-end.

pagetitle The title of the Resource.

longtitle A longer title of the Resource.

description An extended description of the Resource.

introtext Also called 'Summary', an introductory excerpt of the Resource's content. Useful for blogs or searching.

alias The URL alias to use, if your site is using Friendly URLs. A Resource with alias 'home' and Content Type 'html' would render'home.html' if it isn't a Container.

parent The Parent Resource's ID.

menutitle The title to show for the Resource when displayed in a menu.

menuindex The order index of the Resource in a menu. Higher order means later.

hidemenu Also called 'Hide from Menus', if set, this Resource will not show in most Menu or Navigation snippets.

content The actual content of the Resource.

Settings Resource Fields

Name Description

isfolder Labeled as 'Container', this specifies whether or not the Resource renders with a / in Friendly URLs instead of its suffix.

searchable If the Resource is searchable.

cacheable If the Resource is cacheable.

createdby The ID of the user who created the Resource.

editedby The ID of the last user to edit the Resource.

deleted If the Resource is deleted or not.

deletedby The ID of the user who deleted the Resource.

publishedby The ID of the user who last published the Resource.

createdon The date the Resource was created.

Page 37: ModX Revolution Docs 20101007

publishedon The date the Resource was published.

editedon The date the Resource was last edited.

Using Resource Fields

Resource fields can be accessed from anywhere by using the syntax, ie:Template Variable

[[*pagetitle]] // renders the pagetitle.[[*id]] // renders the Resource's ID[[*createdby]] // renders the ID of the user who created Resourcethis

They can also have applied to them:Output Filters

// Renders a limited version of the introtext field. // If it is longer than 100 chars, adds an ...[[*introtext:ellipsis=`100`]]

// Grabs the user who last edited the Resource's username[[*editedby:userinfo=`username`]]

// Grabs the user who published the Resource's email[[*publishedby:userinfo=`email`]]

Accessing Resource Fields in a Snippet

Grabbing the Resource Fields in a is quite easy; MODx provides you with the Resource object in any Snippet, via the $modx->resourceSnippetreference. For example, this example Snippet will return the current page's pagetitle reversed:

/* output the current Resource's pagetitle */$output = $modx->resource->get('pagetitle');

strrev($output);return

Linking to a Resource

In MODx, links to Resources are dynamically managed via "Resource Tags". They look like this:

[[~123]]

where '123' is the ID of the Resource to link to. You can put these tags anywhere, and MODx will dynamically render the URL for the Resource.

You can also get the Resource Tag by dragging a Resource from the left tree into the content panel.

Also see .Named Anchor

URL Parameters for Resource Tags

Adding URL parameters in your Resource Tag is quite simple in Revolution. Let's say we have Resource ID 42 that resolves to a URL of'store/items.html'. We want to add a 'tag' parameter to the URL, with a value of 'Snacks' and a 'sort' parameter of 'Taste'. Here's how you'd do it:

[[~42? &tag=`Snacks` &sort=`Taste`]]

This would render as:

store/items.html?tag=Snacks&sort=Taste

Note that those are instead of apostrophes.backticks

URL Schemes in Resource Tags

Page 38: ModX Revolution Docs 20101007

You can specify the scheme for a Resource in your tag:

[[~123? &scheme=`https`]]

Would render the URL using 'https' instead of the normal http.

The available schemes are:

Name Description

https Renders the link with https instead of http

full Renders the link as an absolute URL

See Also

Content Types

What are Content Types?Usage

Creating New Content TypesSee Also

What are Content Types?

Content types are specific filesystem types for your resources. They are associated with file extensions and tell the MODx Parser what type ofextension to render the page with.

For example, a with an alias of 'test' and Content Type "CSS" that has a file extension of ".css" will render as:Resources

test.css

instead of test.html. This allows you to create any type of file from .Resources

Usage

When editing a Resource, simply select the Content Type that you'd like to use:

Then save the . This will automatically associate that with the selected Content Type.Resources Resources

Creating New Content Types

First, go to System -> Content Types. You'll see a grid populated with all the current Content Types. Click on 'New Content Type', and a windowwill appear:

Page 39: ModX Revolution Docs 20101007

The fields that appear are as follows:

Name - This is the name of the Content Type. It is mainly for organizational and labeling purposes, and does not affect the function of thetype.MIME Type - Here you can set the MIME Type for the extension, which will tell the browser what type of file the is. A list ofResourcesavailable MIME Types can be found or .here hereFile Extensions - This is the file extension to render the Resource as.Binary - Is the file type text/ascii or binary?Description - An optional field for your own descriptive purposes.

From there, click "save" and the Content Type will appear in the grid.

See Also

Resources

Named Anchor

What is a Named Anchor?

A named anchor is a link to content within the current resource.

A typical named anchor will be similar to:

<a name="prohibited"></a>

Accessing the Named Anchor

To generate a link to the current Resource, while using a named anchor of "prohibited":

<a href= >Prohibited Activities</a>"[[~[[*id]]]]#prohibited"

To generate a link to a Resource with ID 12, while using a named anchor of "prohibited":

<a href= >Prohibited Activities</a>"[[~12]]#prohibited"

Static Resource

What is a Static Resource?

A Static Resource is a Resource abstraction of an actual file on the filesystem. You can point a Static Resource to any file on your webserver; this

Page 40: ModX Revolution Docs 20101007

allows you to manage these Resources externally.

Static Resources can also have tags inside their content fields to determine the path of the file - so you can specify custom paths to set as SystemSettings, or use to dynamically find the path.Snippets

They behave exactly like a Document (standard Resource). Content within a Static Resource is parsed and displayed in the exact same way as aDocument.

See Also

Symlink

What is a Symlink?

Symlinks are similar to in that they redirect to another or URL; however, symlinks will persist the current URL.Weblinks Resources

See Also

Using Resource Symlinks

Understanding a Symlink

A MODx Revolution symlink simply takes the content of one resource and displays it in another.  You can add a new template or what everchanges you may want to the symlink, and you can place it anywhere within the site,  but you can not add additional content to it.

How do I use this feature?

1) Create the symlink with a name, an alias and a reference to the "master" document itself. 2) If you do not see it -- try clearing the site cache / document cache.

Example:

Page 41: ModX Revolution Docs 20101007

For my site this example would feed the contents of my college degrees page to the me.html

Why Symlink?

A document needs moved in the structure and google has it listed at the old locationA document may actually and logically belong in more than one place in a siteYou quickly and simply want to provide a short and simple url to a document located many levels deep in a siteYou want to deal with various spellings of a document: foursquare, 4square, forsquare and have them all point to the same content (eachof these would be a separate symlink)Most web site host control panels allow for subdomains.  By creating a subdomain in the control panel and then a symlink in the root ofthe website to content burried further down, you could create a "doorway" page or a fast means to getting to a group of related content.

Weblink

What is a Weblink?

A weblink is a document of type "reference". It has no template. It simply serves as a link that will be part of a generated menu.

The content of the weblink is just an URL. The parser doesn't even parse it; as soon as it sees that it is a "reference", it just uses the content asthe argument for sendRedirect($url).

You can use an external URL for the content, or you can use a Resource ID to link to a Resource in your MODx Resource tree.

Example

Say you want a footer menu with links to a Terms of Use, a Privacy Policy, and others. But you also want a link to "Contact Us" there. Contact Usis one of your main pages, and is in the top-level of your tree to be displayed in your main menu. You would put those Resources in one "utility

Page 42: ModX Revolution Docs 20101007

pages" folder, probably unpublished so it won't show up in your main menu, and use that folder ID as the Resource ID for the menu snippet. Inthat folder you would also put a Weblink to your site's contact page. This way the menu will include a link to the contact page, even though thatResource is not in the folder.

Or, you could do it the other way around, have the Contact Us Resource in your unpublished "utility pages" folder, and put the Weblink to it in yourtop-level so it will show in the main menu.

Originally a menu snippet would make the link to the Weblink itself, just as to any other MODx resource, thus causing the page to be loaded bythe parser, triggering the redirect.

The parser will detect that the Weblink's content is a number, and run it through makeUrl($id) before redirecting.

See Also

Templates

What are Templates?

Templates typically contain the HTML markup tags that determine the layout and appearance of your site. When a document is requested, MODxloads the document and its template, and MODx finds all the special placeholders in the template and replaces them with the correspondingvalues from the document before sending the finished page off to the user's browser.

Think of a Template like a house. Your content, then, is a person. A person can live in many different houses, but only one house.Resource's

A can only be using one Template - however, it can switch Templates at any time, just as a person can move from house to house atResourcesany time. The Template, just like a house, also changes the main way a page is displayed. A Template usually contains the header and footer of apage - and/or a sidebar, navigation bar, etc.

Usage

To create a Template -- Expand the "Elements" part of the tree and right click on Templates. Select "Create a New Template" then paste yourHTML into the "Template Code" textarea; you can copy and paste the text below to get started with a very simple template:

<html><head> <title>[[*pagetitle]]</title> <meta name= content= />"description" "[[*description]]"</head><body><h1>[[*longtitle]]</h1>

Page ID: [[*id]]<br/>IntroText (Summary): [[*introtext]]<br/>MenuTitle: [[*menutitle]]

<hr/>

[[*content]]

</body></html>

Page 43: ModX Revolution Docs 20101007

Note the important [[*content]] tag; this tag tells MODx where to put the Resource's content.

MODx stores template data in its database; you cannot create a template by uploading a file to the filesystem, you createmusta template using the manager.

Remember that simply a template doesn't mean that it is automatically put to use: you have to edit each and specify whichcreating ResourcesTemplate it uses. This is different from some content management systems where each template has one or many pages. Each MODx page hasa single Template that it uses to format output.

After you've created one or more Templates, you can edit any Resource and choose a Template for it by selecting one from the "Uses Template"drop-down list.

Templates can contain any tags, including , , , and others.Template Variables Chunks Snippets

Using Resource Fields in the Template

As you noticed from our Template sample code above, the fields of a Resource can be referenced using the [[*fieldName]] syntax. A list ofavailable Resource Fields can be . For example, if we wanted to show the current Resource's pagetitle in our <title> tag, we wouldfound heresimply do this:

<title>[[*pagetitle]]</title>

You can also place the content of the current Resource using the "content" tag:

<body>[[*content]]</body>

These tags are like normal MODx tags, in that they can have applied to them. For example, say we wanted to display the "introtext"output filtersfield on a right navbar, but strip any HTML tags from it, and only display the first 400 characters - and if longer, add an ellipsis (...):

<div id= >"rightbar"[[*introtext:stripTags:ellipsis=`400`]]</div>

Template Variables in Templates

If Templates are like a house, think of (TVs) like rooms in that house. You can have an infinite number of TVs in a Template;Template Variablesjust think of it like adding new rooms to the house.

Template Variables allow you to have custom fields for any Resource with the specified Template. Say you want a 'photo' field on your Resourcesin your "BiographyPages" Template. Simple - just create a TV, call it "bioPhoto", give it an input and output type of "image", and assign it to your"BiographyPages" Template. You'll then see the TV in any Resource that's using that Template.

You can then reference your "bioPhoto" TV in your content with the same tag syntax as a Resource Field:

<div class= >"photo"[[*bioPhoto]]</div>

Again, it's important to note that must be explicitly assigned to the Template to be used. Once assigned to the Template, aTemplate VariablesTV's value for that Resource will be able to be edited when editing the Resource. If you're not seeing a newly created TV in your Resources,make sure you've assigned that TV to the Template.

See Also

Tag SyntaxTemplate Variables

Chunks

Page 44: ModX Revolution Docs 20101007

CreateUsageProcessing Chunk via the API

Modifying a Chunk Via the APISee Also

Chunks are bits of static text which you can reuse across your site, similar in function to include files or "blocks" in other content managementsystems. Common examples of Chunks might be your contact information or a copyright notice. Although Chunks cannot contain any logicdirectly, they can however contain calls to , which are executable bits of PHP code which produce dynamic output.Snippets

Create

Before you can use a Chunk, you must first create and name one by pasting text into the MODx manager (Elements --> Chunks --> New Chunk):

Usage

To use the Chunk, you reference it by name in your templates or in your page content.

[[$chunkName]]

That reference is then replaced with the contents of the Chunk.

You can also pass properties to a Chunk. Say you had a chunk named 'intro' with the contents:

Hello, [[+name]]. You have [[+messageCount]] messages.

You could fill those values with:

[[$intro? &name=`George` &messageCount=`12`]]

Which would output:

Hello, George. You have 12 messages.

You could even take it one step further, by adding a that allows the user to specify their name per Resource:Template Variable

[[!$intro? &name=`[[*usersName]]` &messageCount=`[[*messageCount]]`]]

or in the Chunk itself:

Hello, [[*usersName]]. You have [[*messageCount]] messages.

Page 45: ModX Revolution Docs 20101007

Processing Chunk via the API

Chunks are also frequently used to format the output of Snippets. A Chunk can be processed from a Snippet using the process() function; forexample, given the following Chunk named 'rowTpl':

<tr class= id= >"[[+rowCls]]" "row[[+id]]"<td>[[+pagetitle]]</td><td>[[+introtext]]</td></tr>

the following Snippet code retrieves it and processes it with an array of properties for all published Resources, and returns formatted results as atable, setting the class to "alt" if for even rows:

$resources = $modx->getCollection('modResource',array('published' => ));true$i = 0;$output = '';foreach ($resources as $resource) { $properties = $resource->toArray(); $properties['rowCls'] = $i % 2 ? '' : 'alt';

$output .= $modx->getChunk('rowTpl',$properties); $i++;}

'<table><tbody>'.$output.'</tbody></table>';return

Modifying a Chunk Via the API

Chunks can also be manipulated by the MODx API:

<?php/* create a chunk, give it some content and save it to the database */new$chunk = $modx->newObject('modChunk');$chunk->set('name','NewChunkName');$chunk->setContent('<p>This is my chunk!</p>');new$chunk->save();

/* get an existing chunk, modify the content and save changes to the database */$chunk = $modx->getObject('modChunk', array('name' => 'MyExistingChunk'));

($chunk) {if $chunk->setContent('<p>This is my existing chunks content!</p>');new $chunk->save();}

/* get an existing chunk and delete it from the database */$chunk = $modx->getObject('modChunk', array('name' => 'MyObsoleteChunk'));

($chunk) $chunk->remove();if?>

See Also

modChunk

Using Snippets

Using a SnippetSnippet PropertiesInstalling SnippetsSee Also

Snippets are MODx's answer to inline PHP code. They provide customizable dynamic content, such as menus, blog or news listings, search andother form-based functionality and anything else that your site needs to generate on-demand.

Page 46: ModX Revolution Docs 20101007

Using a Snippet

Once you have a Snippet installed, you can use it simply by putting its tags in your template, a chunk or TV, or a document's content whereveryou want the Snippet's output to be displayed.

[[MySnippet]]

If you expect the snippet code to be dynamic for different users, you can also call a snippet uncached:

[[!MySnippet]]

Snippet Properties

Snippets can have , which can be passed in the Snippet call, like so:Properties

[[!Wayfinder? &startId=`0` &level=`1`]]

You can also aggregate these Properties into a , which is a dynamic collection of properties that can be attached to any Snippet (orProperty SetElement for that matter). This allows you to share common property configs in a snippet call in one place.

Say you had a Property Set called 'Menu' with `startId` set to 0 and `level` set to 1:

[[!Wayfinder@Menu]]

would then load those properties automatically into the Snippet. And even those properties can be overridden:

[[!Wayfinder@Menu? &level=`2`]]

which would override the set's value on `level` of 1, setting it instead to 2.

Installing Snippets

You can also download and install Snippets via . See the tutorial on for more information.Package Management installing a Package

See Also

Installing a Package

Tag Syntax

To simplify parsing logic, improve parsing performance and avoid confusion with many new adopters, all tags are now of a single format,differentiated by a token or a set of tokens which appear before a string which identifies the Content Element or Content Tag to be processed; e.g.[[ ]].tokenIdentifier

Tag Format Changes for Content Elements and Content Tags

Content Elements Evolution (Old) Revolution (New)

Templates no tag representation no tag representation

Template Variables [* *]templatevar [[* ]]templatevar

Chunks {{ }} chunk [[$ ]]chunk

Snippets [[ ]]snippet [[ ]]snippet

Plugins no tag representation no tag representation

Modules no tag representation does not exist in Revolution

Page 47: ModX Revolution Docs 20101007

Content Tags    

Placeholders [+ +] placeholder [[+ ]]placeholder

Links [~ ~]link [[~ ]]link

System Settings [( )]system_setting [[++ ]]system_setting

Language no tag representation [[% ]]language_string_key

Adopting this simplified format allows the new parser to be fully-recursive, following a source-order mechanism that does not depend on regularexpressions.

Previously, each tag set was parsed independently in a specific order, one level at a time, with any embedded tags delayed until the next pass. Now tags are parsed as they are encountered regardless of the element types they represent, and embedded tags are parsed before the outertag to allow much more complex tags to be composed.  Combined with the ability to use the previously reserved ? & and = symbols in tag strings(when escaped by the infamous backtick, e.g. ), MODx Content Tags offer a powerful new set of&param=`?=&is ok now, wow!?&=`capabilities for mashing up your content.

Caching

In Evolution, Snippets that need to be processed with each request should be on an uncached page or the Snippet itself should be calleduncached: [[!snippet]]

In Revolution, any tag can be called uncached by inserting an exclamation point immediately after the double-bracket:[[!snippet]], [[!$chunk]], [[!+placeholder]], [[!*template_var]], etc. 

Properties

All tags - no longer just Snippets - now accept properties, as well, that can be used. For example, let's say we had a Chunk named 'Hello' with thecontent:

Hello [[+name]]!

You'll note the new placeholder syntax. So, we'll definitely want to parse that Chunk's property. In 096, this was required to be done with aSnippet; no longer. You can simply pass a property for the Chunk:

[[$Hello?name=`George`]]

This would output:

Hello George!

The syntax for properties follows the same syntax as 096/Evolution snippet properties.

Customizing Content

MODx offers many ways of customizing content. This section covers the ways to do so that are built into the core of MODx.

Template Variables

What is a Template Variable?UsageSee Also

Page 48: ModX Revolution Docs 20101007

What is a Template Variable?

A Template Variable (TV) is a custom Resource Field that is created by the site developer. Imagine that you represent the pages on your site viaan Excel spreadsheet: each property is a column on that spreadsheet, and each page is a row. By default there are a specified number ofproperties or columns for each page (e.g. page title, content, alias). Template Variables allow for you to extend the attributes based on yourcontent, for example a page about books might require additional attributes for "author" or "publisher".

A TV is used to represent a value inside a Resource. MODx allows you to have a virtually unlimited number of TVs.

When a is displayed on the web, TV tags are replaced with the actual value entered by the user. TVs are -specific, meaningResources Templatethey can only be used in that they are assigned to.Templates

Template Variable Output Renders make it easier for users to add special visual effects to their web sites in a matter of seconds. With just a fewclicks you can add an Image, URL or custom render to your website.

Usage

Let's say we have a TV named 'bioPhoto', that is an Image TV we created. We've assigned it to our 'Biography Pages' Template, and want toshow it on our page. To do so, we'd simply place this tag anywhere we want:

[[*bioPhoto]]

TVs can also have Properties. Say you had a TV called 'intromsg' with the value:

Hello [[+name]], you have [[+messageCount]] messages.

You could fill the data with the call:

[[*intromsg?name=`George` &messageCount=`123`]]

Which would output:

Hello George, you have 123 messages.

Output Filters are also great tools to be applied to TVs. Say you wanted to limit a TV's output to 100 chars. You'd simply use the 'limit' output filter:

[[*bioMessage:limit=`100`]]

See Also

Creating a Template Variable

General SettingsRendering Options (Input Type)PropertiesTemplate and Resource Group AccessSee Also

This page outlines how to create a Template Variable in MODx Revolution.

General Settings

First off, you'll want to specify a name for the Template Variable. TVs in MODx are case-sensitive, so you'll want to be careful about the name youchoose. You can also specify a caption and description.

Page 49: ModX Revolution Docs 20101007

Rendering Options (Input Type)

From there, you can select all kinds of rendering options for the TV. First off, you'll want to select an input type:

Page 50: ModX Revolution Docs 20101007

These determine how the input form is rendered for the TV in the MODx manager interface. For this example, we'll choose "Date". Should wehave chosen a list, or dropdown, we can specify the Input Option Values in the following format:

option1==value1||option2==value2||option3==value3

We can then also specify a default value for the TV as well.

Next, we'll select the output rendering options. We'll select 'Date' as well, and as you'll note, below this box (depending on the Output Renderselected) some form fields will show:

Allowing us to edit more fine-grained options for that Output Render.

Properties

From there, we can specify any default properties we want for the TV. "How can you use properties on a TV?", you might ask. Well, let's say we'redoing a textarea TV named "viewingSS". In our content, we've got this:

Viewing: [[+subsection]]

We can add a list property 'subsection' to the grid, and then allow that property to be overridden via property sets. Say we created a Property Setnamed 'CarsSectionTVPS' (PS for Property Set). In it, we set the 'subsection' property to "Cars". We'd then attach it to the TV in our Resource, orTemplate, or whereever we are using it like so:

[[*viewingSS@CarsSectionTVPS]]

This would output in the place of the TV:

Viewing: Cars

Template and Resource Group Access

We can assign TVs to , as well. This allows those Resources assigned to those to edit the TVs for each Resource.Templates Templates

Also, TVs can be restricted to certain Resource Groups, selectable in the grid labeled "Access Permissions".

See Also

Bindings

What are Bindings?@

In the context to Template Variables, a Data Source is the location of the information to be displayed. A Data source can come from any of thefollowing sources:

an externally generated file that is sent via FTP to the servera Database table accessible to MODxa in the resource treeResourcesa in the Elements treeChunkthe result of an evaluated PHP script

These Data Sources can be tied (or "bound") to a Template Variable for formatting and displaying in document. In addition, the bound data in theTVs can be almost effortlessly formatted via the Display Controls within the TV system for some truly stunning results. The format for using thetypes of data source bindings available to all template variables follows:

Page 51: ModX Revolution Docs 20101007

@FILE file_path@RESOURCE resource_id@CHUNK chunk_name@SELECT sql_query@EVAL php_code@DIRECTORY path_relative_to_base_path

These "@" commands or bindings will allow you to quickly and easily attach your template variables to virtually any database system available.

The value returned from the data source can either be a string value (including numbers, dates, etc), an array or a recordset. The value returnedis dependent on the type of binding used. Some display controls will attempt to either convert the returned value into a string or an array.

For example, controls that accept string values such as a radio button group or select list will attempt to convert a record set (rows and columns)into the following format:

col1row1Value==col2row1Value||col1row2Value==col2row2Value,...

Please note that @ bindings will work only when used inside "Input Option Values" or "Default Value" fields.

When placing @ bindings inside the "Input Option Values" field, they are used to format input options only when editing document within theManager, for example to create a drop-down list of Cities or Countries.

When placing @ bindings inside the "Default Value" field the returned value is used to render to the final web page. This makes it simple to buildcomplex forms for data input on the web very quickly.

Types

@FILE@RESOURCE@CHUNK@SELECT@EVAL@DIRECTORY@INHERIT

See Also

Template Variables

CHUNK Binding

What is the @CHUNK Binding?

The @CHUNK Binding returns the parsed content of any specified Chunk.

Syntax

@CHUNK chunk_name

Binds the variable to a document. Where chunk_name is the name of the chunk. The returned value is a string containing the content of thechunk.

This binding is very similar to the with the exception that it will bind the TV to a .@RESOURCE binding Chunk

Usage

@CHUNK MycontactForm

See Also

Template Variables

Page 52: ModX Revolution Docs 20101007

Bindings

DIRECTORY Binding

What is the @DIRECTORY Binding?

The DIRECTORY binding reads the contents of a directory. This can really useful when you tie it into a List control widget, e.g. if you want to dosomething like give the user a list of logo images to choose for a page, or choose which mp3 file plays on a particular page. REMEMBER: itreturns contents of a directory, including all files and all directories - with the sole exception of directories prefixed with a period.ALL

Usage

When you create a Template Variable, place the following text into the  box:Input Option Values

@DIRECTORY /path/to/some_directory

Frequently, this is coupled with an Input Type of "DropDown List Menu" to allow the user to select a file from the list.

In MODx Revolution, the path used for the @DIRECTORY binding is relative to the site's root. It is an absolute file path. Ifnotyou want to list files above your site's root, you must use the ".." syntax, e.g.  This binding@DIRECTORY /../dir_above_rootwill work with or without a trailing slash in the directory name.

If you are using the @DIRECTORY binding for your template variable [[*myTV]], you can easily imagine that your template code could have somestuff in it like:

<img src= alt="" />"[[*myTV]]"

Additional Info

Can you filter which files are selected? E.g. using *.jpg? The following DOES NOT WORK:

@DIRECTORY /list/*.jpg # doesn't work!

There are PHP code snippets out there that emulate this functionality. See the following forum thread: http://modxcms.com/forums/index.php/topic,3124.0.html

Security

Depending on how the file is used on the page, it may pose a security risk. Be careful if you were using this binding to select JavaScript files to beexecuted. What if a user had the ability to upload (and thus execute) a JavaScript file? Also, always be wary of letting users see your directorystructure.

See Also

Template VariablesBindings

EVAL Binding

What is the @EVAL Binding?

The @EVAL Binding executes the specified PHP code. It should be used with careful security precautions.

Syntax

@EVAL php_code_here

Page 53: ModX Revolution Docs 20101007

Usage

Simply put a PHP statement after the @EVAL tag:

@EVAL .time();return "The time stamp is now "

@EVAL $a = 'dog'; $a;return

Security

The eval() statement raises an eyebrow with anyone concerned with security: eval statements are notorious for being exploited, so it'srecommended that you find another way of doing whatever you are trying to do, but this context is supported by MODx. If I let my cynical mindwander, allow me to paint one disasterous circumstance: some web user of your MODx application logs in and has access to a field that getsexecuted by an EVAL binding. This nefarious user could eval some nasty or statements and destroy your web server files, or readunlink() rmdir()sensitive files on the web-server that PHP has access to. Be careful with these!anywhere

Thankfully, I've been unsuccessful in my attempts to unlink() a file using the @EVAL binding... but I'm sure there are people out there more cleverthan me...

See Also

Template VariablesBindings

FILE Binding

What is the @FILE Binding?

The @FILE Binding returns the contents of any specified file.

Syntax

@FILE file_path

Binds the variable to a file, where is the path and name of the file. The return value is a string containing the content of the file. The filefile_pathpath is the absolute path from the root of the server or your particular installation.

The command is very useful in cases where we might want to generate data that's available in file. By using the and characters as a@FILE || ==delimiter we could interface with any external database application.

Usage

For example: Let's say we have a text file called headline_news.txt that is external to our database system. This file is constantly being updatedwith up-to-the-minute news items by another external system. We want to display these news items on our website for our visitors to see. Howcan we do that?

First, we might create a new Template Variable. We then add the @FILE command inside the default value of the TV. This will point to where theheadline_news.txt is located in our example. Our default value might look like this:

@FILE assets/news/headline_news.txt

Let's say each headline in the headline_news.txt file is separated by a new-line (lf or \n) character. We can use the Delimiter render to separateeach item and display them one at a time. Our fields will look like this:

Unable to render embedded object: File (filebinding.png) not found.

And viola! We have our dynamically rendering @FILE binding.

See Also

Template VariablesBindings

INHERIT Binding

Page 54: ModX Revolution Docs 20101007

What is the @INHERIT Binding?

The @INHERIT binding will automatically find the value of the parent Resource and use that as its value. If the parent Resource also has@INHERIT, it will look at that parent's parent's value, and so forth. If it ends up at the root and no value has been specified, the value will be 0.

Usage

@INHERIT

See Also

Template VariablesBindings

RESOURCE Binding

What is the @RESOURCE Binding?

The @RESOURCE Binding returns the parsed contents of any specified Resource.

Syntax

@RESOURCE resource_id

Binds the variable to a Resource, where resource_id is the ID of the Resource. The returned value is a string containing the parsed content of theResource.

Usage

To output the contents of a Resource with ID of 12:

@RESOURCE 12

See Also

Template VariablesBindings

SELECT Binding

What is the @SELECT Binding?

The @SELECT binding calls a database query based on the provided value and returns the result.

Syntax

@SELECT * FROM site_content

To write one of these, you need to be familiar with . It is recommended that you first write a functional MySQL statement thatMySQL syntaxexecutes without error in the MySQL command line (see errors, below for some pit-falls). Once you've verified that your query works, then youcan create a @SELECT binding with it.

All you need to do is after you've got a working MySQL query is:

add an '@' symbol in front of your SELECTomit the final semi-colon and any commentsput the query on a single line (no returns!)

Page 55: ModX Revolution Docs 20101007

You can place this binding in one of two places:

On a page (edit the page in the manager). The page where you want to put this binding must be using a valid template, and that templatemust have the correct template variable(s) associated with it. If you've created the and associated it with a ,Template Variable Templateand the page you're working on is using that , then you'll have a place to enter in some text for that variable when you edit theTemplatepage. Paste the "@SELECT ..." stuff in there. It sounds more complicated than it is, but this section is written verbosely for the sake ofclear documentation.You can also place the query into the "Default Value" box for the Template Variable. If you replace the default text of a Template Variablethat's already in use, be careful, because your pages might require a specific type of output, e.g. the output type that a @SELECTbinding returns.

REMEMBER: The query must be on ONE LINE. No returns!

Alternatives

Before we get any more complicated, consider doing this a different way. A might do the job more easily than a binding.Snippet

If your query needs to work with template variables and you need specialized formatting for the output, the @SELECT binding is probably not theway to go. Pretty much everything that's done with the bindings is also possible with ; the bindings just provide a shortcut. When you startSnippetsover-using the shortcut, you may run into headaches.

More Complex Example: Template Variables

What if you need to write a query that accesses the template variables associated with a particular page? Those variables aren't directly stored inthe table, they are stored in other tables. This forces you to write a JOIN statement. Here's a more tangible example: let's say all thesite_contentpages in a particular folder have a template variable for ... that field doesn't exist in the "site_content" table. Hold onto your butts,opening_datebecause this gets complicated. You have to look at MODx's gory plumbing in order to pull this off. You have to understand how MODx extends thedata stored in the "site_content" table and makes use of the custom fields known as "Template Variables". This is open to some debate, butunfortunately, MODx's database schema doesn't follow the strict best practices for foreign keys... it's not always clear which table is beingreferenced by a particular column... it's not even always clear that a column ''is'' a foreign key, but rest assured, it is possible... it just takes a bit ofpatience to figure out.

First, have a look at the following tables (you may have prefixes to your table names):

site_templates - contains the actual template code used for the site (lots of HTML appears in the content field).site_tmplvars - contains the name of template variable. The "name" field is what triggers the substitution. E.g. A name of"my_template_variable" should be used as "[[*my_template_variable]]". If you care to think of this architecturally, this table defines thevariable class: the name and type of variable that a series of pages will have.site_tmplvar_contentvalues - contains the values of the template variables for each page that uses them. The database table has 4 fields:id, tmplvarid (foreign key back to site_tmplvars.id), contentid (foreign key back to site_content.id), value (a text field). Architecturally, thistable represents of the particular class. In other words, one row in the table might have multiple rows in this tableinstances site_tmplvars(one row for each instance of the variable).site_tmplvar_templates - This is a mapping table which associates a Template Variable with a Template (maps site_template:id tosite_tmplvars:id). Contains 3 fields: tmplvarid, templateid, rank.

In our example, we want to filter based on a custom date field named "opening_date", but if you look closely, thesite_tmplvar_contentvalues.value field is a field. MySQL won't automatically recognize arbitrary text as a date value, so you'll have to maketextuse of MySQL's function. You may think that the site_tmplvars.display_params is a savior here, but it's not... you end up smashingstr_to_date()your nose directly into the nasty truth that the formats used by PHP's (stored in site_tmplvars.display_params) are the same as whatstrftime() notMySQL can use in its STR_TO_DATE() function. There may be a way to automatically do this, but it's easier to just hard-code it. You might endup with a query like this:

SELECT page.alias, tv_val.value, DATE_FORMAT(STR_TO_DATE(tv_val.value, '%d-%m-%Y %H:%i:%s'), '%Y-%m-%d %H:%i:%s') as `FormattedOpening Date`,

FROM site_content as pageJOIN site_tmplvar_contentvalues as tv_val ON page.id=tv_val.idWHERE page.parent='95' AND tv_val.tmplvarid='6' /* 6 is the opening_date */ AND DATE_FORMAT(STR_TO_DATE(tv_val.value, '%d-%m-%Y %H:%i:%s'), '%Y-%m-%d %H:%i:%s')>'2008-10-2413:04:57';

Page 56: ModX Revolution Docs 20101007

MODx uses the MyISAM table engine, not InnoDB, so it does not rigidly enforce the foreign key constraints that are inferred bythe table structure.

Errors

What if your MySQL statement executes perfectly, but once you put it in your SELECT binding, it fails? Well, there are some pit-falls. Theimplementation isn't perfect. Pay close attention to the following:

Your query appear on one line. Newline characters cause the @SELECT binding to choke.MUSTDelete all MySQL comments /* this style */ and -- this styleMake sure you have entered the table names correctly! Many sites use table-prefixes, so it is imperative that you test your queries beforetrying to use them in a @SELECT Binding. If your query has an error, MODx will log the error to the error log.

Next Step: Formatting

Ok, so you can return a bunch of data from the database... now what? If you need to format it intelligently, you might get some mileage out of theOutput Renders, but you might find the available options limiting to you. You can write your own that formats the value of a TemplateSnippetVariable.

Security

Does this binding let you execute UPDATE, INSERT, or DELETE queries (or, , DROP TABLE statements)? Even if it doesn't supportgasp directlythis, you may be able to construct and execute a complex query that SELECT's the result of a such a destructive query. At the very least, a usercould construct a query to select another user's password hash or to see documents that the user isn't supposed to have access to. A lot of theCMS's out there give access to the database (including DROP and DELETE statements) with the database handle used by the application.fullThat's dangerous, and the @SELECT binding may expose some of those same vulnerabilities.

See Also

Template VariablesBindings

Template Variable Output Types

Output Types for TVs

Output Types (also called Renders) on allow you to format the value of a TV to any different kind of output - such as a URL,Template Variablesimage, date, or anything else you can think of.

For example, say you have a TV that uses a Textbox as its Input Type. The user would then choose an Image through the TV input on theirResource. That's great - except your TV only outputs the URL of the image! You want it to output the image itself. So you'd then choose theOutput Render of the TV to be an Image, and boom! Your image TV now outputs the image directly! Sweet, huh?

MODx Revolution comes packaged with a few default Output Types. You can also , if you know a little PHP. The list ofcreate your ownpre-packaged ones are:

See Also

Date TV Output Type

Date TV Output Type

This type allows you to output any TV input as a Date, formatted in the way you want.

Output Properties

It's output properties look like:

Page 57: ModX Revolution Docs 20101007

Name Description

Date Format A format string similar to the .PHP strftime method

Default If no value is set for the TV, use the current time? This defaults to 'no', which will output a blank value.

See Also

Delimiter TV Output Type

Delimiter TV Output Type

This type allows you to output any TV input as a delimited list. It's very useful for TV inputs that store multiple values, such as the multiple selectlist, or checkbox inputs.

The output type will split the value on each double-bar (||), and then output it delimited by the delimiter value you set in the properties.

Output Properties

It's output properties look like:

Name Description

Delimiter A delimiter to separated each item with.

See Also

HTML Tag TV Output Type

HTML Tag TV Output Type

This type allows you to wrap an HTML tag around the input.

Output Properties

It's output properties look like:

Page 58: ModX Revolution Docs 20101007

Name Description

Tag Name The tag to create, such as div, img, span, etc.

Tag ID The dom ID of the tag.

Class Any CSS classes to add to the tag.

Style Any style attributes to add to the tag.

Attributes Any other attributes you want to add to the tag.

See Also

Adding a Custom TV Input Type

What are Custom TV Input Types?

MODx Revolution allows you to create your own custom TV input types (similar to the textbox, radio, textarea, richtext, etc types alreadyavailable) for your .Template Variables

Creating the Files

To create a custom TV input type (let's say, one called "test"), you need a few things. Let's say my "test" TV input type loads a Template selectingcombobox.

I'd first need 2 files:

An input controller - put here: core/model/modx/processors/element/tv/renders/mgr/input/test.phpAn input template - put here: manager/templates/default/element/tv/renders/input/test.tpl

The input controller, test.php, would have:

$ ->xpdo->lexicon->load('tv_widget');this// any other PHP i want here

$ ->xpdo->smarty->fetch('element/tv/renders/input/test.tpl');return this

And the input template, test.tpl, for the default mgr theme would have (note that it is using syntax):Smarty

Page 59: ModX Revolution Docs 20101007

<select id= name= class= ></select>"tv{$tv->id}" "tv{$tv->id}" "combobox"<script type= >"text/javascript"// <![CDATA[{literal}MODx.load({{/literal} xtype: 'modx-combo-template' ,transform: 'tv{$tv->id}' ,id: 'tv{$tv->id}' ,width: 300{literal} ,listeners: { 'select': { fn:MODx.fireResourceFormChange, scope: }}this});{/literal}// ]]></script>

And there you go! A custom TV input type.

You don't have to use the ExtJS code as shown here to have a custom input type. It could even just be a straight HTML input.It's really up to you.

See Also

Adding a Custom TV Output Type

What are TV Output Types?Creating the Files

Setting up the Input Properties ControllerSetting up the Input Properties TemplateSetting up the Output Controller

Using the Custom TV Output TypeSee Also

What are TV Output Types?

TV Output Types allow you to output in different markup and formats. Some examples include outputting a TV value as anTemplate Variablesimage, URL, HTML tag, date, etc.

MODx Revolution lets you create custom output types fairly easily.

Creating the Files

Let's create a custom TV Output Type called "button". This will render an input button (or more than one) with a specified value and an optionalname, with some other fields for attributes. You'll need 3 files:

An input properties controller - put here: core/model/modx/processors/element/tv/renders/mgr/properties/button.phpAn input properties template - put here: manager/templates/default/element/tv/renders/properties/button.tplAn output controller - put here: core/model/modx/processors/element/tv/renders/web/output/button.php

Setting up the Input Properties Controller

This is the PHP file that will load the mgr template for managing the TV output type's properties. We'll have it contain just this:

Page 60: ModX Revolution Docs 20101007

<?php// any custom php you want to run here

$modx->smarty->fetch('element/tv/renders/properties/button.tpl');return

Setting up the Input Properties Template

This is the template for the default manager theme to render properties with. We'll use ExtJS to render some pretty form fields:

<div id= ></div>"tv-wprops-form{$tv}"{literal}<script type= >"text/javascript"// <![CDATA[

params = {var{/literal}{foreach from=$params key=k item=v name='p'} '{$k}': '{$v}'{ NOT $smarty.foreach.p.last},{/ }if if{/foreach}{literal}};

oc = {'change':{fn:function(){Ext.getCmp('modx-panel-tv').markDirty();},scope: }};var thisMODx.load({ xtype: 'panel' ,layout: 'form' ,autoHeight: true ,labelWidth: 150 ,border: false ,items: [{ xtype: 'textfield' ,fieldLabel: _('class') ,name: 'prop_class' ,id: 'prop_class{/literal}{$tv}{literal}' ,value: params['class'] || '' ,width: 300 ,listeners: oc },{ xtype: 'textfield' ,fieldLabel: _('id') ,name: 'prop_id' ,id: 'prop_id{/literal}{$tv}{literal}' ,value: params['id'] || '' ,width: 300 ,listeners: oc },{ xtype: 'textfield' ,fieldLabel: _('style') ,name: 'prop_style' ,id: 'prop_style{/literal}{$tv}{literal}' ,value: params['style'] || '' ,width: 300 ,listeners: oc },{ xtype: 'textfield' ,fieldLabel: _('attributes') ,name: 'prop_attributes' ,id: 'prop_attributes{/literal}{$tv}{literal}' ,value: params['attributes'] || '' ,width: 300 ,listeners: oc }] ,renderTo: 'tv-wprops-form{/literal}{$tv}{literal}'});// ]]></script>{/literal}

The key way these save is that each field is prepended with 'prop_' in its name. This tells MODx to save this field in the TV's output properties.Make sure you specify your fields with this prefix!

Page 61: ModX Revolution Docs 20101007

You don't have to use ExtJS, however - you can use just straight HTML - it's totally up to you.Note that if you created another manager theme, you'd have to create a properties tpl for that theme as well.

Setting up the Output Controller

Now we get into the good stuff. This controller will handle exactly how the button is outputted. Our file looks like this (comments inline):

<?php$o= '';$buttons= $ ->parseInput($value, '||', 'array');this/* allow multiple buttons separated by ||, or checkbox/multiple input tvs */foreach ($buttons as $button) { (!is_array($button)) {if $button= explode('==', $button); } /* the TV value must have a value of either: text or text==name */ $text = $button[0]; (!empty($text)) {if $attributes = ''; $attr = array( 'class' => $params['class'], 'id' => ($params['id'] ? $params['id'] : ''), 'alt' => htmlspecialchars($params['alttext']), 'style' => $params['style'] ); /* a name is specified, use it! */if (!empty($button[1])) $attr['name'] = $button[1];if

/* separate the attributes into html tag format */ foreach ($attr as $k => $v) $attributes.= ($v ? ' '.$k.'= ' : '');"'.$v.'" $attributes .= ' '.$params['attrib'];

/* Output the image with attributes */ $o .= '<button'.rtrim($attributes).'>'.$text.'</button>'. ;"\n" }}

$o;return

Using the Custom TV Output Type

So, how does it look? Well, it should render an output form like this when editing the TV - I've added some custom values to it as well:

So we'll save this, and then let's go edit in in a Resource. We'll specify two buttons, separating with ||. We could also just do one button. And, we'llhave the first button have a custom 'name' attribute as well:

Great. Now let's preview the resource, and we'll get an output like this:

Page 62: ModX Revolution Docs 20101007

And we can examine the HTML source:

And there you go! A custom TV output type!

See Also

Properties and Property Sets

What are Properties?What are Property Sets?Assigning Property Sets to ElementsCreating Properties in a Property SetImporting and Exporting PropertiesUsing Properties Programmatically

Using getOptionConclusion

What are Properties?

Properties are simply values that can be configured for any Element via . An example of a Property is the token 'debug' in this SnippetTag Syntaxcall:

[[Quip? &debug=`1`]]

'debug' is the Property, where '1' is the Property Value. They are passed to the Element's parser and interpreted there. Snippets and Plugins canaccess them through the $scriptProperties array, or straight in their key values, as they are extract()'ed.

What are Property Sets?

Property Sets are user-defined collections of properties for an Element. They can be attached to one, or more, Elements via that Element's editingpage. Those property sets, once attached, then can be called in their Element's call syntax like such:

[[ElementName@PropertySetName]]

So, for an example, let's have a Property Set with two properties - 'debug' set to true, and 'user' set to 2. Then let's call it in a snippet.:

[[TestSnippet@DebugMode?user=`1`]]

This example would call the snippet "TestSnippet", load the Property Set 'DebugMode', and then would set the value 'user' to 1. Since theproperty 'user' is defined as 2 in the Property Set, it will be overridden in the call, and end up as 1. The order of property loading is:

Default Element Properties -> Property Set -> Tag-defined Properties

So, if the default property of 'user' was 0, then it would then be set to 2 by the property set, and then to 1 by the call.

The property set can also contain properties not defined in either the default element properties, or in the tag call. This can be useful to loadElements across the site without having to repeat the tag syntax across the site - and make it much easier to manage your tag calls.

Properties will be passed into the Element just as they were in MODx 0.9.6, but they are also passed in via the $scriptProperties array, for thoseof you wanting more flexibility with knowing what properties are passed in. 

Assigning Property Sets to Elements

Page 63: ModX Revolution Docs 20101007

Property Sets can only be used on Elements that they are assigned to. This can be done via either the element's properties grid, or Tools ->Property Sets.

For example, here's an image of a property set named 'TestPropertySet' in a snippet's editing page:

As you can see here, there is a property set loaded with some properties. Properties in green are default properties that have been overridden inthe property set. Properties that are purple are properties that do not exist in the Element's default properties, but are defined in the Property Set.Properties can also have descriptions, as shown by the + icon to the left. When clicked, the description will appear below.

To add a property set to an Element, you'll simply click the "Add Property Set" toolbar item in the top right of the grid. It will show a window likethis:

From there, you can select the property set you want to add. If you'd like to create a completely new Property Set and automatically attach it tothis element, you can do so by checking the "Create New Property Set" checkbox, and these fields will show:

Page 64: ModX Revolution Docs 20101007

Then once you save your new Property Set, it will be automatically attached to that Element.

Creating Properties in a Property Set

To create a Property in a Property Set, you'll simply need to just load the Property Set you want to work on, and then click "Create Property". Thatwill load this window:

From there, you can create a property set. Note here that we are creating a property of type "List", which is a dropdown property. You can addoptions to that property from the grid. Once you save the property, it will be added to the property set.

Importing and Exporting Properties

You can also import and export properties using the grid. Simply click on the corresponding buttons at the bottom.

When you import properties, it will overwrite your properties in the grid currently. Make sure that you want to do this beforeimporting!

Using Properties Programmatically

Page 65: ModX Revolution Docs 20101007

Properties are available in a snippet via the $scriptProperties array:

$prop = $scriptProperties['propertyName'];

Note that if a parameter is sent in the snippet call that has the same name as a property in a property set, the parameter value will override thedefault value in the property set.

Using getOption

You can also get a snippet property with $modx->getOption() like this:

$modx->getOption('propertyName', $scriptProperties, ' ');default

Conclusion

Input and Output Filters

What are Filters?Input FiltersOutput FiltersExamplesSee Also

What are Filters?

Filters in Revolution allow you to manipulate the way data is presented or parsed in a tag. They allow you to modify values from inside yourtemplates.

Input Filters

Currently input filters process tag calls. More documentation to come.

Output Filters

In Revolution, Output Filters behave similarly to PHx calls in MODx Evolution - except they're built into the core. The syntax is like such:

[[element:modifier=`value`]]

They can also be chained (executed left to right):

[[element:modifier:anothermodifier=`value`:andanothermodifier:yetanother=`value2`]]

The list of string modifiers:

Modifier Description Example

cat Appends the option's value (if not empty) to the input value [[+numbooks:cat=` books`]]

lcase Similar to PHP's strtolower [[+title:lcase]]

ucase Similar to PHP's strtoupper [[+headline:ucase]]

ucwords Similar to PHP's ucwords [[+title:ucwords]]

ucfirst Similar to PHP's ucfirst [[+name:ucfirst]]

htmlent Similar to PHP's . Uses the current value the system settinghtmlentities"modx_charset"

[[+email:htmlent]]

esc,escape Safely escapes character values [[+email:escape]]

Page 66: ModX Revolution Docs 20101007

strip Replaces all linebreaks, tabs and multiple spaces with just one space [[+textdocument:strip]]

stripString Strips string of specified value [[+name:stripString=`Mr.`]]

replace Replaces one value with another [[+pagetitle:replace=`Mr.==Mrs.`]]

stripTags,notags Similar to PHP's strip_tags [[+code:strip_tags]]

len,length Similar to PHP's strlen [[+longstring:strlen]]

reverse Similar to PHP's strrev [[+mirrortext:reverse]]

wordwrap Similar to PHP's . Takes optional value to set wordwrap position.wordwrap [[+bodytext:wordwrap=`80`]]

wordwrap Similar to PHP's , with word cutting enabled. Takes optional value towordwrapset wordwrap position.

[[+bodytext:wordwrap=`80`]]

limit Limits a string to a certain number of characters. Defaults to 100. [[+description:limit=`50`]]

ellipsis Adds an ellipsis to and truncates a string if it's longer than a certain number ofcharacters. Defaults to 100.

[[+description:ellipsis=`50`]]

tag Displays the raw element without the :tag. Useful for documentation. [[+showThis:tag]]

math Returns the result of an advanced calculation (expensive on processor. notrecommended)

 

add,increment,incr Returns input incremented by option (default: +1) [[+downloads:incr]] [[+blackjack:add=`21`]]

subtract,decrement,decr Returns input decremented by option (default: -1) [[+countdown:decr]] [[+moneys:subtract=`100`]]

multiply,mpy Returns input multiplied by option (default: *2) [[+trifecta:mpy=`3`]

divide,div Returns input divided by option (default: /2) Does not accept 0. [[+rating:div=`4`]]

modulus,mod Returns the option modulus on input (default: %2, returns 0 or 1) [[+number:mod]]

ifempty,default,empty Returns the input value if empty [[+name:default=`anonymous`]]

notempty Returns the input value if not empty [[+name:notempty=`Hello[[+name]]!`]]

nl2br Similar to PHP's nl2br [[+textfile:nl2br]]

date Similar to PHP's . Value is format.strftime [[+birthyear:date=`%Y`]]

strtotime Similar to PHP's . Takes in a date.strtotime [[+thetime:strtotime]]

fuzzydate Returns a pretty date format with yesterday and today being filtered. Takes in adate.

[[+createdon:fuzzydate]]

ago Returns a pretty date format in seconds, minutes, weeks or months ago. Takesin a date.

[[+createdon:ago]]

md5 Similar to PHP's .md5 [[+password:md5]]

cdata Wraps the text with CDATA tags [[+content:cdata]]

userinfo Returns the requested user data. The element must be a modUser ID. The valuefield is the column to grab.

[[+userId:userinfo=`username`]]

isloggedin Returns true if user is authenticated in this context.  

isnotloggedin Returns true if user is not authenticated in this context.  

urlencode Similar to PHP's urlencode [[+mystring:urlencode]]

urldecode Similar to PHP's urldecode [[+myparam:urldecode]]

Examples

A good example of chaining would be to format a date string to another format, like so:

Page 67: ModX Revolution Docs 20101007

[[+mydate:strtotime:date=`%Y-%m-%d`]]

Directly accessing the modx_user_attributes table in the database using filters instead of a can be accomplished simply by utilizing theSnippetuserinfo filter. Select the appropriate column from the table and link to it, like so:

User Internal Key: [[+userId:userinfo=`internalKey`]]<br />User name: [[+userId:userinfo=`username`]]<br />Full Name:[[+userId:userinfo=`fullname`]]<br />Role: [[+userId:userinfo=`role`]]<br />E-mail: [[+userId:userinfo=`email`]]<br />Phone: [[+userId:userinfo=`phone`]]<br />Mobile Phone: [[+userId:userinfo=`mobilephone`]]<br />Fax: [[+userId:userinfo=`fax`]]<br />Date of birth: [[+userId:userinfo=`dob`:date=`%Y-%m-%d`]]<br />Gender[[+userId:userinfo=`gender`]]<br />Country: [[+userId:userinfo=`country`]]<br />State: [[+userId:userinfo=`state`]]<br />Zip Code: [[+userId:userinfo=`zip`]]<br />Photo: [[+userId:userinfo=`photo`]]<br />Comment: [[+userId:userinfo=`comment`]]<br />Password: [[+userId:userinfo=`password`]]<br />Cache Password: [[+userId:userinfo=`cachepwd`]]<br />Last Login: [[+userId:userinfo=`lastlogin`:date=`%Y-%m-%d`]]<br />The Login:[[+userId:userinfo=`thislogin`:date=`%Y-%m-%d`]]<br />

of Logins: [[+userId:userinfo=`logincount`]]Number

Note that the user ID and username is already available by default in MODx, so you dont need to use the "userinfo" filter:

[[+modx.user.id]] - Prints the ID[[+modx.user.username]] - Prints the username

Also, can be used as custom modifiers and filters. Simply put the name instead of the modifier. Example with a snippet namedSnippets Snippet'makeDownloadLink':

[[+file:makeDownloadLink=`notitle`]]

This will pass these properties to the snippet:

Param Value Example Result

input The element's value. The value of [[+file]]

options Any value passed to the modifier. 'notitle'

token The type of the parent element. + (the token on `file`)

name The name of the parent element. file

tag The complete parent tag. [[+ `notitle`]]file:makeDownloadLink=

And then the return value of that call would be whatever the snippet returns.

See Also

Properties and Property SetsTemplatesTemplate VariablesSnippets

Administering Your Site

Page 68: ModX Revolution Docs 20101007

This section contains information about maintaining and administering your MODx site.

Settings

What are Settings?

Settings are site-wide variables that can be used by either the MODx Core or by 3rd-Party Components to provide site, context, or user-levelcustomization.

Usage

They can be referenced at any point via their Tag, for example, for the 'site_start' Setting:

[[++site_start]]

System Settings can also be overridden by Context Settings, which are specific to each . Context Settings can be overridden by UserContextSettings, which are specific to each user. So, the order of relevance is:

System Setting -> Context Setting -> User Setting

Let's say I set the System Setting named 'use_editor' to 0. However, I created a Context Setting called 'use_editor' for the 'mgr' context and set itto 1. This would mean that any time I'm in the mgr context, the setting would be 1, overriding the System Setting.

Further, I've got a user named 'johndoe' who I don't want to use the editor. I create a User Setting 'use_editor' for his user and set it to 0. Now,John Doe's "use_editor" setting will be 0, overriding the Context Setting.

Settings can also be specific to , as well. This allows you to easily group your settings for each of your different Components.Namespaces

Retrieving Settings in PHP

Getting settings is simple in MODx Revolution; simply use . For example, to get the setting 'site_start', simply:getOption

$siteStartId = $modx->getOption('site_start');

Now, all settings are overridable by Context and User, as described above, and getOption respects that. So, if in the above code example, if youhad set site_start as a Context Setting that overrode the System Setting, getOption will respect that - but only if you're executing the PHP in thatContext that has the Setting.

For example, if I were using that code block in a Context called 'boo', and I had added a Context Setting for site_start in the 'boo' Context, and setit to 3, the above code would output '3'.

Now if I were in the 'web' context, and site_start was still '1' (from the System Setting), getOption would return 1.

Default values with getOption

getOption supports 3 parameters:

1. The key of the setting2. An array to search first before looking for the setting3. A default value should the setting not be found.

So, for example, if I were in a Snippet and wanted some default properties at the top, I could use getOption. automatically pass in anSnippetsarray of all the Properties attached to that snippet (or specified in the Tag call) via the $scriptProperties array. So, you can use that array to checkfor default properties. This example sets a default value to the 'showPublished' property should it not be specified:

Page 69: ModX Revolution Docs 20101007

$showPublished = $modx->getOption('showPublished',$scriptProperties, );true

Now, assuming the Snippet doesnt have showPublished as a , if you called the Snippet via the tag call:default property

[[mySnippet]]

showPublished will be set to true. If it did have the default Property attached to it that set the value to 0, or the showPublished property wasspecified as 0 in the tag, then showPublished would be 0.

Additional Information

Only use getObject if you're checking for an existing setting in the DB because you want to create onegetOption uses the settings cache (its much faster)getOption will also check User -> Context -> System settings (allowing you to override system settings with context and further with usersettings)

See Also

System Settings

MODx comes with a flexible amount of system settings. They are found in System -> System Settings, and can easily be edited and changed.

Settings List 

A description of each setting follows:

allow_duplicate_alias

allow_duplicate_alias

Name: Allow Duplicate Aliases: Yes/NoType

: NoDefault

If set to 'yes', this will allow duplicate aliases to be saved.

This option should be used with set to 'Yes' in order to avoid problems when referencing a resource.use_alias_path

allow_multiple_emails

allow_multiple_emails

Name: Allow Duplicate Emails for Users: Yes/NoType

: YesDefault

If enabled, Users may share the same email address.

allow_tags_in_post

Page 70: ModX Revolution Docs 20101007

allow_tags_in_post

Name: Allow Tags in Post: Yes/NoType

: YesDefault

If set to true, will allow POST requests to contain HTML form tags.

Do not change this value for the manager context. Only use this in a Context if you specifically want to. This can causeproblems in a MODx install if you change it without an explicit purpose.

auto_check_pkg_updates

auto_check_pkg_updates

Name: Automatic Check for Package Updates: Yes/NoType

: YesDefault

If 'Yes', MODx will automatically check for updates for packages in Package Management. This may slow the loading of the Packages grid.

auto_check_pkg_updates_cache_expire

auto_check_pkg_updates_cache_expire

Name: Cache Expiration Time for Automatic Package Updates Check: NumberType

: 15Default

The number of minutes that will cache the results when checking for package updates.Package Management

auto_menuindex

auto_menuindex

Name: Menu Indexing Default: Yes/NoType

: YesDefault

Select 'Yes' to turn on automatic menu index incrementing by default.

blocked_minutes

blocked_minutes

Name: Blocked Minutes: NumberType

: 60Default

The number of minutes that a user will be blocked for if they reach their maximum number of allowed failed login attempts.

cache_action_map

cache_action_map

Name: Enable Action Map Cache: Yes/NoType

: YesDefault

When enabled, actions (or controller maps) will be cached to greatly reduce manager page load times.

Page 71: ModX Revolution Docs 20101007

cache_context_settings

cache_context_settings

Name: Enable Context Setting Cache: Yes/NoType

: YesDefault

When enabled, context settings will be cached to reduce load times.

cache_db

cache_db

Name: Enable Database Cache: Yes/NoType

: NoDefault

When enabled, objects and raw result sets from SQL queries are cached to significantly reduce database loads.

This can take up a good amount of hard drive space. Only do this if you have enough space to scale the requests.

cache_db_expires

cache_db_expires

Name: Expiration Time for DB Cache: NumberType

: 0Default

Default time for the expiration of the database cache. If set to '0', the cache will never expire unless a record is updated.

cache_default

cache_default

Name: Cacheable Default: Yes/NoType

: YesDefault

Makes all new resources cacheable by default.

cache_disabled

cache_disabled

Name: Disable Global Cache Options: Yes/NoType

: NoDefault

If true, disables all MODx caching features.

This feature is . MODx recommends not turning off caching site-wide, as it can significantly slow down your site.experimental

cache_handler

cache_handler

Name: Cache Handler Class

Page 72: ModX Revolution Docs 20101007

: StringType: xPDOFileCacheDefault

The class name of the type handler to use for caching. Can be set to a custom caching class you provide, or xPDOMemCache if you havememcached installed.

cache_json

cache_json

Name: Cache JSON Data: Yes/NoType

: NoDefault

If Yes, caching will be stored JSON format.

cache_json_expires

cache_json_expires

Name: Expiration Time for JSON Cache: NumberType

: 0Default

Expiration time for JSON format cached data. A value of zero means the cache never expires.

cache_lexicon_topics

cache_lexicon_topics

Name: Cache Lexicon Topics: Yes/NoType

: YesDefault

When enabled, all Lexicon Topics will be cached so as to greatly reduce load times for Internationalization functionality. MODx stronglyrecommends leaving this set to Yes, as setting it to No will greatly slow down your manager load times.

cache_noncore_lexicon_topics

cache_noncore_lexicon_topics

Name: Cache Non-Core Lexicon Topics: Yes/NoType

: YesDefault

When disabled, non-core Lexicon Topics will be not be cached. This is useful to disable when developing your own Extras.

cache_resource

cache_resource

Name: Enable Partial Resource Cache: Yes/NoType

: YesDefault

Partial Resource caching is configurable by resource when this feature is enabled. Disabling this feature will disable it globally.

cache_resource_expires

cache_resource_expires

Name: Expiration Time for Partial Resource Cache: NumberType

: 0Default

Expiration time for the Partial Resource Cache setting. A value of 0 means the cache will never expire.

Page 73: ModX Revolution Docs 20101007

cache_scripts

cache_scripts

Name: Enable Script Cache: Yes/NoType

: YesDefault

When enabled, MODx will cache all Scripts (Snippets and Plugins) to file to reduce load times. MODx recommends leaving this set to 'Yes'.

compress_css

compress_css

Name: Use Compressed CSS Stylesheets: Yes/NoType

: YesDefault

When this is enabled, MODx will use a compressed version of its custom CSS stylesheets. This greatly reduces load and execution time. Disableonly if you are modifying core elements.

This setting will not work in Git deployments of Revolution. Leave it at 'No'.

compress_js

compress_js

Name: Use Compressed Javascript Libraries: Yes/NoType

: YesDefault

When this is enabled, MODx will use a compressed version of its custom JavaScript libraries. This greatly reduces load and execution time.Disable only if you are modifying core elements.

This setting will not work in Git deployments of Revolution. Leave at 'No'.

concat_js

concat_js

Name: Use Concatenated Javascript Libraries: Yes/NoType

: YesDefault

When this is enabled, MODx will use a concatenated version of its custom core JavaScript libraries. This greatly reduces load and execution time.Disable only if you are modifying core elements.

This setting will not work in Git deployments of Revolution. Leave set to 'No'.

container_suffix

container_suffix

Page 74: ModX Revolution Docs 20101007

Name: Container Suffix: StringType

: /Default

Sets the container suffix for the site. This is the suffix added to the Friendly URL when a Resource is checked as a container.

Example

A container suffix of / will render a Resource with an alias of 'test' as:

www.mysite.com/test/

whereas a container suffix of '.html' will render:

www.mysite.com/test.html

cultureKey

cultureKey

Name: Language: StringType

: enDefault

Select the language for all non-manager Contexts, including web.

custom_resource_classes

custom_resource_classes

Name: Custom Resource Classes: StringType

:Default

A comma-separated list of custom Resource classes. Specify with lowercase_lexicon_key:className (Ex: wiki_resource:WikiResource). Allcustom Resource classes must extend modResource. To specify the controller location for each class, add a setting with[nameOfClassLowercase]_delegate_path with the directory path of the create/update php files. Ex: wikiresource_delegate_path for a classWikiResource that extends modResource.

default_template

default_template

Name: Default Template: TemplateType

: 1Default

The default to use for new Resources. You can still select a different Template in the Resource editing page; this setting just pre-selectsTemplateone of the Templates.

editor_css_path

editor_css_path

Name: Path to CSS file: StringType

:Default

The path to your CSS file that you wish to use within the editor. The best way to enter the path is to enter the path from the root of your server, forexample: /assets/site/style.css. If you do not wish to load a style sheet into the editor, leave this field blank.

editor_css_selectors

editor_css_selectors

Name: CSS Selectors for Editor

Page 75: ModX Revolution Docs 20101007

: StringType:Default

emailsender

emailsender

Name: Site Admin Email Address: StringType

: Set at InstallDefault

The e-mail address used when sending users their usernames and passwords.

emailsubject

email_subject

Name: Email Subject: StringType

: Your login detailsDefault

The subject line for the default signup email.

error_page

error_page

Name: Error Page: NumberType

: 1Default

The ID of the resource you want to send users to if they request a Resource which doesn't actually exist.

failed_login_attempts

failed_login_attempts

Name: Failed Login Attempts: NumberType

: 3Default

The number of times a user can attempt to login before being blocked.

fe_editor_lang

fe_editor_lang

Name: Front-end Editor Language: StringType

: englishDefault

The language for the editor to use when used as a front-end editor.

This setting is and no longer in use.deprecated

feed_modx_news

feed_modx_news

Name: MODx News Feed URL: StringType

Page 76: ModX Revolution Docs 20101007

: Default http://feeds.feedburner.com/modx-announce

Set the URL for the RSS feed for the MODx News panel in the manager.

feed_modx_news_enabled

feed_modx_news_enabled

Name: Enable MODx News Feed: Yes/NoType

: YesDefault

If 'No', MODx will hide the News feed in the welcome section of the manager.

feed_modx_security

feed_modx_security

Name: MODx Security Feed URL: StringType

: Default http://feeds.feedburner.com/modxsecurity

Set the URL for the RSS feed for the MODx Security panel in the manager.

feed_modx_security_enabled

feed_modx_security_enabled

Name: Enable MODx Security Feed: Yes/NoType

: YesDefault

If 'No', MODx will hide the Security feed in the welcome section of the manager.

filemanager_path

filemanager_path

Name: File Manager Path: stringType

:Default

Determines the root of the file browser for the currently-logged in user in the manager backend.

Usage

Specify either a relative path from the MODx root directory, or an absolute path. It can be outside of the webroot.

friendly_alias_urls

friendly_alias_urls

Name: Use Friendly URL Aliases: Yes/NoType

: NoDefault

Turns on friendly URLs, which generate SEO-friendly URL mappings for your Resources. The URL map is determined by the Resource's place inthe site tree, and its "alias" field.

For example, a Resource with alias 'blog' and a Content Type of "HTML" will be rendered as www.mysite.com/blog.html if it's not a container. Ifthe blog Resource was under another Resource with an alias of 'test', then the blog Resource's URL would be:

www.mysite.com/test/blog.html

This allows for completely customizable and automatically built SEO-friendly URLs.

Page 77: ModX Revolution Docs 20101007

You'll need to rename the ht.access file to .htaccess in your site root, and change the RewriteBase parameter in it to your site'sbase URL to get this to work.

friendly_url_prefix

friendly_url_prefix

Name: Friendly URL Prefix: StringType

:Default

This setting is and is no longer available in MODx Revolution.deprecated

Here you can specify the prefix to use for friendly URLs. For example, a prefix setting of 'page' will turn the URL /index.php?id=2 to the friendlyURL /page2.html (assuming the suffix is set to .html). This way you can specify what your users (and search engines) see for links on your site.

friendly_url_suffix

friendly_url_suffix

Name: Friendly URL Suffix: StringType

: .htmlDefault

This setting is and is no longer in use. See for how suffixes are now handled.deprecated Content Types

Here you can specify the suffix for Friendly URLs. Specifying '.html' will append .html to all your friendly URLs.

friendly_urls

friendly_urls

Name: Use Friendly URLs: Yes/NoType

: NoDefault

This allows you to use search engine friendly URLs with MODx. Please note, this only works for MODx installations running on Apache, and you'llneed to write a .htaccess file for this to work. See the .htaccess file included in the distribution for more info.

mail_charset

mail_charset

Name: Mail Charset: StringType

: UTF-8Default

The (default) charset for e-mails, e.g. 'iso-8859-1' or 'UTF-8'.

mail_encoding

mail_encoding

Name: Mail Encoding: StringType

: 8bitDefault

Page 78: ModX Revolution Docs 20101007

Sets the Encoding of the message. Options for this are "8bit", "7bit", "binary", "base64", and "quoted-printable".

mail_smtp_auth

mail_smtp_auth

Name: Use SMTP Authentication: Yes/NoType

: NoDefault

Sets SMTP authentication. Utilizes the and settings.mail_smtp_user mail_smtp_pass

mail_smtp_helo

mail_smtp_helo

Name: SMTP Helo Message: StringType

:Default

Sets the SMTP HELO of the message (Defaults to the hostname).

mail_smtp_hosts

mail_smtp_hosts

Name: SMTP Hosts: StringType

: localhostDefault

Sets the SMTP hosts. All hosts must be separated by a semicolon. You can also specify a different port for each host by using this format:hostname:port (e.g. "smtp1.example.com:25;smtp2.example.com"). Hosts will be tried in order.

mail_smtp_keepalive

mail_smtp_keepalive

Name: SMTP User: Yes/NoType

: NoDefault

Prevents the SMTP connection from being closed after each mail sending. Not recommended.

mail_smtp_pass

mail_smtp_pass

Name: SMTP Password: StringType

:Default

The password to authenticate to SMTP against.

mail_smtp_port

mail_smtp_port

Name: SMTP Port: StringType

: 587Default

Sets the default SMTP server port.

mail_smtp_prefix

Page 79: ModX Revolution Docs 20101007

mail_smtp_prefix

Name: SMTP Connection Prefix: StringType

:Default

Sets connection prefix. Options are "", "ssl" or "tls".

mail_smtp_single_to

mail_smtp_single_to

Name: SMTP Single-To: Yes/NoType

: NoDefault

Provides the ability to have the TO field process individual emails, instead of sending to entire TO addresses.

mail_smtp_timeout

mail_smtp_timeout

Name: SMTP Timeout: NumberType

: 10Default

Sets the SMTP server timeout in seconds. This function will not work in win32 servers.

mail_smtp_user

mail_smtp_user

Name: SMTP User: StringType

:Default

The user to authenticate to SMTP against.

mail_use_smtp

mail_use_smtp

Name: Use SMTP in Mail: Yes/NoType

: NoDefault

If true, MODx will attempt to use SMTP in mail functions.

manager_date_format

manager_date_format

Name: Manager Date Format: StringType

: Y-m-dDefault

The format string, in PHP date() format, for the dates represented in the manager.

manager_direction

manager_text_direction

Name: Manager Text Direction: StringType

: ltrDefault

Page 80: ModX Revolution Docs 20101007

The direction that the text will be rendered in the Manager, left to right or right to left.

manager_lang_attribute

manager_lang_attribute

Name: Manager HTML and XML Language Attribute: StringType

: enDefault

The language code that best fits with your chosen manager language. This will ensure that the browser can present content in the best format foryou.

manager_language

manager_language

Name: Language for the Manager: StringType

: enDefault

The language for the MODx Manager interface. This will override any cultureKey setting for the mgr context.

manager_theme

manager_theme

Name: Manager Theme: StringType

: defaultDefault

The current Theme for the backend Manager.

manager_time_format

manager_time_format

Name: Manager Time Format: StringType

: g:i aDefault

The format string, in PHP date() format, for the time settings represented in the manager.

modx_charset

modx_charset

Name: Character Encoding: stringType

: UTF-8Default

The character encoding used. Please note that MODx primarily works with UTF-8.

new_file_permissions

new_file_permissions

Name: New File Permissions: stringType

: 0644Default

When uploading a new file in the File Manager, the File Manager will attempt to change the file permissions to those entered in this setting. Thismay not work on some setups, such as IIS, in which case you will need to manually change the permissions.

new_folder_permissions

Page 81: ModX Revolution Docs 20101007

new_folder_permissions

Name: New Folder Permissions: StringType

: 0755Default

When creating a new folder in the File Manager, the File Manager will attempt to change the folder permissions to those entered in this setting.This may not work on some setups, such as IIS, in which case you will need to manually change the permissions.

password_generated_length

password_generated_length

Name: Password Auto-Generated Length: NumberType

: 8Default

The length of the auto-generated password for a User.

password_min_length

password_min_length

Name: Password Minimum Length: NumberType

: 8Default

The minimum length in characters for a password for a User.

phpthumb_cache_maxage

phpthumb_cache_maxage

Name: phpThumb Max Cache Age: NumberType

: 30 (days)Default

Delete cached thumbnails that have not been accessed in more than X days.

phpthumb_cache_maxfiles

phpthumb_cache_maxfiles

Name: phpThumb Max Cache Files: NumberType

: 10000 (10k files)Default

Delete least-recently-accessed thumbnails when cache has more than X files.

phpthumb_cache_maxsize

phpthumb_cache_maxsize

Name: phpThumb Max Cache Size: NumberType

: 100 (mb)Default

Delete least-recently-accessed thumbnails when cache grows bigger than X megabytes in size.

phpthumb_cache_source_enabled

phpthumb_cache_source_enabled

Name: phpThumb Cache Source Files: Yes/NoType

Page 82: ModX Revolution Docs 20101007

: NoDefault

Whether or not to cache source files as they are loaded. Recommended to leave at No.

phpthumb_far

phpthumb_far

Name: phpThumb Force Aspect Ratio: Yes/NoType

: NoDefault

The default far setting for phpThumb when used in MODx. Defaults to C to force aspect ratio toward the center.

phpthumb_zoomcrop

phpthumb_zoomcrop

Name: phpThumb Zoom-Crop: StringType

: 0Default

The default zc setting for phpThumb when used in MODx. Defaults to 0 to prevent zoom cropping.

proxy_auth_type

proxy_auth_type

Name: Proxy Authentication Type: StringType

: BASICDefault

Supports either BASIC or NTLM.

proxy_host

proxy_host

Name: Proxy Host: StringType

:Default

The hostname of your proxy server. If this is specified, MODx will attempt to use the proxy when connecting to the RSS feeds or Package.Management

proxy_password

proxy_password

Name: Proxy Password: StringType

:Default

The password to authenticate with on your proxy server.

proxy_port

proxy_port

Name: Proxy Port: StringType

:Default

The port for your proxy server.

Page 83: ModX Revolution Docs 20101007

proxy_username

proxy_username

Name: Proxy Username: StringType

:Default

The username to authenticate against with your proxy server.

publish_default

publish_default

Name: Published Default: Yes/NoType

: NoDefault

If true, makes all new resources published by default.

rb_base_dir

rb_base_dir

Name: Resource Path: StringType

:Default

The physical path to the resource directory. This setting is usually automatically generated. If you're using IIS, however, MODx may not be able towork the path out on its own, causing the Resource Browser to show an error. In that case, you can enter the path to the images directory here(the path as you'd see it in Windows Explorer).

This setting is in MODx Revolution. Please use instead.deprecated filemanager_path

rb_base_url

rb_base_url

Name: Resource Browser Base URL: StringType

:Default

Enter the virtual path to resource directory. This setting is usually automatically generated. If you're using IIS, however, MODx may not be able towork the URL out on it's own, causing the Resource Browser to show an error. In that case, you can enter the URL to the images directory here(the URL as you'd enter it on Internet Explorer).

This setting is in MODx Revolution. Please use instead.deprecated filemanager_path

request_controller

request_controller

Name: Request Controller Filename: StringType

: index.phpDefault

The filename of the main request controller from which MODx is loaded. Most users can leave this as index.php.

request_param_alias

Page 84: ModX Revolution Docs 20101007

request_param_alias

Name: Request Alias Parameter: StringType

: qDefault

The name of the GET parameter to identify Resource aliases when redirecting with FURLs.

request_param_id

request_param_id

Name: Request ID Parameter: StringType

: qDefault

The name of the GET parameter to identify Resource IDs when not using FURLs.

search_default

search_default

Name: Published Default: Yes/NoType

: YesDefault

If true, makes all new resources searchable by default.

server_offset_time

server_offset_time

Name: Server Offset Time: NumberType

: 0Default

Select the number of hours time difference between where you are and where the server is.

server_protocol

server_protocol

Name: Server Protocol: StringType

: httpDefault

If your site is on a normal http or secure https connection.

session_cookie_domain

session_cookie_domain

Name: Session Cookie Domain: StringType

: localhostDefault

Use this setting to customize the session cookie domain.

This setting isn't in MODx by default, as it's best to let PHP calculate this on its own. Only set this if you are sure of what you aredoing.

session_cookie_lifetime

Page 85: ModX Revolution Docs 20101007

session_cookie_lifetime

Name: Session Cookie Lifetime: NumberType

: 604800Default

Use this setting to customize the session cookie lifetime in seconds. This is used to set the lifetime of a client session cookie when they choosethe 'remember me' option on login.

session_cookie_path

session_cookie_path

Name: Session Cookie Path: StringType

: /Default

Use this setting to customize the cookie path for identifying site specific session cookies.

This setting isn't in MODx by default. It's best to let PHP figure this out on its own. Only set this if you know what you are doing.

session_cookie_secure

session_cookie_secure

Name: Session Cookie Secure: Yes/NoType

: NoDefault

Enable this setting to use secure session cookies.

session_handler_class

session_handler_class

Name: Session Handler Class: StringType

: modSessionHandlerDefault

For database managed sessions, use 'modSessionHandler'. Leave this blank to use standard PHP session management, or set to your owncustom session handling class.

session_name

session_name

Name: Session Name: StringType

: modxcmssessionDefault

Use this setting to customize the session name used for the sessions in MODx.

This setting isn't set by default in MODx, as it's best to let PHP calculate this on its own. Only set this if you know what you aredoing.

settings_version

settings_version

Page 86: ModX Revolution Docs 20101007

Name: MODx Version: StringType

: modx-2.0.0-plDefault

The current version of MODx.

Do change this value! Changing it could seriously affect your system.not

signupemail_message

signupemail_message

Name: Signup Email Message: StringType

:Default

Hello [[+uid]]

Here are your login details [[+sname]] Content Manager:for

Username: [[+uid]]Password: [[+pwd]]

Once you log into the Content Manager ([[+surl]]), you can change your password.

Regards,Site Administrator

Here you can set the message sent to your users when you create an account for them and let MODx send them an e-mail containing theirusername and password.

The following placeholders are replaced by the Content Manager when the message is sent:

[[+sname]] - Name of your web site[[+saddr]] - Your web site email address[[+surl]] - Your site url[[+uid]] - User\'s Login name or id[[+pwd]] - User\'s password[[+ufn]] - User\'s full name.

Leave the [[+uid]] and [[+pwd]] in the e-mail, or else the username and password won't be sent in the mail and your users won'tknow their username or password!

site_name

site_name

Name: Site Name: StringType

: MODx RevolutionDefault

The name of your MODx site.

site_start

Page 87: ModX Revolution Docs 20101007

site_start

Name: Site Start: NumberType

: 1Default

The ID of the resource you want to use as your homepage.

Make sure the ID you enter belongs to an existing Resource that has been published!

site_status

site_status

Name: Site Status: Yes/NoType

: YesDefault

If false, your visitors will see the 'Site unavailable message', and won't be able to browse the site.

Note that users with the 'view_offline' Permission (such as users in the Administrator group) will still be able to browse the site in offline mode.

site_unavailable_message

site_unavailable_message

Name: Site Unavailable Message: StringType

:Default

Message to show when the site is offline or if an error occurs.

This message will only be displayed if the option is set to No.site_status

site_unavailable_page

site_unavailable_page

Name: Unavailable Page: NumberType

: 1Default

Enter the ID of the Resource you want to use as an offline page here.

Make sure this ID you enter belongs to an existing resource that has been published!

strip_image_paths

strip_image_paths

Name: Rewrite Browser Paths: Yes/NoType

: YesDefault

Page 88: ModX Revolution Docs 20101007

If this is set to 'No', MODx will write file browser resource src's (images, files, flash, etc.) as absolute URLs. Relative URLs are helpful should youwish to move your MODx install, e.g., from a staging site to a production site. If you have no idea what this means, it's best just to leave it set to'Yes'.

This setting is in MODx Revolution and is no longer in use.deprecated

tree_root_id

tree_root_id

Name: Tree Root ID: StringType

:Default

Set this to a comma-separated list of valid IDs of Resources to start the left Resource tree at below those nodes as the root. The user will only beable to see Resources that are children of those specified Resources.

udperms_allowroot

udperms_allowroot

Name: Allow Root Resource Creation: Yes/NoType

: NoDefault

If true, allows users to create new resources in the root of the site.

This setting is in MODx Revolution. It has been replaced by the 'new_document_in_root' in thedeprecated PermissionAdministrator Policy.

unauthorized_page

unauthorized_page

Name: Unauthorized Page: NumberType

: 1Default

The ID of the resource you want to send users to if they have requested a secured or unauthorized resource.

This will only work if you have a 'load' Permission (via a Load policy or custom policy) set to the context that the Resource being accessed is in.

Make sure the ID you enter belongs to an existing resource that has been published and is publicly accessible!

upload_maxsize

upload_maxsize

Name: Maximum Upload Size: NumberType

: 1048576Default

The maximum file size that can be uploaded via the file manager. Upload file size must be entered in bytes.

Large files can take a very long time to upload. Also ensure that your PHP setup can handle large files in its max post sizesetting in the php.ini.

Page 89: ModX Revolution Docs 20101007

use_alias_path

use_alias_path

Name: Use Friendly Alias Path: Yes/NoType

: NoDefault

Setting this option to 'yes' will display the full path to the document if the document has an alias.

For example, if a document with an alias called 'child' is located inside a container document with an alias called 'parent', then the full alias path tothe document will be displayed as '/parent/child.html'.

use_browser

use_browser

Name: Use File Browser: Yes/NoType

: YesDefault

If set to Yes, enables the resource browser. This will allow your users to browse and upload resources such as images, flash and media files onthe server.

This setting is in MODx Revolution. Use the file_tree and file_manager instead.deprecated Permissions

use_editor

use_editor

Name: Enable RichText Editor: Yes/NoType

: YesDefault

If Yes, will enable any installed Rich Text Editor in the manager.

use_multibyte

use_multibyte

Name: Use Multibyte Extension: Yes/NoType

: Determined at InstallDefault

Set to true if you want to use the mbstring extension for multibyte characters in your MODx installation. Only set to true if you have the mbstringPHP extension installed.

Turning this on will use the setting for the charset in the mb_ PHP functions.modx_charset

welcome_screen

welcome_screen

Name: Show Welcome Screen: Yes/NoType

: NoDefault

If set to true, the welcome screen will show on the next successful loading of the welcome page, and then not show after that.

which_editor

which_editor

Name: RichText Editor to Use

Page 90: ModX Revolution Docs 20101007

1.

2.

: Richtext ComboType:Default

Selects which rich text editor to use when editing Resources. You can download and install additional Rich Text editors from Package.Management

which_element_editor

which_element_editor

Name: Which Element Richtext Editor: Richtext ComboType

:Default

Select which RTE you would like to use when editing an Element.

Using Friendly URLs

Summary:

You can have firendly URLs fully functioning in under two minutes by following a simple three step process:

1) Working .htaccess sample

MODx supplies an ht.access file for you to edit to match your server settings. This file will need to renamed to .htaccess when uploaded to theroot of your site (can be anywhere above the MODx installation or at the top of the site). You can also simply cut and paste this one into any texteditor and edit it accordingly:

change the DOMAINNAME to your domain name in lowercase.For me: shawnwilkersonchange the TLD to the com, net, org, info, whatever you haveFor me: com

# Friendly URLs PartRewriteEngine OnRewriteBase /RewriteCond %{HTTP_HOST} .# Force all pages to go to www.domain.com SEOforRewriteCond %{HTTP_HOST} !^www\.DOMAINNAME\.TLD [NC]RewriteRule (.*) http://www.DOMAINANME.TLD/$1 [R=301,L]# Friendly URLsRewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule ^(.*)$ index.php?q=$1 [L,QSA]# Additional Settings FollowExpiresActive OnExpiresByType image/gif A2592000ExpiresByType image/jpeg A2592000ExpiresByType image/png A2592000BrowserMatch brokenvary=1"MSIE"BrowserMatch brokenvary=1"Mozilla/4.[0-9]{2}"BrowserMatch !brokenvary"Opera"SetEnvIf brokenvary 1 force-no-vary

/htdocs is fine or /public_html or what ever. your server usesThe .htacess has to be at the same level as the main index.php or above the document MODx is presenting.

Be aware some control panels like to write their own .htaccess just above the site level so the best place to put it is where thehome page of the site points to (view image above)

Page 91: ModX Revolution Docs 20101007

The RewriteBase should end with a /

This works fine for Redhat Linux 5 / Apache setups. If it is not working for you contact your hosting provider -- send them this code and ask themwhat you need to get it working. Italicized content left to show entire file, but is not necessary for Friendly URLS.

2) Configure MODx Revolution

Next change the settings in the Friendly URLs Area of the System Settings in the System menu of the Revolution Manager to something like thefollowing image indicates, changing the "Automatically generate alias" to YES from the default NO (shown below).

I personally had issues with linking directly to my resume.pdf file so I turned off . More than likely it was something Iautomatically generate aliaswas not doing correctly, as my resume was the first thing I did after turning on Friendly URLS and even before building the first page or templates.

3) Edit your template(s)

Make sure you have the following between the  <head></head> tags:

<base href= />"[[!++site_url]]"

4) Clear the MODx Revolution cache

And you're done!

Contexts

Contexts allow MODx configuration settings to be overridden, extended, isolated, or shared across domains, sub-domains, sub-sites, multi-sites,cultural-specific sections, specific web applications, etc.

You can easily create a context from the Contexts menu under Tools. The context will then show up in your resource tree. Resources can easilybe dragged between contexts to move them from one context to another.

Note: there's nothing fundamentally about resources in different contexts, except that they now inherit the configurationdifferentsettings of the context they are in. So, if you create a new context, you'll have to override the context settings in the context forany real, distinguishable change to appear.

Creating a Context

First, go to the Contexts page, via System -> Contexts. Then, click on "Create New" in the grid. This will prompt you for a key and description.From there, right-click on your newly-created context, and click "Update Context".

This will bring you to a screen displaying the Context, and an empty grid of settings. From here you can add Context-specific settings that willoverride any System Settings. Your new context will be completely empty, requiring you to include any and all settings you will be using.

Page 92: ModX Revolution Docs 20101007

See Also

Creating a Subdomain from a Folder using Virtual Hosts

This case study will show an example usage of Contexts to create a separate subdomain manageable in a single Revolution install. We're goingto create a subdomain at dev.modxcms.com (of course, not really, but you get the idea).

Creating the Context

First off, go to System -> Contexts. Then, create a new context. We'll call it "dev".

Go ahead and create a "Dev Home" Resource in the Resource tree to the left. Place it in the root of the "dev" context. Also, while you're at it,create a "Dev Docs" Resource as well with an alias of "documentation". We'll use this to test our context links.

Your tree should look something like this:

From there, go ahead and right-click on the "dev" Context in the tree, and click "Edit Context". From here we'll see a Context Settings tab. Click onit, and you'll need to add a few settings:

site_start - Set this to the ID of your "Dev Home" resource.base_url - Set this to "/" (no quotes) since we're making the root of the URL our base.http_host - Set this to "dev.modxcms.com" (or your subdomain name)site_url - Set this to "http://dev.modxcms.com/" (or your subdomain url). Don't forget the trailing slash. Remember this setting is(scheme+http_host+base_url).

You can add other context-specific settings, such as error_page, unauthorized_page, and others if you so choose.

Note: If you're going to be linking back to the 'web' context from this context, you'll want to add those same Context Settings(with 'web'-specific values, of course) to the 'web' context. This allows MODx to know where to redirect 'web' context URLs backto.

After creating the settings, clear your site cache.

Creating the Virtual Host

Now we need to do some Apache work. (If you're not using Apache, you can at least follow the same idea and customize it to your server.) Go toApache's httpd.conf file, and add these lines, changing where necessary for your domain name:

NameVirtualHost dev.modxcms.com<VirtualHost dev.modxcms.com> ServerAdmin [email protected] DocumentRoot /home/modxcms.com/public_html/dev ServerName dev.modxcms.com ErrorLog logs/devmodxcms-error_log TransferLog logs/devmodxcms-access_log</VirtualHost>

Page 93: ModX Revolution Docs 20101007

Some Apache installs prefer you to put the IP address of the server in the VirtualHost and NameVirtualHost parameters - this isfine; the important field is the ServerName.

Obviously, if you're creating a different subdomain than dev.modxcms.com, you'd want to change these values.

Great! Restart your server (apachectl graceful).

The Subdomain Files

Now we're going to need to create the actual files to load the subdomain. Go create a "dev/" subdirectory in /home/modxcms.com/public_html/ (orwhatever base path your webroot is in).

You'll need to copy 3 files from your MODx Revolution's root directory:

index.php.htaccessconfig.core.php

Copy those to the dev/ directory.

Now, you'll need to edit a couple of them.

index.php

Edit index.php, and find this line (near the end):

$modx->initialize('web');

Change 'web' to 'dev'. Save the file and close.

.htaccess

You'll only need to edit one line here (and maybe not at all). Find this line (near the top):

RewriteBase /

Make sure that's set to /, not anything else. It should match the context setting you set up earlier.base_url

Final Steps

Clear your site cache again, refresh the Resource tree, and click 'Preview' on your "Dev Home" document. You should now be showing the pageat the following URL:

http://dev.modxcms.com/

Create a [[~135]] link to the "Dev Docs" Resource in the "Dev Home" Resource. Reload your page. Note the link properly builds to:

http://dev.modxcms.com/documentation.html

And you're done!

See Also

Contexts

Using One Gateway Plugin to Manage Multiple Domains

You have a choice when sharing a single database and manager across multiple domains. You can choose to use the primary front-end context(known as 'web') to handle all domains or you can create a unique gateway file for each domain to directly initialize a specific context. If you use asingle gateway, you would use a plugin to switch contexts registered to the OnHandleRequest event, something like so:

Page 94: ModX Revolution Docs 20101007

<?php ($modx->getOption('http_host')) {switch

'domain2.tld:80':case 'domain2.tld':case // the http_host is of a specific domain, the contextif switch$modx->switchContext('domain2.tld'); ;break :default // by , don't anythingdefault do

;break}?>

Alternatively, you would simply copy the index.php file from the default web context (along with the core.config.php and .htaccess for rewrite rulesaltered appropriately) to another directory and change the line

$modx->initialize('web');

to

$modx->initialize('aContextNameOfYourChoice');

Note that you could also just copy the index.php in the same directory and rename it to do this, but your rewrite rules would have to be smartenough to route requests to the appropriate context gateway, and you would need to configure the request_controller option in Context Settingsappropriately.

You can also still use a custom core location in either of these scenarios; this is independent of the context-driven multi-site capabilities.

Customizing the Manager

What is Form Customization?What are Rules?What Forms can I Customize?ExamplesSee Also

What is Form Customization?

Form Customization is a new feature that allows users to create Rules, which govern how manager pages render their forms in the MODxRevolution Manager. It is similar to ManagerManager in MODx Evolution.

What are ?Rules

Rules in MODx Revolution are simply generic rules that apply to any (manager page). They also can be tied to User Groups, wherein aActionRule will only be applied if the User is part of that User Group.

A rule can be one of the following:

What Forms can I Customize?

Technically any manager page can be customized. Form Customization bases its methods off of , which are database representations ofActionsany MODx Revolution Manager page. This also means that can also have Rules applied to them, should the CMPs beCustom Manager Pagesusing .MODExt

A full list of documented customizable forms, along with their fields and other info, can be found here:

Page 95: ModX Revolution Docs 20101007

Examples

An example set of Rules:

will make the Resource Update page look like so:

and TV part look like:

See Also

Form Customization Pages

Documented Form Customization Pages

FC-Resource

Resource Create/UpdateAvailable FieldsAvailable TabsHiding the Content FieldTVs

This page is under construction.

Resource Create/Update

These pages encompass the following Actions:

resource/updateresource/create

Available Fields

Field Name Containing Panel

Page Title pagetitle modx-panel-resource

Page 96: ModX Revolution Docs 20101007

Published published modx-panel-resource

Long Title longtitle modx-panel-resource

Description description modx-panel-resource

Introtext introtext modx-panel-resource

Link Attributes link_attributes modx-panel-resource

Alias alias modx-panel-resource

Menu Title menutitle modx-panel-resource

Menu Index menuindex modx-panel-resource

Hide from Menus hidemenu modx-panel-resource

Container isfolder modx-panel-resource

Rich Text richtext modx-panel-resource

Published On publishedon modx-panel-resource

Publish Date pub_date modx-panel-resource

Un-Publish Date unpub_date modx-panel-resource

Searchable searchable modx-panel-resource

Cacheable cacheable modx-panel-resource

Deleted deleted modx-panel-resource

Empty Cache syncsite modx-panel-resource

Content Type content_type modx-panel-resource

Content Disposition content_dispo modx-panel-resource

Class Key class_key modx-panel-resource

Available Tabs

These tabs are available for renaming/hiding:

Tab Name (ID) Containing TabPanel

Create/edit Resource modx-resource-settings modx-resource-tabs

Page Settings modx-page-settings modx-resource-tabs

Template Variables modx-panel-resource-tv modx-resource-tabs

Access Permissions modx-resource-access-permissions modx-resource-tabs

Hiding the Content Field

Use these settings:

Field: modx-resource-content: modx-panel-resourceContaining Panel

: Field VisibleRule: 0Value

TVs

Affecting TVs for a Resource is fairly straightforward - just set the "Name" attribute of the Rule to "tv#", and replace # with the ID of the TV you'dlike to affect. You can leave the Containing Panel blank.

FC-Template

Page 97: ModX Revolution Docs 20101007

This page is under construction.

FC-Chunk

This page is under construction.

FC-Snippet

This page is under construction.

FC-Plugin

This page is under construction.

Form Customization Rules

What is a Rule?What are the Rules available?Creating a RuleConstraintsSee Also

What is a Rule?

Rules in MODx Revolution are simply generic rules that apply to any Action (manager page). They also can be tied to User Groups, wherein aRule will only be applied if the User is part of that User Group.

What are the Rules available?

The available Rules are:

Creating a Rule

First off, go to the Form Customization page, under the Security main menu. From there, click "Add" in the grid's toolbar. You'll be presented witha window:

Page 98: ModX Revolution Docs 20101007

Let's go into the fields.

Field Description Optional

Action This field lets you select any available . The rule will only apply to that Action, and no other.Action No

User Group Here you can optionally choose a to tie this Rule to. If a User Group is chosen, the Rule will only applyUser Groupto of that User Group.Users

Yes

Description An optional, for you, description of the Rule. Yes

Field The name of the field or tab to apply the Rule to. No

ContainingPanel

The name of the containing panel that the Field or Tab exists in. Most all Rules will need this value. No

Value The value you'd like to set the Rule to. The type of value can vary depending on the Rule. No

ConstraintClass

If set, will restrict the Rule to a field value (via Constraint Field and Constraint) on this class. Example: modResourcefor the Resource Update screen.

Yes

ConstraintField

If set, will restrict the Rule to the field specified, with the value of Constraint Yes

Constraint If set, will restrict the Rule to the value of the field in the object specified in the constraint options. Yes

Constraints

Page 99: ModX Revolution Docs 20101007

Rule Constraints are special abilities that let you restrict the Rule to a certain value on an object's field. Let's say you want to restrict a Rule forresource/update to only occur on Resource's with a Template ID of 4. You'd simply set the Constraints like so:

Constraint Class: modResourceConstraint Field: templateConstraint: 4

Or, further, if you wanted to restrict the Rule to Resources with a menutitle of "boo":

Constraint Class: modResourceConstraint Field: menutitleConstraint: boo

Constraints allow a superior level of flexibity to .Form Customization Rules

See Also

Field Default

The Field Default Rule

The Field Default Rule, when set, will automatically set the default value of a field.

This will only work on "create" pages, "update" pages.not

Examples

An example Rule of setting the default Category for a for all in the User Group HR Department would look like this:Snippet Users

Page 100: ModX Revolution Docs 20101007

See Also

The root page Form Customization could not be found in space MODx Revolution 2.0.

Field Label

The Field Label Rule

The Field Label Rule, when set, will change a Label of a field to any text value.

Examples

An example Rule of changing the introtext's label to "Comments" for the in the "Marketing" would look like this:Users User Group

Page 101: ModX Revolution Docs 20101007

See Also

The root page Form Customization could not be found in space MODx Revolution 2.0.

Field Visible

The Field Visible Rule

The Field Visible Rule, when set, will declare a field "visible" or not to a user.

Examples

An example Rule of hiding the introtext field from the in the "HR Department" would look like this:Users User Group

Page 102: ModX Revolution Docs 20101007

See Also

The root page Form Customization could not be found in space MODx Revolution 2.0.

Move TV to Tab

The Move TV to Tab Rule

The Move TV to Tab rule will move any TV to the tab you specify.

Usage

Specify the ID of the tab to move to in the "name" field of the Rule. Then specify the TV's ID prefixed with 'tv' in the "value" field.

The list of available tabs is:

ID Description

modx-resource-settings The first tab, or Create/Edit resource tab.

modx-page-settings The second tab, or Page Settings tab.

You can also create a tab with the rule and move a TV there.New Tab

Page 103: ModX Revolution Docs 20101007

Examples

An example rule for moving the TV 1 to the first tab in the Resource create page would look like so:

See Also

New Tab

The New Tab Rule

The New Tab Rule, when set, will create a new tab in the panel.

Usage

Specify the ID of this new tab in the "Name" field.Specify the tabpanel ID in the "Containing Panel" fieldSet the Rule to "New Tab"Set the title of the new tab in the "Value" field

Available TabPanels

Here are the IDs for the corresponding tab panels on various manager pages.

Page 104: ModX Revolution Docs 20101007

ID Corresponding Page

modx-resource-tabs The Resource edit/create page.

modx-chunk-tabs The Chunk page.

modx-snippet-tabs The Snippet page.

modx-plugin-tabs The Plugin page.

modx-template-tabs The Template page.

modx-tv-tabs The Template Variable page.

modx-user-tabs The User page.

modx-usergroup-tabs The User Group page.

modx-context-tabs The Context page.

Tab Panels on non-Resource pages are only available in 2.0.0-pl and up.

Examples

An example rule for creating a new tab in the Resource edit page would look like so:

See Also

The root page Form Customization could not be found in space MODx Revolution 2.0.

Page 105: ModX Revolution Docs 20101007

Tab Title

The Tab Title Rule

The Tab Title Rule will change the title of any Tab.

Usage

The values for the Rule should be as follows:

Name: The ID of the tab to change.Containing Panel: The ID of the tabpanel to change.Rule: Tab TitleValue: The new text to change the tab title to.

For a list of tabs available for each page, see .Form Customization Pages

Examples

An example Rule of changing the title for the Page Settings tab for all to "Custom Fields" would look like this:Users

See Also

Page 106: ModX Revolution Docs 20101007

The root page Form Customization could not be found in space MODx Revolution 2.0.

Tab Visible

The Tab Visible Rule

The Tab Visible Rule, if set to 0, will hide a tab from a User.

Examples

An example Rule of hiding the Page Settings tab for all would look like this:Users

See Also

The root page Form Customization could not be found in space MODx Revolution 2.0.

TV Default

The TV Default Value Rule

Page 107: ModX Revolution Docs 20101007

The TV Default Value Rule, if set, will set the default value for a TV.

This only works on "create" Actions, "update" Actions.not

Usage

The values for the Rule should be as follows:

Name: The ID of the TV prefixed with 'tv'; for example, for the TV with ID 23, 'tv23'Containing Panel: 'modx-panel-resource'Rule: 'TV Default Value'Value: The value you want to set as the default.

Examples

An example Rule of setting the default value for a TV with ID 23 to "test" is:

See Also

The root page Form Customization could not be found in space MODx Revolution 2.0.

TV Title

Page 108: ModX Revolution Docs 20101007

The TV Title Rule

The TV Title Rule will change the title of a TV.

Examples

An example Rule of setting the label to "Boo!" for a TV with ID of 1 for all would look like this:Users

See Also

The root page Form Customization could not be found in space MODx Revolution 2.0.

TV Visible

The TV Visible Rule

The TV Visible Rule, if set to 0, will hide a TV from a User.

Examples

An example Rule of hiding the a TV with ID of 1 for all would look like this:Users

Page 109: ModX Revolution Docs 20101007

See Also

The root page Form Customization could not be found in space MODx Revolution 2.0.

Security

Security in MODx Revolution

Security in MODx Revolution is primarily driven by an Attribute-Based Access Control (ABAC) paradigm.

Each user in MODx has a object, which can be assigned to any number of . Each User Group then has attributes assigned to itUser User Groupsvia (ACLs). These ACLs take a variety of names depending on how they are applied, but all share one common principle -Access Control Liststhey contain a list of . These Permissions allow access to different areas or actions within MODx.Permissions

ACLs usually have the following:

Principal - The object that is getting the access permissions. This is in MODx, by default, a User Group.Target - The object they apply to, for example, a Context or Resource Group.Access Policy - The list of Permissions that is gained by this ACL.Authority - The minimum Authority level required to use this ACL (see ).Roles

Access is in MODx, meaning that access is "open" by default. Once an ACL is applied to an object, such as aallow/denyContext or Resource Group, those Contexts or Resource Groups will now only be accessible to the objects with appropriatePermissions.

Security Tutorial Video

Demonstrates by applying concepts to the MODx Sample Site to:

Restrict RSS feed to Directors and upRestrict Blog to Staff onlyCreate a 'secure' context for Directors and up onlyRestrict some element categories to administrators only

Example: Context Access

A good example is creating a Context named 'test', and assigning an ACL to it. This can be done by editing the Context, and going to the 'AccessPermissions' tab. From here, you can give a User Group (say, 'HR Dept') explicit access to this Context by selecting the User Group, the

Page 110: ModX Revolution Docs 20101007

'Administrator' Access Policy, and specifying a required Authority (say, 9999 for 'Member') to have:

This will restrict the 'test' Context to users who are a Member (or with more authority) of the 'HR Dept' User Group.Role

See Also

Users

What is a User?User SettingsUsers in the Front-EndUser FieldsGrabbing the User via the APISee Also

What is a User?

A User is simply a representation of a login in MODx Revolution.

Users can also be assigned to User Groups, which can have attached to them to provide Access Controls.ACLs

User Settings

User Settings in MODx Revolution will automatically override for that user any System or Context settings with the same key. They can also becompletely unique settings as well. The order of inheritance for Settings is:

System Settings -> Context Settings -> User Settings

Users in the Front-End

When a user is logged into the frontend of your site, their username and ID can be accessed by the following :Properties

[[+modx.user.id]] - Prints the ID[[+modx.user.username]] - Prints the username

If a user is not logged in, ID will be blank, and Username will be "(anonymous)".

User Fields

Users contain the following fields:

Name Description

id The ID of the user.

username The username of the user.

Page 111: ModX Revolution Docs 20101007

password The user's encrypted password.

active Either 1 or 0. If not active, the user will not be able to log in.

remote_key A remote user Key used by remote authentication apps.

remote_data A JSON array of data used by remote authentication apps.

Users also have a Profile attached to them. It contains the following fields:

Name Description

internalKey The ID of the user.

fullname The full name of the user.

email The email of the user.

phone The phone number.

mobilephone The cellphone number.

fax The fax number.

blocked Either 1 or 0. If blocked is set to true, the user will not be able to log in.

blockeduntil A timestamp that, when set, will prevent the user from logging in until this date.

blockedafter A timestamp that, when set, will prevent the user from logging in after this date.

logincount The number of logins for this user.

lastlogin The last time the user logged in.

thislogin The time the user logged in in their current session.

failedlogincount The number of times the user has failed to log in since last logging in.

sessionid The User's session ID that maps to the session table.

dob The date of birth.

gender 0 for neither, 1 for male and 2 for female.

address The physical address.

country The country of the user.

city The city of the user.

zip The zip or postal code for the user.

state The physical state or province of the user.

photo An optional field for a photo. Not used in the UI.

comment An optional comment field for comments on the User.

website The website of the user.

extended A JSON array that can be used to store extra fields for the User.

Grabbing the User via the API

The current user can be gotten in the API via the $modx->user reference. For example, this snippet outputs the username of the user:

return $modx->user->get('username');

Note that to grab Profile fields, you'll need to first get the modUserProfile object via the Profile alias. For example, this snippet grabs the email ofthe user and returns it:

Page 112: ModX Revolution Docs 20101007

$profile = $modx->user->getOne('Profile'); $profile ? $profile->get('email') : '';return

If the User is not logged in, $modx->user will still be available as an object, but will return 0 as the ID and (Anonymous) as the username.

See Also

User Groups

What is a User Group?

A User Group is simply a collection of Users.

Usage

Go to Security -> Access Controls. From there you will see a tree of User Groups and their respective Users. You can assign a User to a UserGroup by right-clicking on the User Group and either:

Adding the User via the context menu itemEditing the User Group and adding a User on the grid there

Assigning Policies

A quick clarification on which policies to use:

Policies assigned on the Context Access tab should be based on the standard Administrator policy.Policies assigned on the Resource Group Access tab should be based on the standard Resource policy.Policies assigned on the Element Category Access tab should be based on the standard Element policy.

Roles in User Groups

Users can have specific Roles within a User Group, should you choose. They can also exist in the User Group without a Role. Roles allow you tofine-tune your permissions more than in previous MODx versions.

Say you want to only allow Supervisors in the "HR Department" User Group access to some Resources; no problem. Just create a Role called"Supervisor", set its authority to some number below 9999 (let's say 3), and then add in the Users to the User Group "HR Department" (via theUser Group editing screen), setting any would-be supervisors to the Supervisor Role.

Then, you'll just add a Resource Policy (the packaged-in-with-modx one will do fine) to the Resource Group you want to restrict access to. It willlook something like this:

And you've got a role-based access permission! This specific ACL will limit all Resources (aka Documents) in the web context and in the resourcegroup "TestResourceGroup4" to only Users in the "HR Department" User Group with at least a Role of Supervisor. Roles with lower authoritynumbers would also inherit access - say you had a Coordinator Role with an authority of 2; Users in this User Group would have access to thisACL as well.

See Also

Resource Groups

Page 113: ModX Revolution Docs 20101007

What is a Resource Group?

A Resource Group is a collection of Resources, e.g. "Members Only" pages.

Usage

You can add or delete members of a Resource Group in two different ways:

Option 1

Go to Security -> Resource Groups. From there you will see a tree of Resource Groups and a tree of Resources.

then drag the Resources from the right tree directly into Resource Groups in the left tree:

Option 2

When you are editing a Resource directly, click on its "Access Permissions" tab, and check which Resource Groups it is a member of.

See Also

Roles

What is a Role?

Page 114: ModX Revolution Docs 20101007

A role is a position or status held within a certain situation. In MODx, it can be used to group Users into a position or status within a User Group,e.g. "Editor" or "Front-end Read Only".

Roles in MODx use an integer value called "Authority". E.g. a Role with Authority 10 will inheritLower numbers represent a stronger authority.any and all Group Policies assigned to itself and to any roles defined with Authority 11, but a user Role with Authority 11 does NOT inherit any ofthe Group Policies from Role 10.

Be sure you clarify your language when talking about Authority because this inverse relationship can lead to some confusing sentences.

It helps to think of "Authority" as ordinal numbers: first, second, third, etc. is the first authority and trumps Authority=1 (i.e. the second authority).Authority=2

You should generally avoid duplicate authority numbers.

Usage

One common example is to create Roles that mimic a basic employee position structure. Let's say we create the following Roles and Authoritylevels:

Administrator - 0Director - 1Coordinator - 2Supervisor - 3Employee - 9999

We can then create a User Group called "HR Department". Within that User Group, we'll assign Users to those Roles (you can have multipleUsers per Role, as well).

Now, let's say John has a Role of Coordinator. Mark has a Role of Supervisor. We're going to give Mark's "HR Deparment" User Group an AccessPolicy (which is a set of Permissions) called "AccountPolicy" that has the following Access Permissions in it:

view_accountssave_accounts

We've assigned this Policy to the "web" context for our User Group "HR Department". We then set its Minimum Role value to "Supervisor":

This means that Mark has these Permissions, since he's in the User Group, and has at least the Role of "Supervisor" (which is the Role he has,specifically).

But this means that John has these Permissions as well, since he is a "Coordinator" which has a stronger Authority level than "Supervisor".alsoSo, John as Coordinator has "inherited" the Permissions than Mark had as Supervisor.

See Also

Page 115: ModX Revolution Docs 20101007

Policies

What is an Access Policy?

An Access Policy is a set of containing one or many Permissions, as defined in the manager.Permissions

Creating and Editing

To create an Access Policy in the manager, navigate to the "Security" menu and select "Access Policies". From there you can add new policies.To edit an Access Policy in the manager, simply right-click the Policy you want to edit.

Usage

Policies can be used in a myriad of different ways. Here are 3 example usages that come by default in MODx:

Context Access

Access Policies can be assigned as (ACLs) to a Context and User Group, with a specified Minimum . When done, thisAccess Control Lists Rolemeans that all the Users in that User Group with at least the Role specified as the Minimum Role can use the Permissions in the Policy in theContext specified in the .ACL

MODx comes with a default that contains all the one would use in a Context ACL. It's best to duplicate this"Administrator" Policy Permissionspolicy when creating a custom access policy for restricting manager users.

Resource Group Access

They can also be Resource ACLs, that limit access to Resources based on Roles and Resource Groups. MODx comes packaged with a default that contains all the basic Permissions one would use in a Resource Group ACL."Resource" Policy

An example would be to assign the "Resource" policy to a Resource Group called 'HR Documents'. Then, you would give a User Group called"HR Department" access to this Resource Group via the Resource ACL:

This would restrict all Resources in the "HR Documents" Resource Group to Users only in the "HR Department" group.

Element Category Access

Elements can be restricted from view by ACLs on Categories. For example, if you had a User Group called 'Developers', and wanted Users in thatgroup to be the only Group that could see Elements in the Category 'Gallery', you would create an ACL like such, in the "Element CategoryAccess" tab when editing the User Group:

Page 116: ModX Revolution Docs 20101007

This would allow only Users in the "Developers" User Group access to see Elements in the "Gallery" Category.

Examples

Here's an example custom policy:

and its permissions:

Any User that had access to this Policy would have the permissions 'view_accounts' and 'save_accounts'.

Page 117: ModX Revolution Docs 20101007

See Also

Permissions

What is a Permission?

A Permission in Revolution is simply a single access control that allows you to deny or allow access to a task. They are collected in Access into a list, which is called an Access Control List (or ACL). From there, the defines all the Permissions that the list contains.Policies Access Policy

An example Permission is "content_types" - if the Policy does not contain this Permission, then users with that Policy will not be able to view theContent Types page.

Usage

Permissions are assigned in Policies in access control lists. To do so, simply edit any available Access Policy, and from there you can view andmanage existing Permissions, as well as create new ones.

See Also

Permissions - Administrator Policy

The Administrator Policy

This policy is packaged into MODx and is given to users on the 'mgr' context who want to have full access to managing MODx content.

Default Permissions

Name Description of Access

about The About page.

access_permissions Any Access Permission-related pages and actions.

action_ok

actions The page.Actions

change_password User can change their user password.

change_profile User can change their profile.

content_types The page.Content Types

create Basic "create" access on objects.

credits View the Credits page.

customize_forms View and manage the page.Customizing the Manager

database The System Info page

database_truncate The ability to truncate a database table.

delete_category To delete or remove any Categories.

delete_chunk To delete or remove any .Chunks

delete_context To delete or remove any .Contexts

Page 118: ModX Revolution Docs 20101007

delete_document To delete or remove any .Resources

delete_eventlog To empty the Event Log.

delete_plugin To delete or remove any .Plugins

delete_snippet To delete or remove any .Snippets

delete_template To delete or remove any .Templates

delete_tv To delete or remove any .Template Variables

delete_role To delete or remove any .Roles

delete_user To delete or remove any .Users

edit_category To edit any Categories.

edit_chunk To edit any .Chunks

edit_context To edit any .Contexts

edit_document To edit any .Resources

edit_locked Allows a user to override a lock and edit a locked Resource.

edit_parser

edit_plugin To edit any .Plugins

edit_role To edit any .Roles

edit_snippet To edit any .Snippets

edit_template To edit any .Templates

edit_tv To edit any .Template Variables

edit_user To edit any .User

element_tree The ability to view the Elements Tree on the left nav.

empty_cache To empty the site cache.

export_static To export the site to static HTML.

file_manager To use the file manager, including creating/deleting files.

file_tree To view the Files Tree on the left nav.

flush_sessions Can flush Sessions across the site.

frames To use the MODx Manager UI at all.

help To view the Help page.

home To view the Welcome page.

import_static To view or use the Import pages.

languages To edit or view Lexicon Languages.

lexicons To edit or view Lexicons and .Internationalization

list Basic permission to "list" any object. List means to get a collection of objects.

load Basic permission to "load" any object, or be able to return it as an instance at all.

logout To be able to logout as a user.

logs To view the logs, such as error and manager logs.

menus To edit or save any top Menu items.

messages To send or view any personal Messages.

namespaces To edit or view .Namespaces

Page 119: ModX Revolution Docs 20101007

new_category To create a new Category.

new_chunk To create a new .Chunk

new_context To create a new .Context

new_document To create a new .Resources

new_plugin To create a new .Plugin

new_role To create a new .Role

new_snippet To create a new .Snippet

new_template To create a new .Template

new_tv To create a new .Template Variable

new_user To create a new .User

packages To use any Transport Packages in the system.Package Management

property_sets To view and edit .Properties and Property Sets

providers To view and edit across the site.Providers

publish_document To publish or unpublish any Resource.

purge_deleted To empty the Recycle Bin.

remove Basic permission to remove any object.

remove_locks To remove all existing Locks throughout the site.

resource_tree To view the Resource Tree in the left nav.

save Basic save permission for any object.

save_category To save any Categories.

save_chunk To save any .Chunks

save_context To save any .Contexts

save_document To save any .Resources

save_plugin To save any .Plugins

save_role To save any .Roles

save_snippet To save any .Snippets

save_template To save any .Templates

save_tv To save any .Template Variables

save_user To save any .User

search To use the Search page.

settings To view and edit any System Settings.

steal_locks To "steal" locks, overriding a current lock on a document.

unlock_element_properties To be able to edit the default properties for any Element.

view Basic permission to "view" any object.

view_category To view any Categories.

view_chunk To view any .Chunks

view_context To view any .Contexts

view_document To view any .Resources

view_eventlog To view the Event Log.

Page 120: ModX Revolution Docs 20101007

view_offline

view_plugin To view any .Plugins

view_role To view any .Roles

view_snippet To view any .Snippets

view_template To view any .Templates

view_tv To view any .Template Variables

view_unpublished To view any unpublished .Resources

view_user To view any .User

workspaces To utilize .Package Management

See Also

Permissions - Resource Policy

The Resource Policy

This policy is packaged into MODx and is given to users on any context who want to have basic object access to content. The Permissions aregeneric and apply across all MODx objects.

Default Permissions

Name

add_children

create

delete

list

load

move

publish

remove

save

steal_lock

undelete

unpublish

view

See Also

ACLs

What is an ACL (Access Control List)?Usage

Page 121: ModX Revolution Docs 20101007

Context ACLResource ACL

See Also

What is an ACL (Access Control List)?

An ACL, or Access Control List, is a set of attached to an object. More information on ACLs can be found .Permissions here in Wikipedia

Usage

In MODx, ACLs can be applied to any modAccessibleObject. Primarily MODx Revolution 2.0 allows for ACLs on Resources and Contexts.

Context ACL

A Context ACL is referenced of 4 parts:

A ContextA User GroupA Minimum RoleAn Access Policy

This means that one can assign a ACL to a Context that will apply to:

All the Users in a User Group...with at least the Minimum Role specified...that will give the Users all the Permissions in the Access Policy assigned.

Resource ACL

Resource ACLs behave a bit differently, and basically allow you to restrict access to Resources (such as Documents, Weblinks, etc) by ResourceGroups. They are comprised of 5 Parts:

A Resource GroupA User GroupA Minimum RoleAn Access PolicyA Context

This means that an ACL applied to a Resource Group will:

Effect all the Users in the specified User Group... with at least the Minimum Role specified... give the Resource Permissions (save, load, delete, etc) in the Policy specified... to all the Resources in the Resource Group

See Also

Security Tutorials

Security Tutorials

Here are some tutorials designed to help you get started with Security in MODx Revolution.

Giving a User Manager Access

The Problem

You want a User to have manager editing access, but not have all the of an Administrator user. This tutorial, partially written byPermissionsBobRay, will help you through that.

Page 122: ModX Revolution Docs 20101007

1. 2. 3. 4. 5. 6.

a. b.

7.

1. 2. 3. 4.

5. 6. 7.

The Solution

First off, create your user. Then:

Create a new role (say, Editor) with an authority of say, 10.Add the User to the admin group with a role of EditorIn Access Controls | Policies, duplicate the administrator policy and rename it to whatever you want, say "AdminLite".Edit the AdminLite Policy to use whatever you want the User to have.PermissionsIn Access Controls | User Groups, right click on the admin group and select "Update Group."On the Context Access tab, add two new ACL entries to the grid:

Context: 'mgr' Minimum Role: 'Editor', Access Policy 'AdminLite'Context: 'web' Minimum Role: 'Editor', Access Policy 'AdminLite'

Click on Security -> Flush Sessions and re-login.

See Also

Making Member-Only Pages

IntroductionStep-by-step explanation

1. Create a Resource Group2. Link your member-only resource to the Resource Group3. Create a User Group4. Add Context access5. Add Resource access6. Add users to the user group7. Flush permissions

Help! I can't get this to work, still!See Also

Work in progressPlease note that this document is a work in progress and may still be inaccurate. It should, however, be possible to set up amember only page using this documentation.

Introduction

MODx Revolution uses a whole new set of security systems to allow you more flexibility while giving your users access (or denying) to Managerand Web resources. As there seems to be need for a proper tutorial to get you into the basics of working with this advanced system this documenthas been written.

For those that are savvy enough, below follows a simple list to help you through the maze or to remind you how it works. If you need moreinformation and would like some examples, scroll down to the related subsection below.

Create a Resource Group (Security -> Resource Groups -> Create Resource Group)Link your member-only resource to the Resource Group. (By editing the resource, or by dragging them from the resource tree to the right)Create a User Group (Security -> Access Controls -> User Groups -> New User Group)Edit the user group you created to add Context Access (Security -> Access Controls -> User Groups -> Right click your user group -> onthe Context Access tab add context "web", minimum role 'Member (9999)', access policy 'Resource' (if you want to modify permissions,duplicate that policy. Do not edit it directly!))Add a resource group entry on the Resource Group Access tab (context: web, minimum role: Member (9999), access policy: resource)Add users to the user group with the role of Member. (Security -> Manage Users)Flush permissions (Security -> Flush Permissions) and try it in another browser (not just another browser window: another browser)

Step-by-step explanation

Work in progressThis section is still being worked on and may be incomplete or incorrect.

If you're not quite as savvy, or would rather also know what happens when you set a certain permission or make an access entry, you might findthis section interesting.

1. Create a Resource Group

Page 123: ModX Revolution Docs 20101007

1. 2. 3. 4. 5.

A is a collection of resources which you can link to user groups and access list entries. When you have created a resource group,resource groupyou can easily classify pages to be only visible for certain user groups, or roles within user groups.

To create a resource group, navigate to Security -> Resource Groups and click on the Create Resource Group button. In the popup you areprompted to enter a name for the resource group. In the tutorial we expect you named it "Protected".

2. Link your member-only resource to the Resource Group

Now that you have a resource group, you should add resources to it. There are two ways to achive this.

First of all, you can go to Security -> Resource Groups and drag resources from the right resource tree to the left resource groups ("Protected").The second option is editing your resource, and ticking the right box on the "Access Permissions" tab.

It is important to realize that as soon as you have protected a resource by assigning it to one or more resource groups, those pages will no longershow up for users that are not linked to the resource group. The default behaviour in that case is displaying the 404-error page. If you wouldrather return the 403-error, you will need to give the anonymous user group "load" permission for the resource group. More about this in a latertutorial. At this moment in the tutorial, your page will not be visible as you have not yet added it to a user group.

3. Create a User Group

You have a resource group with resource applied to them, now you'll need to decide who will be able to view the resources. For this, we'll make anew user group.

To do this, go to Security -> Access Controls. On the (default) User Groups tab, click on the New User Group button. Choose a name for thegroup, and submit the form.

4. Add Context access

At this point the user group means nothing, it has zero access. To start with, we'll add context access to the user group. When a user group hasaccess to a context, it can view (unprotected) resources within that context.

While still being on the Access Controls page, viewing the User Group tab, right click the user group you just made and click on "Update UserGroup". You will find five different tabs:

General Information: this contains the name and if applicable the parent group.Users: shows an overview of users in the user group and offers you to add new users.Context Access: we will discuss this in a minute.Resource Access: we will discuss this in step five.Element Category Access: will not be covered in this tutorial, but can be used to limit access to elements.

Go to the Context Access tab again. At the moment it should still be empty, so the user has no access to any contexts. Click on "Add Context".

As we want our users to be able of accessing the "web" context (that means your resources in the Web context), select "web" from the contextdropdown. The Minimum role refers to the role the user should have within the user group to receive the access to the context. As we want all users, we'll setthis to Member (9999). Note that the number refers to the authority: a user at authority 20 will receive all access list entries that require a role withan authority of 20, 21, 22...9998, 9999. To make it applicable to all users in that group, choose an authority level of 9999.The Access Policy is key in this form. That determines what a user can actually do. As with everything MODx, this is highly flexible. Per defaultthere are several Access Policies added. In this case, we'll set it to Resource. This Access Policy includes all default permissions for resourceaccess. If you ever want to change some of the permissions (which may be covered in a different tutorial or article) always duplicate the accesspolicy and don't modify it directly, as there's no way to recover changes made.

So, to sum up, apply this context access:

Context: webMinimum role: Member (9999)Access Policy: Resource

Now, your user group has access to your Web context, as long as access to resources is not being blocked by resource groups.

5. Add Resource access

Move on to the Resource Access tab. This tab defines the resources your user has access to if they are protected by resource groups. Three outof four fields are similar to the Context Access groups, namely the Context, Minimum Role and Access Policy. A new one is Resource Groupwhich, as you probably guessed, defines the resource group the user group can access.

The settings:

Resource Group: whatever you named it, for example "Protected"Context: webMinimum role: Member (9999)Access Policy: Resource

Page 124: ModX Revolution Docs 20101007

6. Add users to the user group

Now add some users to the user group. You can do this by editing the user, or by going back to the Users tab and adding them from there. It willask for the User Group, as well as the Role. As we assumed the Member role with an authority of 9999, you can simply use that one.

When using a websignup snippet, make sure it automaticly puts them in the right user group.

7. Flush permissions

Now that all settings are done, you will need to flush permissions (Security -> Flush Permissions) before you will see an effect. Also make surethat, if you go to test it front-end, you use a different browser all together. Don't use a different tab or browser window, as it will still use yourManager login to check for permissions.

Please note that in some cases it is also neccesary to clear the site cache, specifically for the mgr (manager) context, as elements and resourcesmay cache their permissions.

Help! I can't get this to work, still!

Make sure you followed everything step by step and that you flushed permissions properly. If everything seems to be alright, check again andthen go to the Forums to ask for help. If you think the tutorial is misleading or inaccurate, please visit the forum topic (linked below) and post aboutwhat is incorrect so it can be fixed.

See Also

Bob's permissions guide: http://bobsguides.com/revolution-permissions.html

Forum topic discussing this tutorial: http://modxcms.com/forums/index.php/topic,51259.0.html

Security: http://svn.modxcms.com/docs/display/revolution/Security

Installing a Package

Installing a Package

This page will guide you through the process of installing a Package via .Package Management

Downloading packages through requires cURL or PHP Sockets. MODx will let you know if you don'tPackage Managementhave either of these. If you are still having problems with Package Management after confirming these are installed, see

.Troubleshooting Package Management

Go to System -> .Package Management

Page 125: ModX Revolution Docs 20101007

Then click the Download Extras link.

Browse the available packages, opening the folders to expose the individual packages. Click Download to download whichever packages you'dlike to download. You may download multiple packages at one time.

Page 126: ModX Revolution Docs 20101007

The package will be downloaded to the proper directories in your MODx installation. Now you can view your new package, and click Install tochoose to install it.

Providers

You can select the location from which to download packages, add a new location, or select packages on your local machine. Use the Add NewPackage link, to the left of the Download Extras link. By default, the modxcms.com/extras repository is available as a remote provider.

Manual Installation

If you prefer, you can manually copy the package into the core/packages directory. The package must be a transport.zip archive, such aswayfinder-2.1.1-beta1.transport.zip. Then, click on 'Add New Package' in the packages grid. From there, select the 'Scan Local' option. Thepackage will now be visible in the Packages list, and you can install it as usual, by right-clicking and selecting Install Package from the pop-upmenu.

See Also

Troubleshooting Package Management

Troubleshooting Package Management

This page is dedicated to problems with Package Management, specifically with downloading and installing packages.

Most issues can be resolved by making sure you have cURL installed, and that the core/packages/ directory is writable by PHP.

Page 127: ModX Revolution Docs 20101007

Upgrading MODx

Upgrading MODx Revolution 2.0

This document assumes you are upgrading from a standard install. For Git users, please see .Git Installation

Uploading the Files

For traditional distribution users, simply upload the files over the existing ones, and then run setup. For the advanced distribution, do the same,but you'll only need to do so for the core/ and setup/ directories.

Make sure that you don't overwrite core/config/config.inc.php, and that it's writable.

Beginning Setup

Simply follow the upgrade process, selecting whichever upgrade you want to perform (normal or database).

If you are upgrading using the distribution, make sure you have the "Core Package has been manually unpacked" and "Files in-place"Advancedcheckboxes unchecked, and that the core/, manager/ and connectors/ directories are writable.

If you get errors during setup, please read .Troubleshooting Installation

After Setup

Make sure to remove the setup/ directory via the last option after setup has completed, so that no one can run setup after you and possibly breakyour site.

Version-Specific Changes

For changes relating to specific versions, please see the following pages:

For Upgrades Coming From Prior to 2.0.0-rc2

Upgrades after 2.0.0-rc-2 should run smoothly without issues.

See Also

Upgrading from MODx Evolution

Automated upgrading from 0.9.6.*/Evolution is not yet available in MODx Revolution 2.0.0. A migration tool will be providedsometime after the release of MODx Revolution 2.0.0.

With that in mind, if you'd _still_ like to upgrade, you're free to do so. However, we . Oncestrongly recommend backing up your data firstyou've done so, simply run the upgrade mode in the setup/ program, and your database tables will be upgraded.

From there, a few things will happen. One, you'll probably notice most of your 3rd party scripts will be broken. You'll need to convert them to theRevolution core, as well as all of your tags to the new . Component developers will hopefully already be converting their scripts by thisTag Syntaxpoint, so you may be able to find Revolution-compatible scripts via , or on or in the .Package Management modxcms.com forums

Also, it's worth noting that there are no more "web users" or "manager users" - only Users. And the is vastly differentnew permissions schemethan in 0.9.6/Evolution.

Again, we don't recommend this, but if you're a *brave* soul, feel free to backup and try it.

Page 128: ModX Revolution Docs 20101007

Extras Changes from Evolution

Some Extras in Evolution have been discontinued or are no longer in active development. Below is a list of Evolution Extras and their Revolutionequivalents:

Evolution Revolution

Ditto getResources, , , getPage tagLister Archivist

Jot Quip

SiteMap GoogleSiteMap

MaxiGallery Gallery

eForm FormIt

Wayfinder Wayfinder

DocManager Batcher

AjaxSearch SimpleSearch

WebLogin Login

See Also

Bob's Guide to Upgrading to Revolution

Functional Changes from Evolution

Changes from MODx Evolution to MODx Revolution

Much has changed from MODx Evolution in the new Revolution release. This document will attempt to address some of the major ones.

Tag Syntax

Tags have changed their basic syntax. You can view the .Tag Syntax changes here

Parsing Order

In Evolution, pages were parsed via eval and done as a whole - in Revolution, we implemented "Source Order" parsing. This means tags areparsed in the order that they occur.

So what does that mean? Well, a few things:

Don't put Snippet calls that assign placeholders at the end of a Resource, or after the Resource. The placeholders will simply be blank,since the haven't executed yet.SnippetTags can now have tags within their properties. [[mySnippet? &tag=`test[call]`]] is now 100% a-okay._Using =,?,!,* is now OK in a Snippet property.

No More 5000-Document limit

Although this has been mostly remedied in later versions of Evolution, there is still a performance hit in those versions. This, caching-wise, hasbeen fixed in Revolution.

That said, if you're creating a site that has over 10,000 Resources, chances are you're not designing it right. Consider writing custom Snippetsthat pull from custom database tables instead for similar pages (such as inventories or e-commerce).

Security

The access permissions system has been completely rewritten into a new ABAC-based system. You can read more about it Security.

Error Page vs Unauthorized Page

This is a change from MODx Evolution. In Revolution, if a web page is protected in the front end so that only logged-in users can see it, the

Page 129: ModX Revolution Docs 20101007

default behavior is for anonymous users to be redirected to the Error (page not found) page rather than the Unauthorized page when they try toaccess the resource. In Revolution, if Users don't have the "load" permission for a resource, it's as if it doesn't exist — thus the "page not found"response. If you would like them to be sent to the Unauthorized page instead, you can do the following:

Create a new Access Policy called "Load" and add a single Permission: Load.Create a new Context Access ACL entry for the anonymous User Group with a Context of "web," a Role of "member" and an AccessPolicy of "Load."

(credit to )Bob's Guides

FURL Suffixes and Prefixes -> Content Types

The settings friendly_url_prefix and friendly_url_suffix are no longer applicable, as Revolution handles those now through .Content Types

Upgrading to Revolution 2.0.0-rc-2

Upgrading to Revolution 2.0.0-rc-2

There are a few changes that have occurred in 2.0.0 RC-2 that will only apply to developers. If you are not:

Writing translatable Extras for RevolutionWriting plugins for Revolution

then you do not have to read this document.

Lexicon Changes

First off, you might ask, "Why such a big change so late in the game?" Well, for one, we didnt realize the limitations of the RC1 lexicon system,and how it hampered Extras development and prevented us from having a stable multi-lingual distribution. What has been changed is:

Dropped entirely the modLexiconTopic and modLexiconLanguage tables.Changed the 'topic' field on modLexiconEntry to be a varchar of the topic name.Refactored the entire modLexiconEntry logic so that now DB records of modLexiconEntry are for overridden entries. Otherwise, theyonlyare cached from the lexicon topic files (the .inc.php files.)Redid the entire Lexicon Management section to now be a grid that only allows overriding of Entries. In other words, you can only editexisting entries, and when you edit them, they show up in , signifying they have been overridden.green

This means that the only Lexicon Entries stored in the database are overrides made by the user.

There are some real benefits to the new approach:

Much, much easier translation abilities.Much faster lexicon loading time, since its file and array based rather than DB and Object based.You can now successfully change any lexicon entry without harming your upgrade path.Cuts down on the size of the core.transport.zip and massively decreases build and setup times.Much easier development. Just put a 'lexicon/' directory in your root of your Namespace's path (like most current Extras do) and build it inthis format: 'lexicon/[language]/[topic].inc.php'. MODx will automatically parse that directory and browse it in Lexicon Management foryou. You no longer need to 'buildLexicon' in your Extra's build scripts. However, this means that all packages using lexicons will need

. All that needs to be changed is that they no longer need to call 'modPackageBuilder::buildLexicon' in theirto be rebuilt for 2.0.0 RC-2build scripts, and their lexicon directories must be under the namespace path with the directory name 'lexicon' (similar to ).this componentWe apologize for the inconvience, but we promise that you'll find the change much, much easier to develop in.

This also means that we will be packaging in core translations into SVN. All core translations will be committed there, similar to Evolution.

Plugin Changes

Deprecated Plugin Events have been removed in RC-2, and a few new events have been introduced. Please view the in-progress documentationon these events on the page, or view an exhaustive list via the .System Events code here

Note that some of these events are model-centric. This means they are executed from within the mod* classes. These are usually:

On*SaveOn*BeforeSaveOn*RemoveOn*BeforeRemove

This means they will fire regardless of where they are executed. This allows you to fire events even when 3rd Party Components modify thoseobjects, such as when a 3PC creates a user. Please see the documentation on each respective event for more information.

Page 130: ModX Revolution Docs 20101007

See Also

Moving Your Site to a New Server

MODx Revolution is a database-driven web application, so moving it to a new server involves the typical porting over of both the database and allthe site's files. Those of you familiar with MODx Evolution may be in the habit of zipping up the files, grabbing a dump of the database, and thendeploying them on the new server... but in Revolution, you may have discovered that maybe something broke in the process... maybe themanager only comes up as a white page. It's more or less the same process, but there are couple extra tidbits to watch out for.

So here's the official documentation of how to move your site to a new location. (Normally, this is to a new server, but the steps here also apply ifyou move your site to a new folder on your current web server).

Packaging up your Files

Any time you pack up a site and move, it's best to package the files into "boxes" – when you move out of your apartment, you put everything intoboxes; the same concept is true with files: package them well. If you simply drag and drop files from one server to another using a GUI interface,chances are good that the GUI will omit hidden files such as the vital file. Besides, transferring hundreds of files via FTP can take a long.htaccesstime because with many servers, each file must undergo some sort of authentication; in other words copying over a hundred 1 megabyte filestakes a lot longer than copying over a single 100 megabyte file.

On a UNIX style system, you can create a compressed file using the tar command:

tar -czf /path/to/backups/modx_revo_site.tar.gz /path/to/modx_doc_root/

Forget me NotA good mnemonic for the "-czf" option is reate ip ile.C Z F

Once you arrive on the other end, it's good to put the zipped file into its own directory before you extract it. The idea here is that if it explodes andyou have to scrape the files off the walls, it's easier to clean up a mess if it's contained in its own directory.

On a UNIX style system, you can unpackage a .tar.gz file using the following commands from a command line:

gunzip modx_revo_site.tar.gztar xvf modx_revo_site.tar

Once you've extracted the files, you can move the whole directory into the correct place. Again, be careful about moving files in bulk: you mightinadvertently forget to copy those hidden files. It's better to rename or move the containing directory instead.

Dumping your Database

In the future, MODx will be able to run on other databases, but for now it runs on MySQL. You can dump your MySQL database using a GUI toolsuch as phpMyAdmin, or you can run the command-line utility.mysqldump

mysqldump -u username -p your_revo_db > /path/to/backups/my_revo_db.sql

If you use , be sure you use a username that has SELECT and LOCK permissions on all your MODx Revolution database tables –mysqldumpusually it's best to simply use the same username and password that are defined in your configuration file ( )./core/config/config.inc.phpRemember that will prompt you for the password after you execute this command: when you type it (or paste it), you won't seemysqldumpanything in the terminal window.

On the new server, you can simply use the "mysql" command to slurp the dump file into the new target database:

mysql -u username -p target_db < my_revo_db.sql

Page 131: ModX Revolution Docs 20101007

You can also use phpMyAdmin, but remember that web-based tools like this are subject to the same memory limits as PHP, so you're usuallybetter off using a command-line tool if possible.

Updating your Config File

Once you've deployed files to the new server, you need to update the main configuration file: . You have to update pathscore/config/config.inc.phpto different resources. Open the file and update the values for the following variables doing a find and replace:6

/* PATHS */$modx_core_path= '/path/to/modx_doc_root/core/';$modx_processors_path= '/path/to/modx_doc_root/core/model/modx/processors/';$modx_connectors_path= '/path/to/modx_doc_root/connectors/';$modx_manager_path= '/path/to/modx_doc_root/manager/';$modx_base_path= '/path/to/modx_doc_root/';$modx_assets_path= '/path/to/modx_doc_root/assets/';

/* HOST (used command-line PHP stuff) */for$http_host='yoursite.com';

PermissionsBefore you can edit your config file, you may need to loosen up the permissions. After you've edited it, be sure you restore theread-only permissions on the file.

Update your Database

Sometimes developers structure their development and production servers to use the same path information, but for most of us, the file pathexactinformation will change when we move our MODx web site to a new server. Take a look inside your Revolution database and see for yourself thatpath information is stored there. Type the following query into phpMyAdmin, a MySQL command line, or any other application that allows you toexecute queries on your database:

SELECT `path` FROM `your_revo_db`.`workspaces`;

Change "your_revo_db" to your database name, and add an appropriate prefix to the "workspaces" table if necessary.

On the new server you need to update this record.  You can edit it using a GUI editor (like SQL-Yog or phpMyAdmin), or you can execute thefollowing command (again, you need to customize the query depending on your database, prefix, and the path to your data):

UPDATE `your_revo_db`.`workspaces` SET path='/path/to/modx_doc_root/core/' WHERE id='1';

Don't Forget the DatabaseMODx stores some path data in its database! When you move servers, you may have to update the workspaces table,otherwise the manager page may show a white page.

Update .htaccess

When you change servers, you frequently wind up changing domain names. Make sure you update any references to the old domain to the newone.

Log into the Manager: Clear your Cache and Sessions

By now you should be able to log into the manager, but when you first login you'll see an error message:

Could not find action file at: /path/to/manager/controllers/ /welcome.phpdefault

That's because the old path is still cached; MODx Revolution caches a lot of information in the database. Once you've gotten the files and

Page 132: ModX Revolution Docs 20101007

database transferred over to the new server, make sure you clear your site's cache of any lingering data that may contain the old file paths.

Log into the manager, then: Site --> Clear Cache

Finally, clear your sessions: Security --> Flush All Sessions

Your site should now be up and running in its new location!

Developing in MODx

This section contains information on starting development in MODx.

Code Standards

Code StandardsGeneral Practices

Indentation and Line BreaksTrailing SpacesCompression

HTMLValidationInline HTML in SnippetsSelf-closing ElementsTerseness

DoctypeTags and AttributesQuotes

CSSInline StylesCSS ValidationCSS FormattingPixels vs. EmsInternet Explorer BugsShorthand

Margin & PaddingHex ColorsBackgroundBorderFontLonghand

JavascriptType CoercionWhite-spaceVariables, ID & ClassQuotesEvent ListenersEvent DelegationClosures & ScopeObjects & Arrays

PHPGeneralParenthesisClassesVariablesFunction Arguments and Class VariablesArraysConstantsFile StructurePrefixing

SQL

Code Standards

Page 133: ModX Revolution Docs 20101007

This page describes the MODx coding standards for any MODx Component, Extension or core code. These are not de-facto rules, but guidelinesfor easier development and collaboration between developers.

This page was heavily borrowed from . Thanks!Fellowship One's Design Standards

General Practices

Indentation and Line Breaks

All indentation must be done with , not tabs. Make sure to change your editor settings to reflect this. Line breaks must be in format.4 spaces UNIX

Trailing Spaces

MODx recommends removing any trailing spaces in a line in code, unless that spacing is for design purposes.

Compression

MODx suggests packaging both compressed and uncompressed JS/CSS. MODx recommends using the compressed JS/CSS in productionenvironments, but allowing users the option to toggle between compressed and uncompressed JS/CSS. This allows for easier debugging.

MODx does not advocate PHP compression.

HTML

HTML5 is a new version of HTML and XHTML. The HTML5 draft specification defines a single language that can be written in HTML and XML. Itattempts to solve issues found in previous iterations of HTML and addresses the needs of Web Applications, an area previously not adequatelycovered by HTML. ( )from html5.org

MODx recommends following the HTML5 specs: http://whatwg.org/specs/web-apps/current-work/

Validation

All HTML must be HTML5-validated. MODx recommends using the .W3C Validator

Inline HTML in Snippets

MODx requires that be echo'ed or inline in a Snippet. MODx also recommends externalizing any HTML in PHP code into .no html Chunks

All HTML pages should be verified against the W3C validator, to ensure that the markup is well formed. This in and of itself is not directlyindicative of good code, but it helps to weed out problems that are able to be tested via automation. It is no substitute for manual code review.

Note: In TextMate, Control + Shift + V will check the validity of the currently open HTML document.

Self-closing Elements

Though we are using HTML5, which allows for either HTML or XHTML style syntax, we prefer the strictness of XHTML. Therefore, all tags mustbe properly closed. For tags that can wrap nodes such as text or other elements, termination is a trivial enough task. For tags that are self-closing,the forward slash should have exactly one space preceding it <br /> vs. the compact but incorrect <br/>. The W3C specifies that a single spaceshould precede the self-closing slash (source).

Terseness

Doctype

A nice aspect of HTML5 is that it streamlines the amount of code that is required. Meaningless attributes have been dropped, and the DOCTYPEdeclaration has been simplified significantly. Additionally, there is no need to use CDATA to escape inline JavaScript, formerly a requirement tomeet XML strictness in XHTML.

"HTML5 Doctype"

<!DOCTYPE html>

Page 134: ModX Revolution Docs 20101007

"XHTML 1.0 Transitional Doctype"

<!DOCTYPE html PUBLIC "- //W3C//DTD XHTML 1.0 Transitional//EN">"http://w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"

Tags and Attributes

All tags and attributes must be written in lowercase. Additionally, we prefer that any attribute values also be lowercase, when the purpose of thetext therein is only to be interpreted by machines. For instances in which the data needs to be human readable, proper title capitalization shouldbe followed, such as:

"For machines"

<meta http-equiv= content= />"content-type" "text/html; charset=utf-8"

"For humans"

<a href="http: title= >Example.com</a>//example.com/" "Description Goes Here"

Quotes

In keeping with the strictness of XHTML code conventions, according to the W3C, all attributes must have a value, and must use double-quotes(source). The following are examples of proper and improper usage of quotes and attribute/value pairs.

"Correct"

<input type= name= disabled= />"text" "email" "disabled"

"Incorrect"

<input type=text name=email disabled>

CSS

Inline Styles

We strive to maintain proper separation of content and design, and therefore highly discourage the use of inline style="..." attributes. This not onlymakes maintenance a nightmare, but inextricably ties the presentation to the data it represents. All of our CSS will be stored in external files, withone master.css file called per page. That single file will incorporate other files as necessary with the @import syntax.

Note: An exception to this rule is style="display:none" for revealing hidden elements via JavaScript.

CSS Validation

All cascading stylesheets should be verified against the W3C validator, to ensure correct syntax and to check for possible accessibility issues withtext and background colors. This in and of itself is not directly indicative of good code, but it helps to weed out problems that are able to be testedvia automation. It is no substitute for manual code review.

Note: In TextMate, Control + Shift + V will check the validity of the currently open CSS document.

CSS Formatting

To ease potential headaches for maintenance, we require that all CSS be written in a consistent manner. For one, all CSS selectors must belisted on their own line. As a general rule of thumb, if there is a comma in CSS, it should immediately be followed by a line break. This way, weknow that all text on a single line is part of the same selector. Likewise, all property/value pairs must be on their own line, with one tab ofindentation. The closing brace must be on the same level of indentation as the selector that began it - flush left.

Page 135: ModX Revolution Docs 20101007

"Correct"

#selector_1 span,#selector_2 span,#selector_3 span { background: #fff; color: #000;}

"Incorrect"

#selector_1 span, #selector_2 span, #selector_3 span { background: #fff; color: #000;}

"Also incorrect"

#selector { background: #fff; color: #000; }

Pixels vs. Ems

We use the px unit of measurement to define font size, because it offers absolute control over text. We realize that using the em unit for fontsizing used to be popular, to accommodate for Internet Explorer 6 not resizing pixel based text. However, all major browsers (including IE7 andIE8) now support text resizing of pixel units and/or full-page zooming. Since IE6 is largely considered deprecated, pixels sizing is preferred.Additionally, unit-less line-height is preferred because it does not inherit a percentage value of its parent element, but instead is based on amultiplier of the font-size.

"Correct"

/*13 * 1.5 = 19.5 ~ Rounds to 20px.*/#selector { font-size: 13px; line-height: 1.5;}

"Incorrect"

/*Equivalent to 13px font-size and 20px line-height,but only the browser text size is 16px.if default*/#selector { font-size: 0.813em; line-height: 1.25em;}

Internet Explorer Bugs

Inevitably, when all other browsers appear to be working correctly, any and all versions of Internet Explorer will introduce a few nonsensical bugs,delaying time to deployment. While we encourage troubleshooting and building code that will work in all browsers without special modifications,sometimes it is necessary to use conditional if IE comments to serve up specific fixes, which are ignored by other browsers.

"Fixing IE"

<!--[ IE 7]>if<link type= rel= href= />"text/css" "stylesheet" "/assets/styleshseets/ie7.css"<![endif]--><!--[ IE 8]>if<link type= rel= href= />"text/css" "stylesheet" "/assets/styleshseets/ie8.css"<![endif]-->

Page 136: ModX Revolution Docs 20101007

Shorthand

In general, CSS shorthand is preferred because of its terseness, and the ability to later go back and add in values that are already present, suchas the case with margin and padding. Developers should be aware of the TRBL acronym, denoting the order in which the sides of an element aredefined, in a clock-wise manner: Top, Right, Bottom, Left. If bottom is undefined, it inherits its value from top. Likewise, if left is undefined, itinherits its value from right. If only the top value is defined, all sides inherit from that one declaration.

For more on reducing stylesheet code redundancy, and using CSS shorthand in general:

http://qrayg.com/journal/news/css-background-shorthandhttp://sonspring.com/journal/css-redundancyhttp://dustindiaz.com/css-shorthand

Margin & Padding

"Correct"

#selector { margin: 0 0 10px; padding: 0 0 10px;}

"Incorrect - left attribute unnecessary"

#selector { margin: 0 0 10px 0; padding: 0 0 10px 0;}

Hex Colors

We prefer hex values for all colors, written in lower-case. No upper-case or RGB, please! Additionally, all colors should be written as tersely aspossible. This means that colors such as full blue, which can be written lengthily as #0000FF, should be simply written as #00f. Obviously, forcolors that require more precision, all six characters should be used. For example, a light shade of grayish beige: #f9f9f0.

Background

"Correct - shorthand"

#selector { background: #fff url(../images/file.png) repeat-x fixed left bottom;}

"Incorrect - longhand unnecessary"

#selector { background-color: #fff; background-image: url(../images/file.png); background-repeat: repeat-x; background-attachment: fixed; background-position: left bottom;}

Border

In general, border should be a single line declaration, assuming that the values of the border are the same on all sides of the element. The orderin which values are declared are: width, style, and color.

"Shorthand - method 1"

#selector { border: 1px solid #000;}

Page 137: ModX Revolution Docs 20101007

If the values of each side differ, then there are two possible ways of using shorthand, and it is up to the discretion of the developer to decide whichto use. Note that method 2 follows the TRBL pattern.

"Shorthand - method 2"

#selector { border-color: #fff #999 #666 #ccc; border-style: solid dashed dotted ;double border-width: 1px 2px 3px 4px;}

"Shorthand - method 3"

#selector { border-top: 1px solid #fff; border-right: 2px dashed #999; border-bottom: 3px dotted #666; border-left: 4px #ccc;double}

By contrast, the same style declaration is extremely verbose using longhand. This should be avoided, except in instances where only oneparticular value needs to be overridden, allowing the rest to flow through.

"Longhand"

#selector { border-top-color: #fff; border-right-color: #999; border-bottom-color: #666; border-left-color: #ccc; border-top-style: solid; border-right-style: dashed; border-bottom-style: dotted; border-left-style: ;double border-top-width: 1px; border-right-width: 2px; border-bottom-width: 3px; border-left-width: 4px;}

Font

Not to be confused with the inadvisable <font> tag, the CSS font property can be written in a few different ways. The shorthand property puts allthe aspects of the font into a single declaration, whereas the longhand splits it out over several lines. While the contrast between methods is notas stark as with that of the border property, there is still space to be saved by using shorthand. While line-height can be defined within the scopeof the font declaration, but when written in longhand it has its own unique property.

Note: Times New Roman is encapsulated in quotes, because the font name itself contains spaces.

"Shorthand"

#selector { font: italic small-caps bold 15px/1.5 Cambria, 'Times New Roman', sans-serif;}

Page 138: ModX Revolution Docs 20101007

"Longhand"

#selector { font-style: italic; font-variant: small-caps; font-weight: bold; font-size: 15px; line-height: 1.5; font-family: Cambria, 'Times New Roman', sans-serif;}

Longhand

When overriding only parts of a style, longhand declaration is preferred. This way, by sticking to shorthand for initial style declarations, anytime wesee a longhand declaration used, we know that we are specifically overriding only a very precise part of an overall style, thereby leaving otheraspects unaffected.

"Longhand override"

#selector { border: 1px solid #ccc; font: 11px Verdana, sans-serif;}#selector.modifier { border-bottom-color: #333; border-bottom-width: 2px; font-family: Georgia, serif;}

Javascript

Type Coercion

Unlike strongly typed languages such as Java or C#, JavaScript will perform type coercion when evaluating conditional statements. Thissometimes creates awkward scenarios in which numerical values are seen as false or the existence of a string is mistaken for true. This istypically disadvantageous.

To ensure a strict level of comparison, as might be seen in a strongly typed or compiled language, JavaScript (like PHP) has a triple-equalsoperator ===. In similar fashion, it also has a strict negation operator !==. Consider the following examples of potential pitfalls when it comes toevaluating comparisons.

var test_1 = ' ';true test_2 = 0;var (test_1 == ) {if true

// Code here will run.// But it shouldn't.}

(test_1 === ) {if true // Code here won't run.// Correct behavior.}

(test_2 != ) {if false // Code here won't run.// But it should.}

(test_2 !== ) {if false // Code here will run.// Correct behavior.}

As you can see in the example above, simply using == and != is insufficient because it makes for potentially unpredictable results. Therefore, thestricter comparison operators should always be used. There is never a good reason to use the lesser form of comparison operators. To simply forthe existence of elements in the DOM, there is an even more abbreviated way, that leaves no room for ambiguity. If you are unsure if certainelements will be present in an HTML page, use one of the following techniques.

Page 139: ModX Revolution Docs 20101007

function first_func() { (!document.getElementById('id_name')) {if ;return } // If code gets here, element exists.}function second_func() { (!document.getElementsByTagName('div').length) {if ;return } // If code gets here, one or more exist.}

White-space

In general, the use of whitespace should follow longstanding English reading conventions. Such that, there will be one space after each commaand colon (and semi-colon where applicable), but no spaces immediately inside the right and left sides of parenthesis. In short, we advocatereadability within reason. Additionally, braces should always appear on the same line as their preceding argument.

Consider the following examples of a JavaScript for-loop...

"Correct"

for ( i=0, j=arr.length; i<j; i++) {var // Do something.}

"Incorrect"

for ( i = 0, j = arr.length; i < j; i++ )var{// Do something.}

Variables, ID & Class

All JavaScript variables shall be written in completely lowercase letters, with underscores to separate words if need be. Likewise, all id and classdeclarations in CSS shall be written in the same manner. Neither dashes nor camelCase shall be used, except for words that contain dasheswhen written in plain English.

Quotes

The preferred method of delineating strings is to use single quotes for everything. Since JavaScript exists to manipulate markup, and becauseHTML is generally written with double quotes in W3C specifications, using single quoted strings will better facilitate handling HTML fragments,and keep code more readable.

"Correct"

var my_html = '<img class= src= alt= />';"photo" "/path/file.jpg" "Text"

"Incorrect"

var my_html = photo\ /path/file.jpg\ Text\ ;"<img class=\" " src=\" " alt=\" " />"

Event Listeners

Rather than using attributes such as onload, onfocus, onsubmit, or onclick directly in markup, we will instead attach event listeners to theseelements via unobtrusive techniques. The reasoning for this is the same philosophy that is behind not using inline style="..." declarations. Sodoing inextricably ties the behavior of a web page to its data, and makes maintenance more difficult.

Event Delegation

Page 140: ModX Revolution Docs 20101007

When assigning unobtrusive event listeners, it is typically acceptable to assign the event listener directly to the element(s) which will trigger someresulting action. However, occasionally there may be multiple elements which match the criteria for which you are checking, and attaching eventlisteners to each one might negatively impact performance. In such cases you should use event delegation instead.

Closures & Scope

To maintain proper scope for variables, it is highly recommended that self-executing anonymous function be used as a closure. For the most part,variables defined correctly using the var syntax, within the scope of a function will not add to global scope pollution. However, from time to time,you may need to access variables via two or more functions. In such cases, multiple functions can be grouped together inside a closure.

"Closure"

(function() { first_variable = 'value 1';var second_variable = 'value 2';var

function first_func() { // Do something.}

function second_func() { // Do something.}})();

Objects & Arrays

Objects can be thought of as tiered variables that contain multiple attributes. Similarly, an array could be described as a list of data that all sharecommon characteristics. The following code snippets show examples of objects and arrays, and the different ways in which they can be defined.Note that values such as John Doe's age and marital status do not have quotation marks around them. This is because age is truely numerical,and true is a Boolean value.

Note also that the commas are before the variable or method declaration. This prevents errors with trailing commas in IE and other browsers.

Objects (and arrays) are an important part of JSON - JavaScript Object Notation, which is a platform and language independent way oftransmitting data, used as an alternative to XML.

"Object literal - preferred"

var john_doe = { first_name: 'John' ,last_name: 'Doe' ,job: 'Everyman Respresentative' ,email: '[email protected]' ,married: true ,age: 30};

"Object dot notation"

/*Could also be written:

john_doe = ();var new Object*/

john_doe = {};varjohn_doe.first_name = 'John';john_doe.last_name = 'Doe';john_doe.job = 'Everyman Representative';john_doe.email = '[email protected]';john_doe.married = ;truejohn_doe.age = 30;

Page 141: ModX Revolution Docs 20101007

"Array literal - preferred"

var doe_family = [ 'John' ,'James' ,'Jane' ,'Jenny' ,'Jared' ,'Jerome'];

"Array bracket notation"

/*Could also be written:

doe_family = Array();var new*/

doe_family = [];vardoe_family[0] = 'John';doe_family[1] = 'James';doe_family[2] = 'Jane';doe_family[3] = 'Jenny';doe_family[4] = 'Jared';doe_family[5] = 'Jerome';

PHP

General

Beginning brackets do NOT linebreak. They start one space after the end parenthesis, as according to traditional Unix policy.Do not do any real logic in object constructors. Create class methods to do so.null, true and false should always be lowercase.Avoid embedded assignments (ex: $d = ($a = $b + $c) is bad).Never use extract().Avoid using global variables if at all possible.Document EVERYTHING.

Parenthesis

Do not put parenthesis next to keywords. Put a space between.Do put parenthesis next to function names.Do not use parenthesis in return statements when it's not necessary. Example:

if ($test) {}

($test == $other) {while}array_push($one,$two);

$test;return

Do use parenthesis when using include, require, include_once, and require_once.not

Classes

All ''core'' classnames, unless stated otherwise for special conditions, will be prefixed with the "mod" prefix: ie, modChunk, modTemplate,etc.All method names will be camelCase and will start with a lowercase letter.All private methods and variables must be prefixed with the underscore _ character.

Page 142: ModX Revolution Docs 20101007

class modFactor { $publicVar;public $_privateVar;private function _privateFunc() { }private function publicFunc() { }public}

Variables

Note these are not function arguments.

Use all lowercase letters.Separate words with the underscore.

Function Arguments and Class Variables

The first letter is lowercase, rest are camelCase. Example:

class modFactor { function testFunc($testVar, array &$anotherTest = array()) {public $ ->_privateVar = $testVar;this $local_variable =& $anotherTest; }}

Arrays

Array index names use the underscore _, not the dash as their separator. This prevents errors with magic_quotes.Array index names are always lowercase. Spaces are represented by an underscore.Array index names are always encapsulated with single quotes.Example:

$_lang['chunk_create_text'] = 'Test';

Constants

Constants must be in all UPPERCASE letters.Use only if absolutely necessary.

File Structure

Always name PHP class files in name.class.php format.

Prefixing

Lexicon strings for Components need to be prefixed:

$_lang['mycomponent.welcome_message'] = 'Welcome!';

Always prefix class names; eg: 'finBank', 'finTransaction', etc.Always prefix names; eg: 'finStatement', 'finDeposit'Chunk

SQL

All inline SQL must be capitalized, and table and column names must be enclosed with backticks.

Page 143: ModX Revolution Docs 20101007

"Correct"

UPDATE `mydatabase`.`mytable`SET `name` = "Johnny"WHERE `id` = 123;

"Incorrect"

update mydatabase.mytable set name='Johnny' where id=12

Overview of MODx Development

This section pertains to developing Extras for MODx Revolution that can help extend your MODx system.

Developer Introduction

What is MODx?What is MVC?

What is MVC²?Connector/Processor Relationships

What is xPDO?What is an ORM?A Brief Overview of Revolution

The ModelThe View

In the front-end, they are Templates, Chunks and Resources.TemplatesChunksResources

In the ManagerThe Controller

SnippetsPlugins

The 2nd C: The ConnectorsSee Also

What is MODx?

MODx Revolution is an Content Application Platform, built for developers, designers and users who want a powerful, scalable system with flexiblecontent management built in.

What is MVC?

MVC is "Model-View-Controller", a common programming paradigm where the data's Model is only accessed through a Controller, whichconnects to a View that can easily be changed without having to change the Model.

What is MVC²?

MVC² is a MODx terminology that is "Model-View-Controller/Connector". It basically adds a new way of accessing the model from the view -Connectors, which are AJAX-based files that "connect" to processors to provide remote CRUD interactions.

Connector/Processor Relationships

Connectors are simply gateway files that hook into specific Processors. They are used mainly to prevent direct accessing of processors, and limituser access to those processors.

What is xPDO?

Page 144: ModX Revolution Docs 20101007

xPDO is our name for open eXtensions to PDO. It's a light-weight ORB (object-relational bridge) library that works on PHP 4 and 5, and takesadvantage of the newly adopted standard for database persistence in PHP 5.1+, PDO. It implements the very simple, but effective Active Recordpattern for data access, as well as a flexible domain model that allows you to isolate domain logic from database-specific logic, or not, dependingon your needs.

What is an ORM?

As defined by :Wikipedia

An object-relational database (ORD), or object-relational database management system (ORDBMS), is a database managementsystem (DBMS) similar to a relational database, but with an object-oriented database model: objects, classes and inheritanceare directly supported in database schemas and in the query language. In addition, it supports extension of the data model withcustom data-types and methods.

Basically, tables in SQL databases become classes that can contain table-specific methods, inherit from base classes, and much more.

A Brief Overview of Revolution

Revolution at its core is a Content Management Framework. It's not a PHP Application Framework like CodeIgnitor or Symfony, nor does itpurport to be one. With that said, it's much more than a typical CMS like Wordpress or others; it enables you to build Content ManagementApplications with ease and extensibility.

Revolution bases its internal structure on what we call a MVC² design system. It's loosely based on the MVC, or model-view-controllerarchitectural pattern, in programming.

The Model

The stands for , which is the core classes that manipulate data records. These core classes, prefixed with 'mod' in Revolution, handle allM Modelthe Domain logic for MODx Revolution.

This also includes what Revolution calls "processors", which are scripts that handle Domain Logic for MODx Revolution. They are never accesseddirectly, and are used to handle form processing, REST requests, AJAX requests, and more. They resemble basic CRUD(Create-Read-Update-Delete) processing tasks.

The View

Views in MODx Revolution are called 'Templates', but are used differently based on what context we're talking about.

In the front-end, they are Templates, Chunks and Resources.

Templates

Templates are what they sound like. They allow you to create templates that will encapsulate more page-specific data. Think of them likeheaders/footers all rolled into one (and so much more!)

Chunks

Chunks are small pieces of HTML code that can be inserted anywhere. They represent View widgets, in a sense, because of their modularity andease of insertion.

Resources

Resources is the basic representation of a single "webpage" in MODx Revolution. They represent a single page or resource by which the clientaccesses content from the server. They can be files, weblinks, symlinks or just plain-old HTML pages wrapped by .Templates

In the Manager

In the manager-side of MODx Revolution, the View is handled by templates as well, although these are file-based and located inmanager/templates, and currently loaded via Smarty.

The Controller

Controllers in MODx Revolution come in two forms. In the front-end, they are Request Handlers (via the modRequest class) and Snippets andPlugins.

Snippets

Snippets are simply PHP code that can be placed anywhere in a page. They can be placed in , , or Resources. They simplyChunks Templatesexecute PHP code whenever they are called, and return whatever output they would like to push to the page.

Page 145: ModX Revolution Docs 20101007

Plugins

Plugins are also PHP code, but are targeted at specific System Events that occur throughout the request processing. They can occur before thewebpage is rendered, after it is, before the request is handled, or many more places.

They allow users to write generic code that affects basic page functionality, such as word censoring, automatic link creation, separate cachehandling, context redirection, and more.

The 2nd C: The Connectors

Connectors are a new idea to MODx Revolution; they are access points for processors. The manager system in MODx Revolution uses themextensively; they provide secure locations for AJAX requests to process data on certain objects.

For example, a connector request that loads /modx/connectors/resource/index.php with a GET 'action' parameter of "get", and a GET parameterof 'id', will (assuming the request's client has access) grab the Resource with the ID specified and return it in JSON (or whatever is configured; thisis JSON by default in Revolution) format.

Every Connector request is also secured down by Context permissions loaded on every request. If the user does not have access (via the AccessPolicy assigned to the request's context), the connector will refuse to provide data.

Connectors allow for dynamic, secure JSON requests (and eventually REST-based requests) straight from your MODx manager.

See Also

xPDO, the database layer for RevolutionExplanation of Directory StructureGlossary of Revolution Terms

Getting Started Developing

Programming in MODx Revolution3rd-Party Components (3PCs)core/components and assets/componentsSnippetsPluginsProperties and Property SetsCustom Manager Pages (CMPs)Using MODx Externally

Programming in MODx Revolution

MODx Revolution is an OOP Framework, built around the database ORM .xPDO

3rd-Party Components (3PCs)

3rd-Party Components (3PCs) are collections of any sort of MODx Objects. They can be a collection of Snippets, Plugins and Chunks, or a singleSnippet, or just a collection of files. They are usually transported and installed via .Transport Packages

core/components and assets/components

MODx doesn't necessarily limit where you can put your custom 3rd party component files, but we do have some recommendations. For files thatdon't need to be in the webroot (config files, .php, etc), we recommend putting them in:

core/components/myname

So, if you had a component named 'test', you would put its non-webroot files in "core/components/test/". For files that need to be web-accessible,such as css, js and other files, we recommend:

assets/components/myname

Ergo, for 'test', "assets/components/test". This standardization of paths makes it easier for other developers using your components to find yourfiles easily.

Snippets

Snippets are simply php scripts that can be executed on any page or other Element. They are the cornerstone of MODx Development and

Page 146: ModX Revolution Docs 20101007

dynamic customization. You can read more about Snippets .here

Plugins

Plugins are similar to snippets in that they are snippets of code that have access to the MODx API - however the big difference is that plugins areassociated to specific system events. For example, in an average MODx page request, several events happen at certain points within the pageparsing process and plugins can be attached to any of these events to fulfill a desired function. aren't just limited to front-end processingPluginsthough, there are many events that are available in the MODx Manager.

Properties and Property Sets

Properties are simply placeholders on Elements (Snippets/Plugins/Chunks/TVs/Templates), which can be parsed by each individual Element.They allow customization and argument passing for each Element.

Property Sets are user-defined groupings of Properties that can be used to quickly centralize custom tag syntax calls.

More on Property Sets can be found .here

Custom Manager Pages (CMPs)

Custom Manager Pages, or CMPs, are custom pages in the manager built by 3rd Party developers to allow backend management ofComponents. They use the modAction and modMenu objects to dynamically create manager pages that can be easily found and added with nohacking of the core.

Using MODx Externally

Using the MODx object (and all of its respective classes) is quite simple. All you need is this code:

require_once '/absolute/path/to/modx/config.core.php';require_once MODX_CORE_PATH.'config/'.MODX_CONFIG_KEY.'.inc.php';require_once MODX_CORE_PATH.'model/modx/modx.class.php';$modx = modX();new$modx->initialize('web');

This will initialize the MODx object into the 'web' . Now, if you want to access it under a different (and thereby changing its accessContext Contextpermissions, policies, etc), you'll just need to change 'web' to whatever you want to load.Context

Extras Directories

Extras are most commonly stored in 2 directories when they are installed:

core/components/ - This is the location for all the PHP and non-web-accessible files for the Extra.assets/components/ - This is the location for the web-accessible files for the Extra, such as CSS, JS and images.

Why the separation? Well, since MODx users can move the core outside the webroot, separating out the non-accessible files intocore/components allows MODx developers to add an extra level of security to their Extras.

See Also

Setting up a Development Environment

Recommended Development Tools and Environments for MODx Revolution

In developing MODx Revolution, the MODx Team has found the following environments invaluable:

Netbeans

Netbeans 6.8Netbeans Subversion and JIRA plugins

Page 147: ModX Revolution Docs 20101007

Eclipse 3.6 Helios and EclipsePDT

Currently phpEclipse appears to have issues running under Helios

Install Eclipse IDE for Java EE DevelopersThis will give you the Web Tools Platform in a single step

Start up EclipseAt this point it is not suggested to use a previous workspace with live projectsFor this install we simply selected the default (and empty) workspace, which was located in the current user space

Go to the Help menu | Install New SoftwareSelect "-All Additional Sites-" from the "Work with:" drop down

Wait for the site list to populate the displayOpen the "Programming Languages" categorySelect "PHP Development Tools"

Install all suggested software-- Alternately you can directly install the PDT tools in a much smaller package

Restart EclipseAt this point you can start importing sites into the workspace

Note: With the MODx project being housed on there is an additional and optional eclipse project  yougithub.com/modxcms eGitmay also wish to install.  opengeek (Jason Coward) strongly suggests learning and using git from the tocommand linemaximize your flexibility and potential.  It may also be suggested to set up a local git repo and simply clone the respectiveMODx and xPDO repositories, working from local copies.  SVN is discouraged from continued usage in regards to future MODxrelated development.

Additional suggestions:  Install your IDE in a location which is static and remains consistent for long periods of time. You mayalso want to isolate your workspace to a dedicated partition/drive, especially in operating systems (such as Soalris, Linux, andMac OS) which do not require erasure/formatting of the entire drive to install.  By placing the development tools and projects indedicated spaces it will be much easier to make backups and to get back to work in the case of a system install.

It is not advised to install Eclipse and point to a workspace with existing projects, as many of its internal system settings (suchas repos and file type associations with specific tools) are stored in the workspace and may actually inadvertently cause issuesif an alternate tool is being used in place of an older one.

Eclipse  versions before 3.6

Eclipse 3.2.+ (recommend latest 3.5.1)Web Standard Tools Project (WST) 2.0.1 ( )http://download.eclipse.org/webtools/updates/Subclipse 1.6.5 ( )http://subclipse.tigris.org/update_1.6.xPHPEclipse 1.2.3 ( )http://update.phpeclipse.net/update/nightlySpket IDE 1.6.18 ( )http://spket.com/update/

Installation

Simply install the latest Eclipse ClassicStart up eclipse / select a workspaceUse the Install Software option under the help menuRight click and copy each of the links above (doing them in order doesn't hurt)Click the "Add" buttonName the "repo" WST, Subclipse, PHPEclipse, or Spket, as it relates to the URLPaste the URLClick OKRepeat for each of the links above as necessaryIndividual notes:

WST - select the latest Web Tools Platform (takes quite a while)Subclipse - simply install the Subclipse optionPHPEclipse - install everything offeredSpket - Install everything offered

Other IDEs

For Mac:

TextMate - IDECoda - IDEVersions - SVN clientsvnX - SVN client

Page 148: ModX Revolution Docs 20101007

For PC:

UltraEdit - IDEE - IDETortoiseSVN - SVN clientKate - IDE for Linux / KDE

Development Server Environments

We also MacPorts, XAMPP and MAMP, and the following tools/libraries in the development of MODx Revolution:

PHPUnit - this drives the PHP 5.1+ unit testing framework for xPDO, and we'll be adding a test harness to MODx soonSimpleTest - this drives the PHP 4/5.0.x unit testing framework for xPDO, and we'll be adding a test harness to MODx soonPHPDocumentor - all of the classes in MODx Revolution are documented in PHPDoc format, and we'll be developing tutorials and otherextended documentation for inclusion in the PHPDocs in DocBook XML formatPhing - will be used to allow automation of nightly builds, various distribution builds, unit testing, and many other development tasks

Basic Development

This section is geared at familiarizing developers with basic MODx development principles, and using the structures in MODx to create dynamic,script-driven content.

Snippets

OverviewWhat is a Snippet?How Do They Work?Simple ExamplePassing Values Into a Snippet

Database Interaction in SnippetsWhy an ORM?Example DB CodeFurther Database Reading

Recommended Methods and TipsWrite your Snippets outside of MODx.Don't try to mix PHP and HTML in a Snippet.Don't Work on Live SnippetsUse Default Properties

See Also

Overview

Snippets are the method by which MODx allows you to run dynamic PHP code in any of your pages. They are the main development vehicle formost developers.

What is a Snippet?

According to one definition, a "snippet" is "a short reusable piece of computer source code". Some people have a hard time distinguishing thisfrom a "chunk", so a helpful mnemonic might lie in the p's... as in "PHP", e.g. sni-"P(h)P"-et.

How Do They Work?

First off, most Snippets are , meaning they're stored as a temporary, dynamic function in the cache. If they're flagged as uncached, thencachedthey are not parsed until the parser has done all of the other cached content.

Then, once they're up to be cached, Snippets are then parsed by the MODx Parser. They have access to the $modx object.

Simple Example

Here's the perfunctory super-basic example of what a Snippet might look like:

Page 149: ModX Revolution Docs 20101007

1.

2.

3.

<?php 'Hello, World!';return

?>

If you named this , you could call this snippet by using [[helloWorld]] in your documents, templates, or Chunks."helloWorld"

Note how we returned the code rather than 'echo'ed the content out. in a Snippet - always return the output.Never use echo

Passing Values Into a Snippet

Snippets can take input values using a modifed CGI web-form type notation. For example, if your Snippet looks something like this:

<?php 'My input was: ' . $input;return

?>

You might call it using something like this:

[[!mySnippetName? &input=`Hello World`]]

Notice that the variable names in the calling bit need to match the variable names in the Snippet EXACTLY (case matters... i.e. 'Input' not 'input').Secondly, don't forget the '&' in front of the would be variable names. And last but most certainly not least, take note that those are backticks, notsingle quotes!

Database Interaction in Snippets

Accessing the database layer in MODx is quite simple; MODx uses an Object Relational Model (ORM) called for database connectivity.xPDO

Why an ORM?

You might be asking, why use an ORM instead of just straight SQL? Well, a few reasons:

SQL Abstraction - This means that you can write code that works in a variety of different database types, such as MySQL, sqllite,postegresql, and more, as MODx expands to those databases. All without having to rewrite a single line of code.Parameter Escaping - No more having to worry about SQL injection; xPDO uses PHP's PDO to escape all variables passed in to theSQL call to prevent any malicious calls.Cleaner, shorter Code - What could be done in 40+ lines in mysql_* calls can now be done in 10 or less.

There are more reasons, but that's for brevity. Let's look at a few examples:

Example DB Code

Let's get a chunk named 'LineItem', and change the placeholders in it (done with [[+placeholderName]] syntax) to some custom values:

$chunk = $modx->getObject('modChunk',array( 'name' => 'LineItem',));

(!$chunk) 'No line item chunk!';if return

$chunk->process(array(return 'name' => 'G.I. Joe', 'grenades' => 42,));

That code would get a chunk with the name of 'LineItem', and return it processed with the placeholders set. The $chunk variable there is actuallyan , which is an object representation of the Resource.xPDOObject

What about more complex queries? Like, say, getting the first 10 Resources with a parent of 23, 24 or 25. And let's make it so they aren't hiddenfrom menus or deleted, are published, and sort them by menuindex. That's when we use the powerful $modx->newQuery() method:

Page 150: ModX Revolution Docs 20101007

$c = $modx->newQuery('modResource');$c->where(array( 'parent:IN' => array(23,24,25), 'deleted' => ,false 'hidemenu' => ,false 'published' => ,true));$c->sortby('menuindex','ASC');$c->limit(10);$resources = $modx->getCollection('modResource',$c);

Note how we first create an xPDOQuery object ($c) using $modx->newQuery(). We passed in the name of the class we wanted to build the queryfrom - here 'modResource', or Resources - and then used our where() function to add some restrictions. Then we sorted and limited them.

And finally, we called getCollection which - unlike getObject - returns a collection, or array, of xPDOObjects. We could then iterate over thoseusing foreach and do whatever we want with them.

Further Database Reading

For further reading on xPDO, read up on these:

xPDO at the spacexPDORetrieving Objects in xPDOThe ObjectxPDOQuery

Recommended Methods and Tips

Write your Snippets outside of MODx.

This is pretty easy to do - just create an 'include' snippet, but make its content be this:

if (file_exists($file)) { $o = include $file;} { $o = 'File not found at: '.$file; }else

$o;return

You can use the include snippet on a page like such:

[[!include? &file=`/absolute/path/to/my/snippet.php`]]

And run your Snippets externally while you develop them!

Then you can test them to make sure they work (e.g. on the bash command line, you can use the command to check thephp -l my_script.phpscript for syntax errors). Depending on your environment, you may also get some useful error messages to help you with debugging. Copy andpaste the code into MODx only when you're sure it's working.

Don't try to mix PHP and HTML in a Snippet.

Snippets execute PHP code. They should always begin with a and end with a For<?php ?> You cannot mix PHP and HTML in a Snippet!example, the following code won't work:

<p>This is a horrible mixture of HTML and PHP</p><?php

;return "<p>and PHP!&nbsp; Don't it!&nbsp; It's bad architecture and it won't work!!</p>"try?>

You'll find that MODx will append PHP tags to beginning and end of the snippet, creating an invalid syntax, e.g.:

<?php <?php //something here ?> ?>

If you need to do something like this, - separate the PHP into a Snippet, load its output into a placeholder with the use a Chunk modx APIplaceholder functions or chunk processing, and include the Snippet's placeholders in the Chunk:

Page 151: ModX Revolution Docs 20101007

$output = $modx->getChunk('myChunk',array( 'placeholderOne' => 'test', 'name' => 'Harry', 'scar' => 'Lightning',));

$output;return

Don't Work on Live Snippets

If you're writing new versions of Snippets, the old version! That way you can go back to the old version of the code if something doesn'tduplicatework correctly! MODx doesn't inherently do versioning control, so you have to backup code yourself.

Use Default Properties

Consider adding your properties for your snippet into the Properties grid, so that the user can add custom to override them.Property Sets

See Also

modX.runSnippetmodX.setPlaceholdermodX.regClientCSS

Templating Your Snippets

Templating Snippets

One of the best practices in Snippet design is to make sure that you never write HTML directly in the Snippet, but template out the HTML intoChunks. This tutorial shows you how to do that in a Snippet.

Templating SnippetsOur Initial SnippetTemplating the SnippetAdding A Row ClassPassing a Custom ID

See Also

Our Initial Snippet

Let's take a case scenario; say you want to iterate across the published, non-deleted Resources that are children of the Resource with ID 390,sorted by menuindex, and then output them as LI tags with the pagetitle and a link to click them.

Go ahead and create a snippet called 'ResourceLister', and put this inside:

Page 152: ModX Revolution Docs 20101007

/* first, build the query */$c = $modx->newQuery('modResource');/* we only want published and undeleted resources */$c->where(array( 'published' => ,true 'deleted' => ,false));/* get all the children of ID 390 */$children = $modx->getChildIds(390);

(count($children) > 0) {if $c->where(array( 'id:IN' => $children, ));}/* sort by menuindex ascending */$c->sortby('menuindex','ASC');/* get the resources as xPDOObjects */$resources = $modx->getCollection('modResource',$c);

$output = '';foreach ($resources as $resource) { $output .= '<li><a href="'.$modx->makeUrl($resource->get('id')).'">'.$resource->get('pagetitle').'</a></li>';}

$output;return

This does what we want, but puts the HTML inline. We don't want that. It doesn't let the user control the markup, or change it if they want to. Wewant more flexibility.

Templating the Snippet

First off, let's create a chunk that we'll use for each item in the result set. Call it "ResourceItem", and make this its content:

<li><a href= >[[+pagetitle]]</a></li>"[[~[[+id]]]]"

Basically, we make an LI tag, and put some placeholders were our content was. We have available any field in the Resource, and here we're justusing the ID and pagetitle fields. The [[~ tells MODx to make a link from the ID passed in the [[+id]] property. Now let's add a default property tothe snippet, called 'tpl', to the top of our snippet code:

$tpl = $modx->getOption('tpl',$scriptProperties,'ResourceItem');

This gets us the &tpl= property from the Snippet call, since $scriptProperties just holds all the properties in the Snippet call. If 'tpl' doesn't exist,getOption defaults the value to ResourceItem (the Chunk we just made).

And then, change the foreach loop in the Snippet to this:

foreach ($resources as $resource) { $resourceArray = $resource->toArray(); $output .= $modx->getChunk($tpl,$resourceArray);}

The code first turns the modResource object into an array of field=name pairs (ie, $resourceArray['pagetitle'] is the pagetitle) via the toArray()method. Then, we use $modx->getChunk() to pass our tpl Chunk and the resource array into it as properties. MODx parses the chunk, replacesthe properties, and returns us some content.

Now the user can call the snippet this way to override the chunk for each Resource with this call:

[[!ResourceLister? &tpl=`MyOwnChunk`]]

Page 153: ModX Revolution Docs 20101007

Meaning they can template their results however they want - using LIs, or table rows, or whatever! You've now created a flexible, powerfulsnippet.

Adding A Row Class

What if we want the user to be able to specify a CSS class for each LI row, but not have to make their own custom chunk? Simple, we just add adefault property 'rowCls' to our snippet code at the top, below our first getOption call:

$rowCls = $modx->getOption('rowCls',$scriptProperties,'resource-item');

This tells MODx to default the &rowCls property for the snippet to 'resource-item'. Let's go edit our ResourceItem chunk:

<li class= ><a href= >[[+pagetitle]]</a></li>"[[+rowCls]]" "[[~[[+id]]]]"

And finally, change our foreach loop to this:

foreach ($resources as $resource) { $resourceArray = $resource->toArray(); $resourceArray['rowCls'] = $rowCls; $output .= $modx->getChunk($tpl,$resourceArray);}

Note how we're explicitly setting the 'rowCls' variable into our $resourceArray property array. We do this because we've already gotten the valueof rowCls earlier in the snippet (with the getOption call), and we know that it's not going to vary per row.

Passing a Custom ID

What if we want the user to be able to pass in what parent to grab resources from? Again, we just add a default property 'id' to our snippet code atthe top, below our getOption calls:

$id = ( )$modx->getOption('id',$scriptProperties,390);int

Basically, allow the user to override the parent ID for the Snippet - to say Resource 123, with an &id=`123` property - in their snippet call. But wewant it to default to 390. And then we'll change the getChildIds line to this:

$children = $modx->getChildIds($id);

Obviously, you could add more options to this snippet, such as firstRowCls (for only the first row in the results), lastRowCls, firstRowTpl, sortBy,sortDir, limit, or anything else you could dream up. We could even make it so the 'published' filter is a property as well, or hide resources that arefolders, etc. The important part is that now you have the general idea.

For reference, our final code looks like this:

Page 154: ModX Revolution Docs 20101007

$tpl = $modx->getOption('tpl',$scriptProperties,'ResourceItem');$id = ( )$modx->getOption('id',$scriptProperties,390);int$rowCls = $modx->getOption('rowCls',$scriptProperties,'resource-item');

$c = $modx->newQuery('modResource');$c->where(array( 'published' => ,true 'deleted' => ,false));$children = $modx->getChildIds($id);

(count($children) > 0) {if $c->where(array( 'id:IN' => $children, ));}$c->sortby('menuindex','ASC');$resources = $modx->getCollection('modResource',$c);

$output = '';foreach ($resources as $resource) { $resourceArray = $resource->toArray(); $resourceArray['cls'] = $rowCls; $output .= $modx->getChunk($tpl,$resourceArray);}

$output;return

See Also

Adding CSS and JS to Your Pages Through Snippets

Learning How to Register CSS and JS

So, you've got a Snippet that you've been writing and want to add CSS and/or JavaScript to your pages, but don't want to have to setup a customTemplate Variable and edit it on every Resource your Snippet is used on. You want the Snippet to do it, dagnabbit! Well, it's pretty easy, actually,using some MODx API methods.

Adding to the HEAD

There are a few methods that automatically add CSS and/or JavaScript to the HEAD of the current page. They will run in the order that they'readded, so if you need them in a certain order, make sure you execute the methods in that order as well.

regClientCSS

This function lets you register any CSS file to the HEAD of the content by providing the URL in the method:

$modx->regClientCSS('assets/css/my-custom.css');

regClientStartupScript

This function lets you register any custom JavaScript to the HEAD of the document:

$modx->regClientStartupScript('assets/js/site.js');

regClientStartupHTMLBlock

This function is useful if you need to set some JS variables, or output some HTML into the HEAD:

Page 155: ModX Revolution Docs 20101007

$modx->regClientStartupHTMLBlock('<meta tag= />"here"<script type= >"text/javascript"

myCustomJSVar = 123;var</script>');

Adding Before the BODY End

There are also methods that can be used to insert Javascript or HTML at the end of every page, right before the BODY tag closes. They are oftenuseful for custom analytics scripts, or JS that needs to be run at the body-level rather than in the HEAD.

regClientScript

Similar to except that it runs before the closing BODY tag:regClientStartupScript

$modx->regClientScript('assets/js/footer.js');

regClientHTMLBlock

Similar to except that it runs before the closing BODY tag:regClientStartupHTMLBlock

$modx->regClientStartupHTMLBlock('<div>custom stuff here</div><script type= >"text/javascript"runAnalytics();</script>');

Conclusion

MODx offers Extras developers many options on how to insert custom CSS/JS into their pages at the Snippet level. However, MODx alsorecommends in any Extras you are distributing, to make sure inserting CSS or JS into a page is a toggleable option, so that the user cancustomize the content or javascript framework should they so choose.

See Also

Plugins

What is a Plugin?The Event ModelHandling an EventPlugin Examples

Word FilterPage-Not-Found Redirector:

See Also

What is a Plugin?

Plugins are similar to snippets in that they are snippets of code that have access to the MODx API - however the big difference is that Plugins areassociated with specific System Events. For example, in an average MODx page request, several events happen at certain points within the pageparsing process and plugins can be attached to any of these events to fulfill a desired function. That means that when those events "fire," controlis transferred to any Plugin "listening" for that event. Once the Plugin's code has executed, control returns to the point after the spot where theSystem Event was triggered.

Plugins aren't limited to front-end processing, there are many events that are available in the MODx Manager. There is a list of MODx SystemEvents .here

The Event Model

Page 156: ModX Revolution Docs 20101007

MODx invokes System Events across its code processes to allow you to modify core functionality without hacking the core. These System Eventscan have any number of Plugins attached to them, and will execute each Plugin in rank according to it's priority.

Handling an Event

In your Plugin, how you handle the output depends on the System Event you are in. For some system events, you return a value from the Plugin.For others, you access the output directly and modify it.

If you need to know which event triggered your plugin (say, for a plugin that listens to more than one event), you can access the Event's name likeso:

$eventName = $modx->event->name;

The code for a Plugin listening to more than one event looks like this:

$eventName = $modx->event->name;($eventName) {switch

'OnWebPageInit':case /* something */do ;break 'OnWebPagePrerender':case /* something */do else ;break}

Plugin Examples

Plugins can be used for a variety of different applications, below are a couple of examples:

Word Filter

Description: Filter words from a document before it's displayed on the web OnWebPagePrerenderSystem Events:

$words = array( , ); "snippet" "template" // words to filter$output = &$modx->resource->_output; // get a reference to the output$output = str_replace($words, ,$output);"<b>[filtered]</b>"

Page-Not-Found Redirector:

Description: Redirects a user to selected document and sends a message OnPageNotFoundSystem Events:

System Settings:

pnf.page: Error Resource IDpnf.mailto: Mail To Addresspnf.mailfrom: Mail From Address

Page 157: ModX Revolution Docs 20101007

if ($modx->event->name == 'OnPageNotFound') { $errorPage = $modx->getOption('pnf.page'); (empty($errorPage)) {if $modx->sendErrorPage(); } {else $mailto = $modx->getOption('pnf.mailto'); (!empty($mailto)) {if // send a message to a local account$resourceId = $modx->resource->get('id'); $subject = 'Page not found'; $body = 'Someone tried to access document id '.$resourceId; $modx->getService('mail', 'mail.modPHPMailer'); $modx->mail->set(modMail::MAIL_BODY, $body); $modx->mail->set(modMail::MAIL_FROM, '$modx->getOption('pnf.mailfrom')); $modx->mail->set(modMail::MAIL_FROM_NAME, 'MODx'); $modx->mail->set(modMail::MAIL_SENDER, 'MODx'); $modx->mail->set(modMail::MAIL_SUBJECT, $subject); $modx->mail->address('to',$mailto); $modx->mail->setHTML( );true $modx->mail->send(); } $url = $ ->makeUrl($scriptProperties['page']);this $modx->sendRedirect($url, 1); exit; }}

See Also

System Events

What are System Events?The Model of a System Event

Service TypesAvailable EventsSee Also

What are System Events?

System Events are the events in MODx that are registered to. They are 'fired' throughout the MODx code, allowing Plugins to interact withPluginsMODx code and add custom functionality without hacking core code.

The Model of a System Event

The system events table is found under {table_prefix}_system_eventnames, and has the following fields:

id - The unique ID of the event.name - The name of the event. This is how they are referenced in code, via the method.modX.invokeEventservice - What type of system event this event is.groupname - Used for user interfaces, primarily for filtering, grouping and sorting of events. Not used explicitly in the modx model.

Service Types

The 'service' field in the System event is a number; the numbers reference different types of System Events. They are:

1 - Parser Service Events2 - Manager Access Events3 - Web Access Service Events4 - Cache Service Events5 - Template Service Events6 - User Defined Events

Page 158: ModX Revolution Docs 20101007

3 is not fired in the 'mgr' context; 2 is not fired in any context but 'mgr'.

Available Events

This is not an exhaustive list as events are still being documented. Thank you for your patience. The TV, Template and Snippetevents are still to be documented. For a complete list, please either view a Plugin in the manager and see the System Eventstab, or view . Note also that all WUsr (web-user) events have been removed.here

See Also

OnBeforeCacheUpdate

Event: OnBeforeCacheUpdate

Fired before the entire site cache is cleared.

Service: 4 - Cache Service EventsGroup: None

Event Parameters

None.

See Also

System EventsPlugins

OnBeforeChunkFormDelete

Event: OnBeforeChunkFormDelete

Fires before a chunk is deleted.

Service: 1 - Parser Service EventsGroup: Chunks

Event Parameters

Name Description

chunk A reference to the modChunk object.

id The ID of the Chunk.

See Also

System EventsPlugins

OnBeforeChunkFormSave

Event: OnBeforeChunkFormSave

Page 159: ModX Revolution Docs 20101007

Fires after a form is submitted but before a Chunk is saved in the manager.

Service: 1 - Parser Service EventsGroup: Chunks

Event Parameters

Name Description

mode Either 'upd' or 'new', depending on the circumstance.

chunk A reference to the modChunk object.

id The ID of the chunk. Will be 0 for new chunks.

See Also

System EventsPlugins

OnBeforeDocFormDelete

Event: OnBeforeDocFormDelete

Fires before a Resource is deleted via the manager.

Service: 1 - Parser Service EventsGroup: Documents

Event Parameters

Name Description

resource A reference to the modResource object.

id The ID of the Resource.

children An array of IDs of children of this resource which will also be deleted.

See Also

System EventsPlugins

OnBeforeDocFormSave

Event: OnBeforeDocFormSave

Fires before a Resource is saved in the manager via the editing form.

Service: 1 - Parser Service EventsGroup: Documents

Event Parameters

Name Description

mode Either 'new' or 'upd', depending on the circumstances.

resource A reference to the modResource object.

id The ID of the Resource. Will be 0 for new Resources.

See Also

Page 160: ModX Revolution Docs 20101007

System EventsPlugins

OnBeforeManagerLogout

Event: OnBeforeManagerLogout

Fires before a user is logged out of the manager.

Service: 2 - Manager Access Service EventsGroup: None

Event Parameters

Name Description

user A reference to the modUser object of the user.

userid The user ID of the user. (deprecated)

username The username of the user. (deprecated)

See Also

System EventsPlugins

OnBeforeSaveWebPageCache

Event: OnBeforeSaveWebPageCache

Fired after the Resource is loaded and before the Resource is cached. If the Resource is not cacheable, this event will not fire.

Service: 4 - Cache Service EventsGroup: None

Event Parameters

None. The resource can be referenced via $modx->resource.

See Also

System EventsPlugins

OnBeforeWebLogout

Event: OnBeforeWebLogout

Fires right before a user logs out of a non-mgr context.

Service: 3 - Web Access Service EventsGroup: None

Event Parameters

Name Description

user A reference to the modUser object of the user.

userid The user ID of the user.

username The username of the user.

Page 161: ModX Revolution Docs 20101007

See Also

System EventsPlugins

OnCacheUpdate

Event: OnCacheUpdate

Fired after the cache is cleared at any time.

Service: 4 - Cache Service EventsGroup: None

Event Parameters

Name Description

results The results of the clearing.

paths An array of paths that were to be cleared.

options An array of options passed to the cache clearing method.

See Also

System EventsPlugins

OnChunkFormDelete

Event: OnChunkFormDelete

Fires after a chunk is deleted.

Service: 1 - Parser Service EventsGroup: Chunks

Event Parameters

Name Description

chunk A reference to the modChunk object.

id The ID of the Chunk.

See Also

System EventsPlugins

OnChunkFormPrerender

Event: OnChunkFormPrerender

Occurs before the chunk modification form is rendered, but after the JS is registered. Can be used to render custom Javascript for the mgr.

Service: 1 - Parser Service EventsGroup: Chunks

Event Parameters

Page 162: ModX Revolution Docs 20101007

Name Description

mode Either 'new' or 'upd', depending on the circumstance.

id The ID of the Chunk. This will be 0 for new chunks.

chunk A reference to the modChunk object. Will be null in new chunks.

See Also

System EventsPlugins

OnChunkFormRender

Event: OnChunkFormRender

Fires during the rendering of a form. Useful for rendering HTML straight into the Chunk form.

Service: 1 - Parser Service EventsGroup: Chunks

Event Parameters

Name Description

mode Either 'new' or 'upd', depending on the circumstance.

id The ID of the Chunk. This will be 0 for new chunks.

chunk A reference to the modChunk object. Will be null in new chunks.

See Also

System EventsPlugins

OnChunkFormSave

Event: OnChunkFormSave

Fires after a Chunk is saved in the manager.

Service: 1 - Parser Service EventsGroup: Chunks

Event Parameters

Name Description

mode Either 'upd' or 'new', depending on the circumstance.

chunk A reference to the modChunk object.

id The ID of the chunk.

See Also

System EventsPlugins

OnDocFormDelete

Page 163: ModX Revolution Docs 20101007

Event: OnDocFormDelete

Fires after a Resource is deleted via the manager.

Service: 1 - Parser Service EventsGroup: Documents

Event Parameters

Name Description

resource A reference to the modResource object.

id The ID of the Resource.

children An array of IDs of children of this resource which were deleted.

See Also

System EventsPlugins

OnDocFormPrerender

Event: OnDocFormPrerender

Fires before a Resource editing form is loaded in the manager.

Service: 1 - Parser Service EventsGroup: Documents

Event Parameters

Name Description

mode Either 'new' or 'upd', depending on the circumstance.

resource A reference to the modResource object. Will be null for new Resources.

id The ID of the Resource. Will be 0 for new Resources.

See Also

System EventsPlugins

OnDocFormRender

Event: OnDocFormRender

Fires after a Resource editing form is loaded in the manager. Useful for inserting HTML into forms.

Service: 1 - Parser Service EventsGroup: Documents

Event Parameters

Name Description

mode Either 'new' or 'upd', depending on the circumstance.

resource A reference to the modResource object. Will be null for new Resources.

id The ID of the Resource. Will be 0 for new Resources.

Page 164: ModX Revolution Docs 20101007

See Also

System EventsPlugins

OnDocFormSave

Event: OnDocFormSave

Fires after a Resource is saved in the manager via the editing form.

Service: 1 - Parser Service EventsGroup: Documents

Event Parameters

Name Description

mode Either 'new' or 'upd', depending on the circumstances.

resource A reference to the modResource object.

id The ID of the Resource. Will be 0 for new Resources.

See Also

System EventsPlugins

OnDocPublished

Event: OnDocPublished

Called when a Resource is published via the Publish context menu.

Service: 5 - Template Service EventsGroup: None

Event Parameters

Name Description

docid The ID of the resource being published. (deprecated)

id The ID of the resource being published.

resource A reference to the modResource object being published.

See Also

System EventsPlugins

OnDocUnPublished

Event: OnDocUnPublished

Called when a Resource is unpublished via the Unpublish context menu.

Service: 5 - Template Service EventsGroup: None

Event Parameters

Page 165: ModX Revolution Docs 20101007

Name Description

docid The ID of the resource being unpublished. (deprecated)

id The ID of the resource being unpublished.

resource A reference to the modResource object being unpublished.

See Also

System EventsPlugins

OnLoadWebPageCache

Event: OnLoadWebPageCache

Fires after a Resource is loaded from the cache. If the Resource is not cached, this event will not fire.

Service: 4 - Cache Service EventsGroup: None

Event Parameters

None.

See Also

System EventsPlugins

OnManagerLogin

Event: OnManagerLogin

Fires anytime a user successfully logs into the manager.

Service: 2 - Manager Access Service EventsGroup: None

Event Parameters

Name Description

user A reference to the modUser object.

attributes An array of:

rememberme - Boolean set if user wants password to be remembered.lifetime - The session cookie lifetime for this login.loginContext - The context key this login is occurring in.

See Also

System EventsPlugins

OnManagerLogout

Event: OnManagerLogout

Fires after a user is logged out of the manager and their context session is removed.

Page 166: ModX Revolution Docs 20101007

Service: 2 - Manager Access Service EventsGroup: None

Event Parameters

Name Description

user A reference to the modUser object of the user.

userid The user ID of the user. (deprecated)

username The username of the user. (deprecated)

See Also

System EventsPlugins

OnSiteRefresh

Event: OnSiteRefresh

Fires after the cache for the entire site is cleared.

Service: 1 - Parser Service EventsGroup: None

Event Parameters

Name Description

results An array of results.

See Also

System EventsPlugins

OnUserChangePassword

Event: OnUserChangePassword

Fires anytime the user properly changes their password.

Service: 3 - Template Service EventsGroup: None

Event Parameters

Name Description

user A reference to the modUser object of the user.

newpassword The new password being set.

oldpassword The old password being overridden.

userid The user ID of the user. (deprecated)

username The username of the user. (deprecated)

userpassword The new password being set. (deprecated)

See Also

Page 167: ModX Revolution Docs 20101007

System EventsPlugins

OnWebLogin

Event: OnWebLogin

Fired anytime a user logs into a non-mgr context.

Service: 3 - Web Access Service EventsGroup: None

Event Parameters

Name Description

user A reference to the modUser object.

attributes An array of:

rememberme - Boolean set if user wants password to be remembered.lifetime - The session cookie lifetime for this login.loginContext - The context key this login is occurring in.

See Also

System EventsPlugins

OnWebLogout

Event: OnWebLogout

Fires right after the user logs out of a context and their context session is removed.

Service: 3 - Web Access Service EventsGroup: None

Event Parameters

Name Description

user A reference to the modUser object of the user.

userid The user ID of the user.

username The username of the user.

See Also

System EventsPlugins

OnWebPagePrerender

Event: OnWebPagePrerender

Fired after a Resource is parsed, but before it is rendered.

Content Type headers have not yet been sent, nor has the output been flushed.

Service: 5 - Template Service Events

Page 168: ModX Revolution Docs 20101007

Group: None

Event Parameters

None.

See Also

System EventsPlugins

OnBeforeEmptyTrash

Event: OnBeforeEmptyTrash

Fires before the trash is emptied for the site.

Service: 1 - Parser Service EventsGroup: Documents

Event Parameters

Name Description

ids An array of Resource IDs that will be permanently deleted.

See Also

System EventsPlugins

OnBeforeManagerLogin

Event: OnBeforeManagerLogin

Fires before the login process is started for a user when logging in to the manager context.

Service: 3 - Web Access EventsGroup: None

Event Parameters

Name Description

username The provided username.

password The provided password.

attributes An array of:

rememberme - Boolean set if user wants password to be remembered.lifetime - The session cookie lifetime for this login.loginContext - The context key this login is occurring in.

See Also

System EventsPlugins

OnBeforeManagerPageInit

Event: OnBeforeManagerPageInit

Page 169: ModX Revolution Docs 20101007

Loaded right before a manager controller is run.

Service: 2 - Manager Access EventsGroup: None

Event Parameters

Name Description

action The ID of the action being loaded.

filename The filename of the controller being loaded.

See Also

System EventsPlugins

OnBeforePluginFormDelete

Event: OnBeforePluginFormDelete

Fires before a plugin is deleted in the manager.

Service: 1 - Parser Service EventsGroup: Plugins

Event Parameters

Name Description

plugin A reference to the modPlugin object.

id The ID of the Plugin.

See Also

System EventsPlugins

OnBeforePluginFormSave

Event: OnBeforePluginFormSave

Fires after a form is submitted but before a Plugin is saved in the manager.

Service: 1 - Parser Service EventsGroup: Plugin

Event Parameters

Name Description

mode Either 'upd' or 'new', depending on the circumstance.

plugin A reference to the modPlugin object.

id The ID of the plugin. Will be 0 for new plugins.

See Also

System EventsPlugins

Page 170: ModX Revolution Docs 20101007

OnBeforeSnipFormDelete

Event: OnBeforeSnipFormDelete

Fires before a Snippet is deleted in the manager.

Service: 1 - Parser Service EventsGroup: Snippets

Event Parameters

Name Description

snippet A reference to the modSnippet object.

id The ID of the Snippet.

See Also

System EventsPlugins

OnBeforeSnipFormSave

Event: OnBeforeSnipFormSave

Fires after a form is submitted but before a Snippet is saved in the manager.

Service: 1 - Parser Service EventsGroup: Snippets

Event Parameters

Name Description

mode Either 'upd' or 'new', depending on the circumstance.

snippet A reference to the modSnippet object.

id The ID of the Snippet. Will be 0 for new Snippets.

See Also

System EventsPlugins

OnBeforeTempFormDelete

Event: OnBeforeTempFormDelete

Fires before a Template is deleted in the manager.

Service: 1 - Parser Service EventsGroup: Templates

Event Parameters

Name Description

template A reference to the modTemplate object.

id The ID of the Template.

Page 171: ModX Revolution Docs 20101007

See Also

System EventsPlugins

OnBeforeTempFormSave

Event: OnBeforeTempFormSave

Fires after a form is submitted but before a Template is saved in the manager.

Service: 1 - Parser Service EventsGroup: Templates

Event Parameters

Name Description

mode Either 'upd' or 'new', depending on the circumstance.

template A reference to the modTemplate object.

id The ID of the Template. Will be 0 for new Templates.

See Also

System EventsPlugins

OnBeforeTVFormDelete

Event: OnBeforeTVFormDelete

Fires before a TV is deleted in the manager.

Service: 1 - Parser Service EventsGroup: Template Variables

Event Parameters

Name Description

tv A reference to the modTemplateVar object.

id The ID of the TV.

See Also

System EventsPlugins

OnBeforeTVFormSave

Event: OnBeforeTVFormSave

Fires after a form is submitted but before a Chunk is saved in the manager.

Service: 1 - Parser Service EventsGroup: Template Variables

Event Parameters

Page 172: ModX Revolution Docs 20101007

Name Description

mode Either 'upd' or 'new', depending on the circumstance.

tv A reference to the modTemplateVar object.

id The ID of the TV. Will be 0 for new TVs.

See Also

System EventsPlugins

OnBeforeUserActivate

Event: OnBeforeUserActivate

Never fired in MODx core; can be used by 3rd Party Components (such as ) when a User is being activated.Login

Service: 1 - Parser Service EventsGroup: modUser

Event Parameters

Depends on implementation.

See Also

System EventsPlugins

OnBeforeUserFormDelete

Event: OnBeforeUserFormDelete

Fires before a User is deleted in the manager.

Service: 1 - Parser Service EventsGroup: Users

Event Parameters

Name Description

user A reference to the modUser object.

id The ID of the User.

See Also

System EventsPlugins

OnBeforeUserFormSave

Event: OnBeforeUserFormSave

Fires after a form is submitted but before a User is saved in the manager.

Service: 1 - Parser Service EventsGroup: Users

Event Parameters

Page 173: ModX Revolution Docs 20101007

Name Description

mode Either 'upd' or 'new', depending on the circumstance.

user A reference to the modUser object.

id The ID of the User. Will be 0 for new Users.

See Also

System EventsPlugins

OnBeforeWebLogin

Event: OnBeforeWebLogin

Fires before the login process is started for a user when logging in via a non-manager context.

Service: 3 - Web Access EventsGroup: None

Event Parameters

Name Description

username The provided username.

password The provided password.

attributes An array of:

rememberme - Boolean set if user wants password to be remembered.lifetime - The session cookie lifetime for this login.loginContext - The context key this login is occurring in.

See Also

System EventsPlugins

OnCategoryBeforeRemove

Event: OnCategoryBeforeRemove

Happens right before a category is removed.

Service: 2 - Manager Access EventsGroup: Categories

Event Parameters

Name Description

category A reference to the modCategory object.

See Also

System EventsPlugins

OnCategoryBeforeSave

Page 174: ModX Revolution Docs 20101007

Event: OnCategoryBeforeSave

Happens right before a category is saved.

Service: 2 - Manager Access EventsGroup: Categories

Event Parameters

Name Description

id The ID of the modCategory object.

category A reference to the modCategory object.

See Also

System EventsPlugins

OnCategoryRemove

Event: OnCategoryRemove

Happens after a category is removed.

Service: 2 - Manager Access EventsGroup: modCategory

Event Parameters

Name Description

category A reference to the modCategory object.

See Also

System EventsPlugins

OnCategorySave

Event: OnCategorySave

Happens after a category is saved.

Service: 2 - Manager Access EventsGroup: modCategory

Event Parameters

Name Description

category A reference to the modCategory object.

See Also

System EventsPlugins

OnChunkBeforeRemove

Page 175: ModX Revolution Docs 20101007

Event: OnChunkBeforeRemove

Fires right before a Chunk is removed.

Service: 1 - Parser Service EventsGroup: modChunk

Event Parameters

Name Description

chunk A reference to the modChunk object.

See Also

System EventsPlugins

OnChunkBeforeSave

Event: OnChunkBeforeSave

Fires right before a Chunk is saved.

Service: 1 - Parser Service EventsGroup: modChunk

Event Parameters

Name Description

chunk A reference to the modChunk object.

See Also

System EventsPlugins

OnChunkRemove

Event: OnChunkRemove

Happens after a chunk is removed.

Service: 2 - Manager Access EventsGroup: modChunk

Event Parameters

Name Description

chunk A reference to the modChunk object.

See Also

System EventsPlugins

OnChunkSave

Page 176: ModX Revolution Docs 20101007

Event: OnChunkSave

Happens after a chunk is saved.

Service: 2 - Manager Access EventsGroup: modChunk

Event Parameters

Name Description

chunk A reference to the modChunk object.

See Also

System EventsPlugins

OnContextBeforeRemove

Event: OnContextBeforeRemove

Happens right before a context is removed.

Service: 2 - Manager Access EventsGroup: modContext

Event Parameters

Name Description

context A reference to the modContext object.

See Also

System EventsPlugins

OnContextBeforeSave

Event: OnContextBeforeSave

Happens right before a context is saved.

Service: 2 - Manager Access Events

Event Parameters

Name Description

context A reference to the modContext object.

mode Either 'new' (modSystemEvent::MODE_NEW) or 'upd' (modSystemEvent::MODE_UPD) depending on whether is a new object or anexisting one.

See Also

System EventsPlugins

OnContextFormPrerender

Page 177: ModX Revolution Docs 20101007

Event: OnContextFormPrerender

Fires prior to the context editing form loading. Useful for running custom javascript.

Service: 2 - Manager Access EventsGroup: modContext

Event Parameters

Name Description

key The key of the context.

context A reference to the modContext object.

mode Either 'upd' or 'new', depending on the situation.

See Also

System EventsPlugins

OnContextFormRender

Event: OnContextFormRender

Fires after the context editing form has loaded.

Service: 2 - Manager Access EventsGroup: modContext

Event Parameters

Name Description

key The key of the context.

context A reference to the modContext object.

mode Either 'upd' or 'new', depending on the situation.

See Also

System EventsPlugins

OnContextRemove

Event: OnContextRemove

Happens after a context is removed.

Service: 2 - Manager Access EventsGroup: modContext

Event Parameters

Name Description

context A reference to the modContext object.

See Also

System EventsPlugins

Page 178: ModX Revolution Docs 20101007

OnContextSave

Event: OnContextSave

Happens whenever a context is saved.

Service: 2 - Manager Access Events

Event Parameters

Name Description

context A reference to the modContext object.

mode Either 'new' (modSystemEvent::MODE_NEW) or 'upd' (modSystemEvent::MODE_UPD) depending on whether is a new object or anexisting one.

See Also

System EventsPlugins

OnEmptyTrash

Event: OnEmptyTrash

Fires after the trash is emptied for the site.

Service: 1 - Parser Service EventsGroup: Documents

Event Parameters

Name Description

ids An array of Resource IDs that were attempted to be permanently deleted.

num_deleted The number of Resources actually deleted.

See Also

System EventsPlugins

OnFileManagerUpload

Event: OnFileManagerUpload

Fires after any files are uploaded via the manager.

Service: 1 - Parser Service EventsGroup: None

Event Parameters

Name Description

files An array of files from the PHP $_FILES array.

directory A reference to the modDirectory object that the files are being uploaded to.

See Also

Page 179: ModX Revolution Docs 20101007

System EventsPlugins

OnHandleRequest

Event: OnHandleRequest

Fires at the beginning of a request handler.

Service: 5 - Template Service EventsGroup: None

Event Parameters

None.

See Also

System EventsPlugins

OnInitCulture

Event: OnInitCulture

Fires after a Culture and Lexicon has been initialized.

Service: 1 - Parser Service EventsGroup: None

Event Parameters

None.

See Also

System EventsPlugins

OnLoadWebDocument

Event: OnLoadWebDocument

Fires directly before the Response is sent and after a Resource is loaded.

Service: 5 - Template Service EventsGroup: None

Event Parameters

None. The resource can be referenced via $modx->resource.

See Also

System EventsPlugins

OnManagerAuthentication

Event: OnManagerAuthentication

Page 180: ModX Revolution Docs 20101007

Fires right before the user is authenticated or its session is added to the manager context. This event can be used to provide externalauthentication support.

If its output is true, or an array where at least one index is set to true, then MODx will assume that the user has successfully logged in and bypassthe default authentication via password.

Service: 2 - Manager Access EventsGroup: None

Event Parameters

Name Description

user A reference to the modUser object.

password The provided password.

rememberme Whether or not to remember the user via cookie.

lifetime The lifetime of the session cookie.

See Also

System EventsPlugins

OnManagerLoginFormPrerender

Event: OnManagerLoginFormPrerender

Fires before the login form is rendered for the MODx manager.

Service: 2 - Manager Access EventsGroup: None

Event Parameters

None.

See Also

System EventsPlugins

OnManagerLoginFormRender

Event: OnManagerLoginFormRender

Fires when the login form is rendered for the MODx manager. Useful for inserting custom HTML into the login form.

Service: 2 - Manager Access EventsGroup: None

Event Parameters

None.

See Also

System EventsPlugins

OnManagerPageInit

Page 181: ModX Revolution Docs 20101007

Event: OnManagerPageInit

Fired in the manager request handler, before the manager page response is loaded.

Service: 2 - Manager Access EventsGroup: None

Event Parameters

Name Description

action The ID of the action currently being loaded.

See Also

System EventsPlugins

OnPageNotFound

Event: OnPageNotFound

Fires immediately before the user is forwarded to the error page if attempting to view a non-existent Resource.

Service: 1 - Parser Service EventsGroup: None

Event Parameters

Name Description

response_code The response code to send. Defaults to "HTTP/1.1 404 Not Found"

error_type The type. Defaults to 404.

error_header The header being sent: Defaults to "HTTP/1.1 404 Not Found"

error_pagetitle The pagetitle of the error page.

error_message The message being sent in the error page.

See Also

System EventsPlugins

OnPageUnauthorized

Event: OnPageUnauthorized

Fires immediately before the user is forwarded to the unauthorized page if attempting to view a non-accessible Resource.

Service: 1 - Parser Service EventsGroup: None

Event Parameters

Name Description

response_code The response code to send. Defaults to "HTTP/1.1 401 Unauthorized"

error_type The type. Defaults to 401.

error_header The header being sent: Defaults to "HTTP/1.1 401 Unauthorized"

Page 182: ModX Revolution Docs 20101007

error_pagetitle The pagetitle of the unauthorized page.

error_message The message being sent in the unauthorized page.

See Also

System EventsPlugins

OnParseDocument

Event: OnParseDocument

Fires on each time the Element tags are parsed. This can happen many times during the loading of a Resource. To reference the content of theResource, use $modx->documentOutput.

Service: 1 - Template Service EventsGroup: None

Event Parameters

None.

See Also

System EventsPlugins

OnPluginBeforeRemove

Event: OnPluginBeforeRemove

Happens right before a plugin is removed.

Service: 2 - Manager Access EventsGroup: modPlugin

Event Parameters

Name Description

plugin A reference to the modPlugin object.

See Also

System EventsPlugins

OnPluginBeforeSave

Event: OnPluginBeforeSave

Happens right before a plugin is saved.

Service: 2 - Manager Access EventsGroup: modPlugin

Event Parameters

Name Description

plugin A reference to the modPlugin object.

Page 183: ModX Revolution Docs 20101007

See Also

System EventsPlugins

OnPluginEventRemove

Event: OnPluginEventRemove

Fires after a plugin is disassociated directly from an event.

Service: 1 - Parser Service EventsGroup: None

Event Parameters

Name Description

id The id of the modPluginEvent object

pluginEvent A reference to the modPluginEvent object

See Also

System EventsPlugins

OnPluginFormDelete

Event: OnPluginFormDelete

Fires after a plugin is deleted.

Service: 1 - Parser Service EventsGroup: Plugins

Event Parameters

Name Description

chunk A reference to the modPlugin object.

id The ID of the Plugin.

See Also

System EventsPlugins

OnPluginFormPrerender

Event: OnPluginFormPrerender

Occurs before the plugin modification form is rendered, but after the JS is registered. Can be used to render custom Javascript for the mgr.

Service: 1 - Parser Service EventsGroup: Plugins

Event Parameters

Name Description

Page 184: ModX Revolution Docs 20101007

mode Either 'new' or 'upd', depending on the circumstance.

id The ID of the Plugin. Will be 0 for new plugins.

plugin A reference to the modPlugin object. Will be null in new plugins.

See Also

System EventsPlugins

OnPluginFormRender

Event: OnPluginFormRender

Fires during the rendering of a form. Useful for rendering HTML straight into the Plugin form.

Service: 1 - Parser Service EventsGroup: Plugins

Event Parameters

Name Description

mode Either 'new' or 'upd', depending on the circumstance.

id The ID of the Plugin. This will be 0 for new plugins.

chunk A reference to the modPlugin object. Will be null in new plugins.

See Also

System EventsPlugins

OnPluginFormSave

Event: OnPluginFormSave

Fires after a Plugin is saved in the manager.

Service: 1 - Parser Service EventsGroup: Plugins

Event Parameters

Name Description

mode Either 'upd' or 'new', depending on the circumstance.

chunk A reference to the modPlugin object.

id The ID of the plugin.

See Also

System EventsPlugins

OnPluginRemove

Event: OnPluginRemove

Page 185: ModX Revolution Docs 20101007

Happens right after a plugin is removed.

Service: 2 - Manager Access EventsGroup: modPlugin

Event Parameters

Name Description

plugin A reference to the modPlugin object.

See Also

System EventsPlugins

OnPluginSave

Event: OnPluginSave

Happens right after a plugin is removed.

Service: 2 - Manager Access EventsGroup: modPlugin

Event Parameters

Name Description

plugin A reference to the modPlugin object.

See Also

System EventsPlugins

OnPropertySetBeforeRemove

Event: OnPropertySetBeforeRemove

Fires right before a Property Set is removed.

Service: 1 - Parser Service Events

Event Parameters

Name Description

propertySet A reference to the modPropertySet object.

See Also

System EventsPlugins

OnPropertySetBeforeSave

Event: OnPropertySetBeforeSave

Fires right before a Property Set is saved.

Service: 1 - Parser Service Events

Page 186: ModX Revolution Docs 20101007

Event Parameters

Name Description

propertySet A reference to the modPropertySet object.

See Also

System EventsPlugins

OnPropertySetRemove

Event: OnPropertySetRemove

Fires after a Property Set is removed.

Service: 1 - Parser Service Events

Event Parameters

Name Description

propertySet A reference to the modPropertySet object.

See Also

System EventsPlugins

OnPropertySetSave

Event: OnPropertySetSave

Fires right after a Property Set is saved.

Service: 1 - Parser Service Events

Event Parameters

Name Description

propertySet A reference to the modPropertySet object.

See Also

System EventsPlugins

OnResourceGroupBeforeRemove

Event: OnResourceGroupBeforeRemove

Fires right before a Resource Group is removed.

Service: 1 - Parser Service Events

Event Parameters

Name Description

Page 187: ModX Revolution Docs 20101007

group A reference to the modResourceGroup object.

See Also

System EventsPlugins

OnResourceGroupBeforeSave

Event: OnResourceGroupBeforeSave

Fires right before a Resource Group is saved.

Service: 1 - Parser Service EventsGroup: modResourceGroup

Event Parameters

Name Description

group A reference to the modResourceGroup object.

See Also

System EventsPlugins

OnResourceGroupRemove

Event: OnResourceGroupRemove

Fires after a Resource Group is removed.

Service: 1 - Parser Service Events

Event Parameters

Name Description

group A reference to the modResourceGroup object.

See Also

System EventsPlugins

OnResourceGroupSave

Event: OnResourceGroupSave

Fires after a Resource Group is saved.

Service: 1 - Parser Service EventsGroup: modResourceGroup

Event Parameters

Name Description

group A reference to the modResourceGroup object.

Page 188: ModX Revolution Docs 20101007

See Also

System EventsPlugins

OnRichTextBrowserInit

Event: OnRichTextBrowserInit

Used to handle MODx.Browser's filesystem implementation for custom RTEs.

Simply pass in a Javascript function that will handle the return url for the file selected from MODx.Browser to your RTE.

Service: 1 - Parser Service EventsGroup: Richtext Editor

Event Parameters

None.

See Also

System EventsPlugins

OnRichTextEditorInit

Event: OnRichTextEditorInit

Renders anytime a Richtext Editor could be used.

Service: 1 - Parser Service EventsGroup: Richtext Editor

Event Parameters

Name Description

editor The specified editor that the user wants to use.

elements An array of elements to transform into an RTE.

Other properties might be passed, such as:

forfrontend If passed, this will indicate to the plugin that this is to be loaded in a front-end context, not the manager.

width The requested width of the RTE.

height The requested height of the RTE.

See Also

System EventsPlugins

OnRichTextEditorRegister

Event: OnRichTextEditorRegister

Renders during any dropdown or select for available richtext editors for MODx.

If you are developing a custom RTE, simply return the name of the RTE that you are developing. This will then be matched to the System Setting'which_editor', which will allow users to select your RTE to use.

Page 189: ModX Revolution Docs 20101007

Service: 1 - Parser Service EventsGroup: Richtext Editor

Event Parameters

None.

See Also

System EventsPlugins

OnSiteSettingsRender

Event: OnSiteSettingsRender

Fires before the system settings page is rendered. Useful for adding custom HTML into the System Settings page.

Service: 1 - Parser Service EventsGroup: System Settings

Event Parameters

None.

See Also

System EventsPlugins

OnUserActivate

Event: OnUserActivate

Never fired in MODx core; can be used by 3rd Party Components (such as ) when a User is being activated.Login

Service: 1 - Parser Service EventsGroup: modUser

Event Parameters

Depends on implementation.

See Also

System EventsPlugins

OnUserBeforeRemove

Event: OnUserBeforeRemove

Fires right before a User is removed.

Service: 1 - Parser Service EventsGroup: modUser

Event Parameters

Name Description

user A reference to the modUser object.

Page 190: ModX Revolution Docs 20101007

See Also

System EventsPlugins

OnUserBeforeSave

Event: OnUserBeforeSave

Fires right before a User is saved.

Service: 1 - Parser Service EventsGroup: modUser

Event Parameters

Name Description

user A reference to the modUser object.

mode Either 'new' (modSystemEvent::MODE_NEW) or 'upd' (modSystemEvent::MODE_UPD) depending on whether is a new object or anexisting one.

See Also

System EventsPlugins

OnUserFormDelete

Event: OnUserFormDelete

Fires after a User is deleted.

Service: 1 - Parser Service EventsGroup: modUser

Event Parameters

Name Description

user A reference to the modUser object.

id The ID of the user.

See Also

System EventsPlugins

OnUserFormSave

Event: OnUserFormSave

Fires after a User is updated via the manager form.

Service: 1 - Parser Service EventsGroup: modUser

Event Parameters

Page 191: ModX Revolution Docs 20101007

Name Description

user A reference to the modUser object.

id The ID of the user.

See Also

System EventsPlugins

OnUserNotFound

Event: OnUserNotFound

Fires when a user is not found during login.

Can be used to provide external authentication by returning an array, where one of the indexes in the array is an instance of (or extending) amodUser object.

Service: 6 - User Defined EventsGroup: modUser

Event Parameters

Name Description

username The specified username.

password The specified password.

attributes An array of:

rememberme - Boolean set if user wants password to be remembered.lifetime - The session cookie lifetime for this login.loginContext - The context key this login is occurring in.

See Also

System EventsPlugins

OnUserRemove

Event: OnUserRemove

Fires after a User is removed.

Service: 1 - Parser Service EventsGroup: modUser

Event Parameters

Name Description

user A reference to the modUser object.

See Also

System EventsPlugins

OnUserSave

Page 192: ModX Revolution Docs 20101007

Event: OnUserSave

Fires when a User is saved.

Service: 1 - Parser Service EventsGroup: modUser

Event Parameters

Name Description

user A reference to the modUser object.

mode Either 'new' (modSystemEvent::MODE_NEW) or 'upd' (modSystemEvent::MODE_UPD) depending on whether is a new object or anexisting one.

See Also

System EventsPlugins

OnWebAuthentication

Event: OnWebAuthentication

Fires right before the user is authenticated or its session is added for any non-manager context. This event can be used to provide externalauthentication support.

If its output is true, or an array where at least one index is set to true, then MODx will assume that the user has successfully logged in and bypassthe default authentication via password.

Service: 3 - Web Access EventsGroup: None

Event Parameters

Name Description

user A reference to the modUser object.

password The provided password.

rememberme Whether or not to remember the user via cookie.

lifetime The lifetime of the session cookie.

See Also

System EventsPlugins

OnWebPageComplete

Event: OnWebPageComplete

Fires after the Resource is loaded, response is sent, cache is stored (if applicable) and execution is completed.

Service: 2 - Template Service EventsGroup: None

Event Parameters

None.

Page 193: ModX Revolution Docs 20101007

See Also

System EventsPlugins

OnWebPageInit

Event: OnWebPageInit

Fires during the initialization process of a Resource, after modRequest::beforeRender is called, but before config placeholders are set and any404 or unauthorized page checking are done, or a response is sent.

Service: 5 - Template Service EventsGroup: None

Event Parameters

None.

See Also

System EventsPlugins

xPDO

What is xPDO?

OpenExpedio is the name for PDO. It's a light-weight ORB (object-relational bridge) (also see ). It implements the veryopen eXtensions to ORMsimple, but effective, Active Record pattern for data access. The library works on PHP 4 (xPDO 1.0 only) and 5, and takes advantage of the newlyadopted standard for database persistence in PHP 5.1+.

Documentation for xPDO

Documentation on xPDO can be found here:

xPDO 2.0 Documentation

See Also

 More information about xPDO can be found at the .xPDO website

Advanced Development

This section is for advanced techniques and tools in MODx development.

Namespaces

What are Namespaces?

Namespaces are organizational elements for Components. They relate lexicon strings and packages to one another, as well as provide a basicway for Revolution to know what objects belong to what package.

Usage

Page 194: ModX Revolution Docs 20101007

Revolution uses namespace paths to determine where to load 3rd Party Component files for custom manager pages, as well as managing customlanguage strings for those 3rd Party Components.

How to get a Namespace

You can access a Namespace, and its specified path, via:

$namespace = $modx->getObject('modNamespace','mynamespace');echo $namespace->get('name').' has a path of: '.$namespace->get('path');

See Also

Package ManagementInternationalizationSettings

Caching

How is Caching Done in Revolution?Configuration CacheContext Configuration, Event Map, and Plugin CachingResource (Partial-Page) CachingElement CachingxPDO Object and Database Result Set Caching

Programmatic CachingUsing modCacheManagerUsing modCacheManager::clearCache

See Also

There are many different caching features in Revolution. Different aspects of the caching can be extended with user-defined classes, so it ispossible to implement different kinds of features in custom component cache mechanisms (i.e. where you cache your own custom data), just notthroughout the entire core.

How is Caching Done in Revolution?

First, lets take a look at all of the things in the core/cache/ directory of Revolution (or core/cache/MODX_CONFIG_KEY/ if you have that set tosomething other than 'config')

Configuration Cache

In the root you will find the config.cache.php which contains the system settings which are loaded on any request.

Context Configuration, Event Map, and Plugin Caching

In a subdirectory for each context (i.e. web/ or mgr/ or connector/) you will find a context.cache.php file containing the context settings, a pluginevent map for the context, and the plugin elements that are registered in the event map.

Resource (Partial-Page) Caching

Within the web context (or another custom front-end context) there will be a subdirectory for resources/ containing files like 1.cache.php where the1 represents the id of the resource. These files contain the resource object as well as any cached element output used by the resource.

Element Caching

Within each context you will also find an elements/ subdirectory containing cache files for various kinds of elements (especially snippets andplugins). These contain various kinds of cache files which the element classes make use of when they are being processed. For instance,snippets and plugins both cache a generated global function which is included and made available at runtime.

xPDO Object and Database Result Set Caching

If you enable this, xPDO can cache query result sets representing any objects and collections in the objects subdirectory. This can be enabled inenvironments where database access is more expensive than PHP include time. This is separate from all of the other caching mechanisms whichare very specific to the operation of MODx.

Programmatic Caching

Page 195: ModX Revolution Docs 20101007

xPDOCacheManager and the modCacheManager class derived from it provide some useful features for caching any kind of data to just aboutany cache system and includes a memcached implementation. There is no tagging feature here as in the programmatic features of theZend_Cache library but there are definitely some ways to clear specific parts of any custom caching, as well as various parts of theMODx-specific caching mechanisms described above.

Using modCacheManager

// write some data to a cache file$colors = array('red','blue','green');$modx->cacheManager->set('colors',$colors); /* writes to core/cache/colors.cache.php */

// get that data$colors = $modx->cacheManager->get('colors');foreach ($colors as $color) { echo $color.'-';} /* echoes 'red-blue-green' */ this?>

You can also set time expirations on cached files:

$str = 'My test cached data.';$modx->cacheManager->set('testdata',$str,7200);// caches the data 2 hours.this for

Using modCacheManager::clearCache

Now, here are some examples of using modCacheManager->clearCache():

<?php// clear all the usual stuff by (all files with the extension .cache.phpdefault// in the cachePath + all object caches)$modx->cacheManager->clearCache();

// clear only cache files with extension .php or .log in the web/ custom/// or logs/ paths; no objects are cleared$paths = array('web/', 'custom/', 'logs/');$options = array('objects' => , 'extensions' => array('.php', '.log'));null$modx->cacheManager->clearCache($paths, $options);

// clear all cache files with extension .php in the cachePath// + all objects + execute the timed publishing checks$paths = array('');$options = array('objects' => '*', 'publishing' => , 'extensions' => array('.php'));true$modx->cacheManager->clearCache($paths, $options);

See Also

Caching in xPDOxPDOCacheManager

Custom Manager Pages

What is a CMP?Namespaces

Creating a NamespaceUsing modAction and modMenu

Creating the modActionCreating the modMenu

Returning the PageSmartyPlain-Old HTMLScripts and CSS

Page 196: ModX Revolution Docs 20101007

Brief Overview of MODExtCustom ConnectorsConclusionSee Also

What is a CMP?

CMP stands for Custom Manager Page, and it is simply a custom page that a developer or user can create that can be accessed from within theMODx Revolution manager. It can be used to create custom administration interfaces for 3rd Party Components (Extras/3PCs), or it can simplyadd functionality to the Revolution core.

In MODx Evolution, CMP's were handled by , but Revolution does not use Modules.Modules

Namespaces

Because CMPs are generated by code on the filesystem, you have to define a path to tell MODx where to look for the custom PHP controllers toload the Custom Manager Page. These paths are called 'Namespaces', and in case you're not familiar with MVC nomenclature, the generic termfor a script or function which generates a page is a 'controller'. The Manager will search for the controller file in the path defined by theNamespace. How the CMP handles redirection from there on is up to the developer.

Creating a Namespace

You can create a Namespace through System -> Namespaces. From there, you can give it a name and path. Because the Namespace name isoften used as part of a URL, MODx recommends to make the Namespace name lowercase; this helps avoid inconsistent behavior that may occurwith some webservers that may handle capitalization differently.

The following window is an example of what information makes up a Namespace:

In the path, you can also use placeholders for MODx paths:

{core_path} - Resolves to the . This is set in the at the root of the site, often it is MODX_CORE_PATH /config.core.php/home/username/modx_location/core/{base_path} - Resolves to the , often MODX_BASE_PATH /home/username/modx_location/

Using modAction and modMenu

Actions (modAction) and Menus (modMenu) work together to allow CMP developers to create Manager pages that directly hook into the defaultManager, without hacking the MODx core. modMenu objects are the actual menu items you see on the navigation bar in the Manager. modActionobjects tell the menu items to do, usually in the form of sending a request to a controller file.what

Creating the modAction

To create a modAction, go to System -> Actions. Right-click your Namespace from the 'Actions' tree and select "Create Action Here. The followingwindow will show something similar to the following:

Page 197: ModX Revolution Docs 20101007

1.

2. 3. 4.

5.

6.

There are several noteworthy fields here:

Controller: This is where you'll put the name of the controller file to look for. . For example, if inMake sure to leave off the .php extensionyour Namespace path, there is a index.php that you'll want to use to handle your CMPs, set this field to 'index'.Namespace: This is the name of the Namespace the new action belongs to. Make sure this is set to the Namespace for your Component.Parent Controller: This is currently only for organizational purposes, and poses no programmatic change if set to something else. Load Headers: If this is checked, MODx will load the Manager header and footer files. This is recommended unless you want to have acompletely separate view for your CMP.Language Topics: A comma-separated list of Lexicon Topics to load prior to the page load. They are in the standard loadingLexiconformat.Assets: A placeholder field for whatever you want to put in. It is not currently used in MODx Revolution 2.0.0.

MODx will automatically load for the Action any Lexicon Topics you specify in the "Language Topics" field you put here.

Creating the modMenu

From there, you can create your menu item by right clicking on an already-existing menu item (MODx recommends placing custom CMP's under'Components'), and clicking 'Place Action Here'. This will load a window where you can enter details for the new modMenu:

Page 198: ModX Revolution Docs 20101007

1.

2. 3. 4. 5.

6.

7.

There are also several noteworthy fields here:

Text: The Lexicon Entry key* that will be the menu item's displayed value. MODx will automatically load your Namespace's "default"Lexicon Topic, should it exist; so place your Lexicon Entry in that Topic.Description: The Lexicon entry key* that will be used for the menu item's description.Action: The action that connects your menu to the appropriate connector. Select the modAction you just created.Icon: This field is currently not in use in MODx Revolution 2.0.0.Parameters: Allows you to specify other GET parameters to be added to the Menu's href URL should you want to, e.g. . Steer&x=1&y=2clear of the variable and other . Note that each variable must be prepended with an ampersand (&); this isa Reserved Parametersbecause the contents of this field will simply be appended to a manager url, e.g. http://yourdomain.com/manager/index.php?a=65&x=1&y=2Handler: Allows you add a Javascript handler to execute instead of the default page loading action. If this is specified, the Menu willdefault to that handler and ignore the HREF attribute entirely. Use this if you just want to execute a JavaScript action instead of load apage.Permissions: If you'd like to restrict view access to this menu item, you can do so here. Just specify the name you'd wantPermissionusers to have to have to see this menu item.

The Lexicon Entry you specify for the Text or Description be in the "default" Topic for your Namespace.must

Returning the Page

Creating a CMP is very similar to a ; you'll just return the page content using the PHP 'return' statement. MODx recommends you do notSnippetuse 'echo', since this will load the page content before the headers have a chance to load.

Smarty

One way to create page content is by the use of templates. The MODx Manager is powered by Smarty, a templating engine whichSmartyfocuses on making it easy for developers to create their own custom templates. To use a template in the Manager, you simply use the following tooutput the content of your list.tpl onto the page:

return $modx->smarty->fetch( '/path/to/templates/list.tpl' );

One common use of Smarty is to assign MODx configuration settings and lexicons to a "placeholder" which can then be used in your templates.For example, in your controller file you might place the following code:

$modx->smarty->assign( '_lang', $ ->modx->lexicon->fetch() );this

Page 199: ModX Revolution Docs 20101007

1. 2.

1. 2.

$modx->smarty->assign() takes two parameters:

$tplVar [string] - The name of the placeholder.$value [string|array] - An string or associative array of data (key => value) to load into the placeholder.

Here's an example of using placeholders:

<h2 class= >"modx-page-header" {$_lang.mycomponent}</h2>

This would output a standard MODx Manager page header with the content of the lexicon matching the "mycomponent" key.

Plain-Old HTML

Of course, you don't need to use Smarty if you don't want to. One could simply return the HTML code in their controller, instead of calling$modx->smarty->fetch():

$o = '<div class= ><h2>My Component</h2></div>';"test"

$o;return

Scripts and CSS

Since ExtJS plays an important part in the MODx Manager, you will probably need to include your own JavaScript files for your components.

The best way to include a JavaScript file on your page is to use $modx->regClientStartupScript(). This function takes two parameters:

$src [string] - The path to your JavaScript file, or the content of the script to output.$plaintext [boolean] - Whether the $src content is a path to a file, or the actual script content. Defaults to false (file path).

You can also output custom CSS files in the same way. Simply use $modx->regClientCSS(), which accepts a single parameter: the path to yourCSS file.

However, you don't to use ExtJS in your Custom Manager Pages - you can use plain HTML, or another JS framework, if you like. If you dohavedecide to use another JS framework, MODx recommends that you not set "Load Headers" to true on the modAction, since this will load the ExtJSscripts. You'll need to create your own header file and output that with your normal output.

Brief Overview of MODExt

More info on , the ExtJS integration for MODx Revolution, can be found .MODExt here

Custom Connectors

A Connector is essentially a PHP file whose main purpose is to provide a connection between an AJAX-based request, and a Processor file.Since Processors are usually involved in CRUD (create, read, update, and delete) operations on a database, they should never be accesseddirectly. Instead, by using a Connector as a proxy to connect to a Processor, additional authentication and security checks can be performedbefore allowing access to the Processor.

Unlike Controllers, which are used in the Manager to display an actual page (and belong in your component's /core/ directory), Connectors mustbe HTTP-accessible. Therefore, it's best to place them in your component's /assets/ directory. Now, let's take a look at the structure of aConnector file.

The first thing your Connector must do is include the MODx configuration file, as well as the main MODx Connector file.

<?php$basePath = dirname( dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) );

require_once $basePath . '/config.core.php';require_once MODX_CORE_PATH . 'config/' . MODX_CONFIG_KEY . '.inc.php';require_once MODX_CONNECTORS_PATH . 'index.php';

Next, we simply have to 'handle' the, or pass the request data on to the appropriate Processor file.

Page 200: ModX Revolution Docs 20101007

$modx->request->handleRequest( array( 'processors_path' => $modx->getOption( 'core_path' ) . 'components/mycomponent/processors/', 'location' => '') );?>

As you can see, handleRequest() accepts an array of options:

processors_path: The base directory where your component's processor files are found.location: The subdirectory of processors_path to find the processor.action: This tells MODx the filename of the Processor file to load. This value will be taken from the HTTP $_REQUEST['action']parameter.

That's all there is to it! Your AJAX requests simply need to call your Connector file (with an 'action' parameter referring to the appropriateProcessor file), and voila -- you can now use AJAX requests in your component!

Conclusion

CMPs allow developers to create custom manager interfaces for their MODx Components without hacking the core. They integrate seamlesslyinto the core MODx installation, and allow for entire custom applications to be built with MODx technologies.

See Also

Actions and Menus

MODx Revolution introduces an entirely new program structure for its core. The manager is also built on what are called and controllers templates, which use AJAX processing to send data to that access .connectors processors

The controllers are simply PHP files that load the correct Smarty template to display, and fetch any pre-render data for the template. Revolutionabstracts these controllers into the DB as modAction's, allowing 3rd party developers to easily create custom manager pages that 'hook' into thecurrent MODx system .without modifying the core

modAction's require a controller and a template to exist, that must be found in the manager/controllers and manager/templates directories. Theyhave a few certain parameters that are worth noting:

Controller - This points to the controller file. If the file is an index.php, you can leave that off and MODx will try and find it through a smartsearch.Load Headers - if checked, this will load the MODx header and footer for the internal page. If you are wanting just a blank page for themanager page, leave this unchecked.Language Topics - Language Topics are simply separations of language areas that allow for quicker i18n access. They can be found inthe core/lexicon/en (or fr,de,etc) directory, and new topics can easily be created simply by using the Lexicon Management section.

For example, 3rd party devs might want to create a Lexicon Topic named 'buttons' for TinyMCE, which would reference the topic incore/components/tinymce/lexicon/en/buttons.inc.php. They can simply either A) use a build script to install the lexicon via a transport package, orB) have users import the lexicon topics using the Import Lexicon utility in Lexicon Management.

You can then load the topic via:

$modx->lexicon->load('tinymce:buttons');

modAction's are also easily hooked to modMenu's, which are abstract representations of the top menubar in the manager. Again, this lets 3rdparty developers easily and quickly develop custom menu implementations for their components - or lets users rearrange the top menu.

These can all be managed via the Actions panel, which is found under the Tools menu. 

Any changes to the order of 'core' menu items will be reverted during Revolution upgrades.

Related Pages

Custom Manager Pages

Page 201: ModX Revolution Docs 20101007

1. a. b. c.

2.

Internationalization

Custom Manager Pages Tutorial

GoalExplanation and Mental Preparation

What we'll need:Create the NamespaceMake the Controller FileCreate the ActionCreate the Menu ObjectMake your CMP Translatable (Optional)

Create a Lexicon DirectoryIdentify your Lexicon keyCreate the Topic FileCreate the Entries (Provide the Translations)

Troubleshooting / Errors

Goal

We want to add a custom page to the MODx Revolution manager that will load (i.e. execute) the contents of an PHP file that has been uploadedto the webserver. Technically, such a page is called a Custom Manager Page, or CMP; please refer to the page on for aCustom Manager Pagesmore detailed description.

In MODx Evolution (versions 1.x and earlier), this process was handled by "Modules", but those have been deprecated in Revolution.

Explanation and Mental Preparation

"What's the big deal?" you might ask. "Why can't I just add an anchor tag somewhere that links to my PHP file and be done with it?"

<a href= >My Custom Manager Page</a>"/path/to/my/file.php"

That should work, right? Well... maybe, but it's not that simple. There are a lot of moving parts that have to get connected to make this seeminglysimple task work. Allowing for internationalization and scalability requires that this process include several layers of abstraction that are notimmediately obvious. It goes far beyond what's possible with the simple anchor tag solution above. But rest assured, the extra steps will ensurethat the solution will be usable in a far greater number of scenarios.

What we'll need:

A PHP file on the webserver which generates the text for our CMP (a.k.a. the controller).A Namespace (i.e. a path) which defines a dedicated folder for our script(s).A clickable Menu object (modMenu) which associates the clickable link to the action.An Action object (modAction) which is an abstract representation of your file.And optionally, a Lexicon entry which would allow you to translate the label on your menu item.

Maybe you're baffled by the complexity here, and to be fair, for simple scenarios, this is a bit more complicated than is strictly required, but manyof you will find yourself at some point getting into more complicated use-cases at which point you'll realize " !!! THAT'S why they did it thisAHAway!" For now, just trust that the smart folks behind MODx put a lot of thought into how this was built, and there's a good reason that it is the wayit is. Onward.

Create the Namespace

You can think of the Namespace as a dedicated directory for your PHP file(s) that pertain to this particular manager page. Keep in mind thatcreating the Namespace inside the MODx manager does not actually create the directory; likewise, removing a Namespace from the manager willnot actually delete files and folders.  When you "create" the namespace, you're just telling MODx about it.

In our example, we've chosen to call our namespace (and its folder) mycmp.

System->NamespacesClick Create NewName: mycmp (all lowercase, one word)Path: {core_path}components/mycmp/ (note the use of the system "core_path" placeholder, and remember to include thetrailing slash)

Using your FTP client, create a directory inside named .core/components mycmp

Watch out for typos! Make sure the Namespace path matches the directory name!

Page 202: ModX Revolution Docs 20101007

1. 2. 3. 4. 5.

1. 2.

a. b. c. d.

3.

Make the Controller File

For our first manager page, we're going to keep it simple. Create a file named which contains the following:index.php

<?php 'This is my first Custom Manager Page';return

?>

Upload the file to your MODx site into the directory (i.e. the Namespace) you've just created: core/components/mycmp/index.php

As a superficial check, you may want to try navigating to the file in a browser window: http://yourdomain.com/core/components/mycmp/index.php

Notice that we did NOT use , or  , or raw HTML in our PHP. If you use any of these, you'll find that the text floats to theprint echotop of the page; remember that a Custom Manager Page is really acting as a function, so it should  a value.return

Create the Action

The Action object identifies the location of your index.php file within the namespace.

System->ActionsRight-click from the list of namespaces and select "Create Action Here".mycmpController: index (this should match the name of your PHP file WITHOUT the .php extension)Check Load HeadersOptionally, enter in one or more Language topics (e.g. "mycmp:default" to load the default topic for the mycmp Namespace)

Create the Menu Object

System->Actions (in the same window where you created the Action)Right-Click "Components" and choose "Place Action Here"

Lexicon Key: My CMPDescription: My first custom manager pageAction: mynamespace - indexSave

Refresh your browser page.

After you edit the menu item, be sure to refresh the manager page. The menu item will not be visible until you refresh yourbrowser; likewise, any changes you make to an existing menu item will not be visible until you refresh the page.

If you add any GET Parameters to the menu item under System -> Actions, steer clear of any use of the variable or any other aReserved Parameters

You should now be able to click on the "Components" menu and see your menu item, and when you click it, you should see your message!

Make your CMP Translatable (Optional)

If you never intend on internationalizing your site, then you probably have no need to create a Lexicon entry. But if you do want to provide

Page 203: ModX Revolution Docs 20101007

1. 2. 3. 4. 5.

1. 2. 3. 4.

translations, the Lexicon is MODx's way of doing it. The Lexicon key is a unique identifier, e.g. 'My CMP' which can get translated into otherlanguages.

Create a Lexicon Directory

Go to your Namespace path (usually in your Extra's core/components/mycmp/ directory) and place a "lexicon/" directory in there. From there, addan 'en' directory as well ('en' for 'English' -- or use your language code of choice). You should have something like:

core/components/mycmp/lexicon/en/

Identify your Lexicon key

System->ActionsFind your Menu action in the menu on the right (under Components)Update MenuNote the 'Lexicon Key' field. Set it to 'mycmp'.Set the 'Description' field to 'mycmp.menu_desc'.

We need both a Language Topic and a Lexicon Key in order to define a Lexicon entry. By doing the above, you've now pointed your Action/Menuto use a particular Topic and Key, but you haven't yet defined them in the Lexicon. It's entirely possible to set up the Lexicon entries and thenfirstpoint your Action and Menu objects to reference them , but here we're assuming that you are adding Lexicon entries creating thesecond afterAction and Menu objects.

Create the Topic File

Create a file name in your new 'en' lexicon directory (i.e. ), and place yourdefault.inc.php core/components/mycmp/lexicon/en/default.inc.phpentries in them, in this format:

$_lang['lexicon_entry_key'] = 'Translation Entry';for

Create the Entries (Provide the Translations)

Go ahead and add these entries to :core/components/mycmp/lexicon/en/default.inc.php

$_lang['mycmp'] = 'My CMP';$_lang['mycmp.menu_desc'] = 'My custom manager page.';

Now, clear the site cache to reload the lexicon cache, via Site -> Clear Cache.

Troubleshooting / Errors

Having problems? Here are a couple things that you may have run into.

Did you make sure you created a directory on your webserver with the EXACT path as defined by your Namespace?Are you sure your controller file is using the statement instead of using or ?return print echoYour menu items aren't being translated? Be sure to clear your cache! Site->Clear CacheTranslations aren't appearing in your CMP? Make sure you specified the "lexicon" in the Action object (ie, "mycmp:default")

Reserved Parameters

Reserved GET Parameters Inside the MODx Manager

The following is a list (currently incomplete) of GET parameters used by the MODx manager. You should avoid using any of these parameters in :Custom Manager Pages

a – used to define an actioncontext_key – specifies one of your contexts (e.g. "web" or "mgr")class_key – specifies a class name, e.g. when creating a Weblink or static resourceid -- specifies a page_id

MODExt

Page 204: ModX Revolution Docs 20101007

What is MODExt?Commonly-Used Components

More MODExt ComponentsExtending a MODExt ClassSee Also

What is MODExt?

MODExt is an extension of the ExtJS 3.0 JavaScript Framework that provides extra, customized-to-MODx functionality. It drives MODxRevolution's manager interface, and it is also available to developers wanting to use it in their CMP development. A developer simply needs touse Ext.extend on the MODx.* class to instantly get the benefit of custom MODExt components.

Commonly-Used Components

There are a few components that are used throughout the MODx Manager, and will likely be used in CMPs

More MODExt Components

Of course, there are more MODExt components at your disposal. For a full list (and source code to examine), browse to the directory of your MODx installation.manager/assets/modext/widgets/core/

Extending a MODExt Class

Extending a MODExt component is actually quite simple. Let's extend the MODx.grid.Grid class to create our own custom grid, complete with acustom toolbar.

First, create a new JavaScript file and place the following code:

MyComponent.grid.MyGrid = function( config ) { /* parent constructor */Class MyComponent.grid.MyGrid.superclass.constructor.call( , config );this};Ext.extend( MyComponent.grid.MyGrid, MODx.grid.Grid, { /* members will go here */Class} );/* Register as an xtype */"mycomponent-grid-mygrid"Ext.reg( , MyComponent.grid.MyGrid );"mycomponent-grid-mygrid"

Here, we've created our own class (MyComponent.grid.MyGrid) which extends MODx.grid.Grid. We have also registered"mycomponent-grid-mygrid" as an Ext xtype, which can be used to display this grid in a FormPanel or other component. It has no additionalfunctionality -- yet!

Now, let's add some configuration options:

Page 205: ModX Revolution Docs 20101007

MyComponent.grid.MyGrid = function( config ) { config = config || {}; /* Grid configuration options */ Ext.applyIf( config, { id : ,"mycomponent-grid-mygrid" title : _( ),"my_grid" url : MyComponent.config.connectors_url + ,"list.php" baseParams : { action : "getlist" }, paging : ,true autosave : ,true remoteSort : ,true /* Store field list */ fields : [ { name : ,"id" type : " "int }, { name : ,"name" type : "string" }, { name : "menu" } ], /* Grid ColumnModel */ columns : [ { header : _( ),"id" dataIndex : ,"id" sortable : true }, { header : _( ),"name" dataIndex : ,"name" sortable : true } ], /* Top toolbar */ tbar : [ { xtype : ,"button" text : _( ),"create" handler : { xtype : ,"mycomponent-window-create" blankValues : true }, scope : this } ] } ); /* parent constructor */Class MyComponent.grid.MyGrid.superclass.constructor.call( , config );this};

Ext.extend( MyComponent.grid.MyGrid, MODx.grid.Grid, { /* members will go here */Class} );

/* Register as an xtype */"mycomponent-grid-mygrid"Ext.reg( , MyComponent.grid.MyGrid );"mycomponent-grid-mygrid"

Our basic configuration sets the grid up to work with a "list" connector, using the "getlist" action parameter. It also sets up paging, sorting, andenables "autosave" functionality so that whenever a record is changed, it's automatically updated in the database.

We then set up our fields (id, name, and menu), and our ColumnModel which references the fields in our store.

Lastly, we create the top toolbar, consisting of a button. The handler creates a window used for creating a record to add to our database.

See Also

ExtJS 3.0 API Documentation

Page 206: ModX Revolution Docs 20101007

MODx.combo.ComboBox

MODx.combo.ComboBox

Extends: Ext.form.ComboBox Remote and local data stores; grid renderer.Key Features:

The MODExt ComboBox class contains all of the functionality of a regular Ext ComboBox. It may be populated remotely by an array of JSONobjects from a connector (default), or locally (using a basic Javascript array or an Ext ArrayStore, with the "mode" config option set to "local").

One unique feature of the MODx ComboBox class is the built-in renderer for grids. It allows developers to use a ComboBox as a grid editor, andautomatically takes care of displaying the correct displayValue in the grid cell:

MODx.FormPanel

MODx.FormPanel

Extends: Ext.FormPanel Drag-and-drop functionality; changed ("dirty") field checking functionality; connector functionality.Key Features:

FormPanels are found throughout the MODx Manager. They can contain form fields, Grids, Trees - just about any component available.

MODx.grid.Grid

MODx.grid.Grid

Extends: Ext.grid.EditorGridPanel Connector functionality; easily integrate toolbar items and MODx.Window; built-in context menu functionality.Key Features:

MODExt Grids are used to display tabular data, complete with a ColumnModel, top toolbar (tbar) and bottom toolbar (bbar). It has built-in support

Page 207: ModX Revolution Docs 20101007

for paging as well. Grids are populated remotely from a connector request returning a JSON object. Displaying a right-click context menu for eachrow can easily be achieved by including a "menu" key for each data row in your processor:

foreach( $items as $item ) { $data[] = array( 'id' => $obj->get( 'id' ), 'name' => $obj->get( 'name' ), 'menu' => array( array( 'text' => $modx->lexicon( 'my_lexicon' ), 'handler' => ' .myHandler'this ) ) );}

The above code would create a context menu for each item with the text being the lexicon key matching "my_lexicon," and the handler being themyHandler function registered to your Grid object.

See Also

MODx.grid.LocalGridMODExt

MODx.grid.LocalGrid

MODx.grid.LocalGrid

Extends: Ext.grid.EditorGridPanel Similar to MODx.grid.Grid.Key Features:

The MODExt LocalGrid class is similar to the MODx.grid.Grid class, however rather than using a connector to populate it with data, it must beloaded through a local store.

See Also

MODx.grid.GridMODExt

MODx.Msg

MODx.Msg

Extends: Ext.Component AJAX connector features.Key Features:

The MODx.Msg class provides the functionality of the Ext.MessageBox class, with the added benefit of using an AJAX callback function (forconfirmation dialogs). Simply provide a URL and optional parameters and a connector request will be sent after the user confirms the prompt.

MODx.tree.Tree

MODx.tree.Tree

Page 208: ModX Revolution Docs 20101007

Extends: Ext.tree.TreePanel Remotely-loaded toolbars; drag-and-drop to form fields functionality; connector functionality for removing and dragging/sorting.Key Features:

Trees provide a quick and easy way to display multiple levels of objects which have a parent-child relationship, such as users or resources.

MODx.Window

MODx.Window

Extends: Ext.Window Drag-and-drop functionality; connector functionality for saving.Key Features:

MODExt Windows are a convenient way to display record data from a Grid or AJAX request for editing. Windows automatically include aFormPanel which you can add form fields (and other components) to. Submitting/saving a Window actually submits the FormPanel, and initiatesan AJAX request to your connector.

Internationalization

An Overview

Page 209: ModX Revolution Docs 20101007

Lexicon EntriesLoading and Using Lexicons

Lexicons Via TagLexicons in Code

modLexicon::load()modX::lexicon()

Lexicons with PlaceholdersLexicons for SettingsConclusionSee Also

An Overview

Internationalization, or i18n, is the process of extrapolating text strings on a document to separate languages, so that the document may beviewed by a multitude of different languages without having to duplicate the page for every different language.

MODx Revolution supports i18n at the core level, through what it calls "Lexicons". A lexicon is simply a collection of the following:

Languages (IANA format)TopicsEntries

A Lexicon Topic is a collection of Lexicon Entries. A Lexicon Entry is one single language string, with a key and a value. Revolution separatesEntries into Topics to make for quicker language file loading, lower JS language cache load times, and ease of maintenance.

Furthermore, the modNamespace class is used to further separate Lexicon Topics into separate namespaces, preventing you from accidentallyoverwriting a core lexicon.

Lexicon Entries

A Lexicon Entry (or modLexiconEntry in the MODx model) is simply a single translation of a string into another language. It has a few importantfields we'll note:

name - This is the name, or "key" of the Entry. When using Lexicons, this is how you will reference this key.value - The translation of the key.topic - The topic that this entry belongs to.language - The IANA key of the language this Entry is translated into.

Loading and Using Lexicons

Lexicons must first be loaded if they are to be used in the front-end; however, this is a trivial process.

Lexicons Via Tag

To use a Lexicon Entry in a tag, simply do:

[[%key? &topic=`topicname` &namespace=`namespace_name` &language=`en`]]

The 'language', 'topic', and 'namespace' properties are optional; if the tag has been run earlier on the page with the same 'topic' property value,that topic will have already been loaded. If 'topic' is not specified, it will assume 'default'. If 'namespace' is not specified, it will assume 'core', or theMODx Revolution Core Namespace.

It is preferable not to use the 'language' property for every tag should you be changing languages; this is best done through aSystem or Context Setting for the entire site or context. The best option is different contexts for each language. But again,MODx leaves you with the preference.

Lexicons in Code

Using lexicons in code is fairly simple; first off you'll want to make sure the modLexicon class is loaded by instantiating it as a service:

$modx->getService('lexicon','modLexicon');

Then we'll want to load the Topic using the load() method.

modLexicon::load()

Page 210: ModX Revolution Docs 20101007

The syntax for the modLexicon::load method is pretty simple:

$modx->lexicon->load('topicname');

The load() function supports Namespace-specific loading. So, say you had a Lexicon Topic named 'default' in a Namespace called 'school'. You'dsimply load it like so:

$modx->lexicon->load('school: ');default

This would load the 'default' Topic in the 'school' Namespace. If the Namespace is not specified, it defaults to 'core', which is the defaultNamespace for the MODx Revolution backend.

The load() function also takes an infinite number of parameters; each parameter loads a separate Topic. Example:

$modx->lexicon->load('chunk','user','school:playground');

This would load 3 Topics: 'chunk', 'user', and the 'playground' Topic from the 'school' Namespace.

Furthermore, the load parameter supports language-specific loading, should you want to override the default language that is being loaded (whichdefaults to the current value of $this->modx->cultureKey, which is set differently depending on the Context loaded, and can be set via Settings),you could load it like so:

$modx->lexicon->load('es:school:playground');

This would load the Spanish version of the 'playground' Topic for the 'school' Namespace. Fun, huh?

modX::lexicon()

Now we can use the lexicon() method on the MODx object to get our Entry with key 'school.basketball':

$modx->lexicon('school.basketball');

Lexicons with Placeholders

Say we wanted to load a Lexicon Entry with some dynamic values we have in our page. For example, say we want a greeting on a website, thatsays, "Hello, John!" if John is the username of the currently logged in user. Our Lexicon Entry "welcome_message" value would look like this:

Hello, [[+name]]!

And then in tag form:

[[!%welcome_message? &name=`John`]]

Or in PHP:

$modx->lexicon('welcome_message',array('name' => 'John'));

You can have an infinite number of placeholders for each Tag.

Note our ! prefix for the Tag; this makes sure the Tag isn't cached, since our string might be changing before the page cachedoes.

Lexicons for Settings

So say you're creating System Settings for your 3rd Party Component (3PC). The syntax for auto-loading them into the Revolution Settings grid issimple. Let's say we have a Namespace for our Component called 'gallery', and a setting called 'gallery.display_thumbs'

Page 211: ModX Revolution Docs 20101007

Recommended FormatThe recommended format for 3PC developers is to use a prefix which identifies the parent component:

$_lang[' .key-name'] = 'Your translation here.';name-of-component

This helps to prevent name collisions; keep in mind that the array may have thousands of entries, so you want to make$_langsure each entry is unique.

To add a lexicon name and description, we'd simply add the following 2 strings into our 'default' Lexicon Topic for our 'gallery' Namespace:

$_lang['setting_gallery.display_thumbs'] = 'Display Thumbnails';$_lang['setting_gallery.display_thumbs_desc'] = 'When set to , will display thumbnails true this forthe gallery.';

And we're done!

Conclusion

Lexicons provide MODx Revolution users with a plethora of avenues and options to do their i18n work. Lexicons are composed of multiple Entriesfor each Language, and are grouped into Topics. They can be called by PHP method calls, or by MODx Tags.

See Also

modX.lexicon

Creating Lexicons for Your Components

MODx Services

What is a Service?

A service is any object that is loaded via . It can be a custom class provided by the user, or by MODx itself.$modx->getService

Once an object is loaded with getService, it is accessible via $modx->(servicename). So, for example:

$modx->getService('twitter','myTwitter','/path/to/twitter/model/',array( 'api_key' => 3212423,)); $modx->twitter->tweet('Success!');

What are the Default Included Services?

A list of the core-included MODx Services is as follows:

See Also

modX.getService

modMail

What is modMail?

Page 212: ModX Revolution Docs 20101007

modMail is an abstract class that can be extended to provide mail services for Revolution. It cannot be run by itself, but must be extended with animplementation class (such as PHPMailer).

What is modPHPMailer?

modPHPMailer is a class that extends modMail to provide an implementation for the open source PHPMailer class.

Usage

Let's say we have an email template in the Chunk 'myEmailTemplate'. We want to send it via mail to [email protected], with the Fromaddress being '[email protected]'. We also want it to be an HTML email. Here's how we'd do it:

$message = $modx->getChunk('myEmailTemplate');

$modx->getService('mail', 'mail.modPHPMailer');$modx->mail->set(modMail::MAIL_BODY,$message);$modx->mail->set(modMail::MAIL_FROM,'[email protected]');$modx->mail->set(modMail::MAIL_FROM_NAME,'Johnny Tester');$modx->mail->set(modMail::MAIL_SENDER,'Johnny Tester');$modx->mail->set(modMail::MAIL_SUBJECT,'Check out my email template!');new$modx->mail->address('to','[email protected]');$modx->mail->address('reply-to','[email protected]');$modx->mail->setHTML( );true

(!$modx->mail->send()) {if $modx->log(modX::LOG_LEVEL_ERROR,'An error occurred trying to send the email: '.$err);while}$modx->mail->reset();

Simple, no?

Note that we have to reset() if we want to send mail again; this resets all the fields to blank. Also, the fields above are (just likeoptionalPHPMailer), so that if you didn't want to specify a 'reply-to' (though we recommend it!) you can.

Also, if you want to send the email to multiple addresses, you can simply call address('to') again, like so:

$modx->mail->address('to','[email protected]');$modx->mail->address('to','[email protected]');

And finally, the example code above will send a message to our error.log if the mail isn't sent for some reason (usually a server misconfiguration).

What if I want to use another email class?

Simple - just extend modMail with that class, then load your class via . You'll get all the modMail functionality, but you will have togetServiceprovide the wrapper class (like modPHPMailer) to do so.

See Also

MODx ServicesmodX.getService

Package Management

MODx Revolution introduces what are called , which are compiled zips of almost anything - from snippets, components,Transport Packagesmanager templates, to the core itself.

Revolution also has , which are download locations that allow for downloading packages straight from within the MODx manager itself.Providers

Downloading PackagesInstalling PackagesUpdating PackagesUninstalling PackagesSee Also

Downloading Packages

Page 213: ModX Revolution Docs 20101007

You have a few options: you can download remotely via the Provider option, by selecting the modxcms.com provider from the menu (or just byclicking 'Download Extras' in the grid toolbar).

To download the packages, simply select the package you wish to download and click the "Download" button.

Or, packages can be downloaded directly from a browser via MODx's Extras section, located at . The package zipshttp://modxcms.com/extras/are loaded simply by uploading them to your core/packages/ directory, and then running the Package Management section of the manager. Fromthere, click on "Add New Package", and select the "Search Locally for Packages" option. MODx will then scan the core package directory, andadd any packages you have.

Downloading Packages requires you to either have cURL or sockets installed on your web server. If you do not have theseinstalled, the list of packages will show blank.

The Official Provider of modxcms.com has a URL of:http://rest.modxcms.com/extras/and comes packaged in with MODx Revolution 2.0.0.

Installing Packages

You can easily install packages by right-clicking on the package and clicking "Install". A console will load showing you the details of the packageinstallation.

If the package should have a License Agreement, you'll need to agree to it before you can proceed. Also, the package might provide a READMEfile for you to purvey before installing.

Finally, the package may or may not have some pre-install options and settings for you to set, such as:

The package should then install on your MODx installation.

Updating Packages

You can easily update any package that has been downloaded from a provider. Simply click the 'Check for Updates' context menu item (afterright-clicking on the package), and MODx will load a window showing any newer versions. Should your package be already up-to-date, amessage will appear.

You can then select the version you would like to install, and MODx will download the package and start the install process.

Now, if you want to revert back, you'll simply uninstall the package, and click the 'Revert' option, which will revert back to the prior package thatwas installed.

Uninstalling Packages

You can click on any package to either remove or uninstall a package. a package removes the zip file entirely from your core/packagesRemoving

Page 214: ModX Revolution Docs 20101007

directory. Uninstall simply uninstalls it.

Note the three modes when you uninstall a package:

Each is self-explanatory.

See Also

Transport Packages

What is a Transport Package?The Internals of a Transport PackageThe manifest.php fileOkay, what are these Vehicles?

Inside a Vehicle's SourceResolvers and Validators

A ValidatorA Resolver

UsageRelated Pages

What is a Transport Package?

A Transport Package is a collection of objects and files that can be used to "transport" data from one MODx installation to another; or even totransport 3rd-Party Components in a simple, easily-manageable format. In other words, Transport Packages can transport nearly - fromanythingdatabase data, files and even scripts to run during its install.

Transport Packages also allow for versioning, in that they match based on a simple format, complying with PHP version number standards:

packagename-version-release.transport.zip

So, an example Transport Package might be "myextra-1.0-rc1.transport.zip". If you were to upload a "myextra-1.0-rc2.transport.zip", MODx wouldthen interpret this as part of the same "package" but a newer version of it. It would then behave in "upgrade" mode.

Transport packages are stored in .zip files, ending with ".transport.zip". They can be uploaded and installed anywhere there is a MODx Revolutioninstance - regardless of the server configuration.

The Internals of a Transport Package

MODx Revolution automatically "unpacks", or unzips, your transport packages for you. Once done, a subdirectory in your core/packages directorywill appear with the name of the zip file (minus ".transport.zip"). This directory will contain:

A manifest.php fileSubdirectories of each Vehicle (more on those later)

It may also contain a "preserved.php" file, if the package is an upgrade from a prior package, which contains the metadata for the install to berestored. And finally, there might be a 'setup-options.php' file if the package has packaged one inside.

Page 215: ModX Revolution Docs 20101007

The manifest.php file

The manifest basically stores all the relevant information for the package, including the locations of files and information about them. If you openthe manifest.php file, you'll see that it contains a giant PHP array being returned. Within that are some keys you might be interested in:

manifest-version - This tells us what version the manifest definition is. MODx uses it to determine how to interpret the manifest andmake it easier for future MODx versions to be backwards-compatible.

manifest-attributes - These are any custom attributes that were set on the package when it was being built. The most common are'license', 'readme' and 'setup-options', which MODx interprets during install time.

manifest-vehicles - These are the Vehicles metadata, in array format.

Okay, what are these Vehicles?

Transport Vehicles are the parts of a Transport Package. A package can contain as many Vehicles as it likes. Vehicles also come in differenttypes; the currently available ones are:

xPDOObjectVehicle - For transporting database dataxPDOFileVehicle - For transporting files

In the 'manifest-vehicles' array, you'll see these keys for each vehicle:

vehicle_package - This tells us what type of package is holding these vehicles. Currently the only type is 'transport'.vehicle_class - The class name of the type of Vehicle this is.class - The class name of the DB object being transported, or xPDOFileVehicle if it's a file vehicle.guid - A randomly generated GUID for the vehicle.native_key - If the vehicle is a database object, this will be its primary key by which it is identified.filename - Where the vehicle's source file can be found within the transport package's folder.namespace - Certain packages use the 'namespace' field to group vehicles and other objects to make them uniquely identifiable within aMODx installation.

So now that we've seen what the vehicles represent in the manifest, let's open up a Vehicle by looking a filename and diving in.

Inside a Vehicle's Source

Vehicles can actually have a few different files grouped with them, but we'll first concern ourselves with the main vehicle file, which is specified inthe manifest and often ends with '.vehicle'.

Again, it looks like a big PHP array, with similar keys. It has some extra keys though, which are important. xPDOFileVehicle andxPDOObjectVehicle can have different keys. Let's go over the common ones:

class - Similar to the manifest, the class type of the vehicle.object - An array that contains the object information. For DB objects this will most likely be a JSON array representation of the DB table.For files, it will be a PHP array with the source, target and name of the vehicle.vehicle_class - Similar to the manifest, the class name of the vehicle.vehicle_package - Similar to the manifest, the transport type of the vehicle.guid - Similar to the manifest, a unique identifier for the vehicle.package - Only applicable to xPDOObjectVehicles, this will most likely be 'modx' or blank.signature - The filename signature for this vehicle.native_key - Similar to the manifest. If the vehicle is a database object, this will be its primary key by which it is identified.

The xPDOObjectVehicle, or database vehicles, often have these extra keys:

preserve_keys - If true, the vehicle will try and preserve the primary key of the database record on install.update_object - If true, the vehicle will UPDATE the object if it's found already in the database during install. If false, it will be skipped.unique_key - The column name by which the database object can be uniquely identified - often this is not the primary key, asauto-incrementing fields often do not match across different databases.related_objects - A complex array of any related objects to this vehicle's main database object. Sometimes, it may be necessary topackage in "related" objects to achieve the desired end result. A great example is if the packager wants to put all of his Snippets in aCategory. He would make the vehicle's object be the Category, and then add related objects - the snippets - to it.related_object_attributes - The attributes for the above related objects.namespace - Similar to the manifest; a grouping value for the objects in a transport package.

There are also some optional ones, which may or may not be set:

validate - An array of arrays which contain validators, explained later.resolve - An array of arrays which contain resolvers, explained later.

In xPDOFileVehicles, you will also see a directory with the same filename as the vehicle, minus the ".vehicle". If you open it, there will be the filesfor the vehicle.

Page 216: ModX Revolution Docs 20101007

1.

2.

Resolvers and Validators

What are resolvers and validators? Well, think of them like pre and post installation scripts. They are, in essence, PHP scripts. (In fact, if you openthem up, they look exactly like PHP scripts.) They are named the same filename as the vehicle, but are postfixed with ".resolver" or ".validator".

A Validator

A validator is executed the Vehicle is installed, upgraded or uninstalled. If they return false, the Vehicle is not installed, and is skipped.before

They are useful for determining whether or not the Vehicle should still be installed, uninstalled or upgraded in the package process. For example -if you want to have dependencies and not have a Vehicle installed unless something else is found, a Validator would be a great place for it.

A Resolver

Resolvers are executed the Vehicle is installed, upgraded or uninstalled. Each will execute in turn regardless of any other resolver results.after

Resolvers are useful for 'cleaning up' after a Vehicle is installed, or setting custom configuration options (such as ones setup in Setup Optionsduring install).

Usage

Transport Packages can be managed in the section of the Revolution manager. They can be added to the RevolutionPackage Managementinstance by either:

Uploading the file manually to core/packages/, and then clicking "Add New Package" and selecting the "Search Locally for Packages"optionDownloading the package from a . This allows updates to be remotely downloaded for a package as well.Transport Provider

Once downloaded, they can be installed by right-clicking a package in the grid, and clicking Install. This will prompt the user to accept a LicenseAgreement should the package come with one, and prompting to read the README should the package contain one. Then it will present a formwith pre-installation options, which may or may not exist depending on the package. The user can then click 'Install' to install the package.

Once installed, the user can uninstall the package at any time. Also, if the package was downloaded from a , then the user canTransport Providercheck for updates for the package.

Related Pages

Package ManagementProvidersTutorial: Creating a 3rd Party Component Build Script

Providers

What is a Transport Provider?UsageRelated Pages

What is a Transport Provider?

Transport Providers in MODx are remote sources that one can download Transport Packages from. Simply by specifying a service URL, you caneasily hook into the Transport Provider and grab the latest Transport Packages easily from it.

MODx supports an unlimited number of Transport Providers, and each one can be from any source.

MODx recommends not downloading Transport Packages from providers you cannot verify or do not trust. We recommend themodxcms.com Official Provider at: http://rest.modxcms.com/extras/

Usage

To setup a Transport Provider, simply go to the Package Management page, and from there click on the 'Providers' panel heading at the bottom.This will open up a grid of Providers, which you can manage easily.

Page 217: ModX Revolution Docs 20101007

From there, you can click "Add New Provider" to add another, or right-click on any provider to get more options. Providers must be valid JSONfiles, web-accessible, and in the correct Provider format. Note that the Extras section of modxcms.com is a Provider.

The Service URL is the actual, absolute location of the provider file.

Once you have a provider, you can connect to it by going up to the Packages grid, clicking "Add New Provider", and then select the "Select aProvider" option. This will bring up a dropdown of Provider options:

 Once you've selected your provider, click Next, and the download tree will be populated with the contents of that Provider's payload (ie, data).This will show you a tree of Package Versions you can download:

Related Pages

Page 218: ModX Revolution Docs 20101007

Creating a 3rd Party Component Build Script

Directory StructureStarting the Build ScriptPackaging in ObjectsValidators and ResolversLexiconsPackage Attributes: License, Readme and Setup OptionsRelated Pages

Users using Revolution 2.0.0-beta-4 or earlier should note that the defines are different in beta5 and onward. An example:xPDOTransport::UNIQUE_KEYS in beta5+ is XPDO_TRANSPORT_UNIQUE_KEYS in beta4 and earlier. MODx recommendsto just update to beta5/SVN.

A build script. What is that, you might ask? This is the meat of the packaging process; here is where your component is actually put into the nice,neat .zip transport package that you find on modxcms.com or through Revolution's Package Management section.

This tutorial will guide you through how to create one of those scripts. We'll be using a sample component called Quip, which contains amodAction, a few menus, some chunks and a snippet, lexicons, setup options, a license, a readme, and system settings. It's basically a quick,easy run through of all the basics to creating a fundamental build script.

Directory Structure

First off, let's take a quick look at our directory structure. This isn't always how you have to do it - this one is specifically built this way for SVN; butit's definitely recommended, especially with the and structures, since that makes creating theassets/components/quip/ core/components/quip/transport package much easier.

Page 219: ModX Revolution Docs 20101007

Starting the Build Script

Let's first start with some phpdoc comments at the top, and then start the timer.

<?php/** * Quip build script * * @ quippackage * @subpackage build */$mtime = microtime();$mtime = explode( , $mtime);" "$mtime = $mtime[1] + $mtime[0];$tstart = $mtime;set_time_limit(0); /* makes sure our script doesnt timeout */

Now let's define some basic paths. We can define these up top into a "sources" array to make them easier to reach later in the build script. Notehow the 'source_core' and 'source_assets' directories do post-fix a foreslash onto their paths. This is required.not

Page 220: ModX Revolution Docs 20101007

$root = dirname(dirname(__FILE__)).'/';$sources= array ( 'root' => $root, 'build' => $root .'_build/', 'resolvers' => $root . '_build/resolvers/', 'data' => $root . '_build/data/', 'source_core' => $root.'core/components/quip', 'lexicon' => $root . 'core/components/quip/lexicon/', 'source_assets' => $root.'assets/components/quip', 'docs' => $root.'core/components/quip/docs/',);unset($root); /* save memory */

Now, we'll need to include some files to get the build libraries we'll need. First, let's include a file we'll create called 'build.config.php' in our builddir.

require_once dirname(__FILE__) . '/build.config.php';

In this file, we'll want to define the location of our MODx Revolution installation so that the build script can know where to get the modX class, aswell as where to put the package when finished. Our file will look somewhat like this:

<?php/** * Define the MODX path constants necessary core installationfor * * @ quippackage * @subpackage build */define('MODX_CORE_PATH', '/absolute/path/to/modx/core/');define('MODX_CONFIG_KEY','config');

You'll want to make sure to change the value of MODX_CORE_PATH to the absolute path of where your MODx Revolution core is installed.MODX_CONFIG_KEY can stay the same, unless you're doing a multi-domain install.

Now, you'll want to include the modX class, and instantiate it. We'll also initialize it into the 'mgr' context, and set the log output to HTML to makeour errors and info messages nice and formatted - unless we're doing this from the cmd line, where we'll want just standard echo messages.

require_once MODX_CORE_PATH . 'model/modx/modx.class.php';

$modx= modX();new$modx->initialize('mgr');$modx->setLogLevel(modX::LOG_LEVEL_INFO);$modx->setLogTarget(XPDO_CLI_MODE ? 'ECHO' : 'HTML');

Okay, it's time for the meat. Let's first off use $modx->loadClass to load the modPackageBuilder class. Then we'll instantiate an instance of it, andcreate a package.

$modx->loadClass('transport.modPackageBuilder','', , );false true$builder = modPackageBuilder($modx);new$builder->createPackage('quip','0.1','alpha7');$builder->registerNamespace('quip', , ,'{core_path}components/quip/');false true

The modPackageBuilder::createPackage function has 3 parameters:, , and . For us,name version release

we'll be doing quip-0.1-alpha7, so let's go with that.

Next, we'll register a to this package. Not all packages need ; but all 3rd Party Components do. Basically, a NamespaceNamespace Namespacesis an organizing tool for MODx so that MODx can know what objects are tied to what package. This is helpful later on should we want to uninstallour package; we'd want it to remove the objects we'd install.

Plus, should we want to add any to this package (which we will), MODx does so by relating it to it's Namespace. Our packageLexicon Entriesbuilder will assign our Lexicon Entries to the Namespace, so we can easily manage our Lexicon Entries; not any others.just

Page 221: ModX Revolution Docs 20101007

Packaging in Objects

Objects are packaged as in MODx Revolution; basically think of a vehicle as a sort of storage system that transports the data and/or filesVehiclesinto the zip package. Packages can contain many vehicles; vehicles can contain many objectsor files - however, vehicles that contain an objectmust only have one reference object (or parent object, whichever you prefer) that the vehicle is based off of.

So, let's look at some examples for creating a vehicle before digging into our build script. This first example packages in a simple object, withsome parameters:

$snippet = $modx->newObject('modSnippet');$snippet->set('id',1);$snippet->set('name','Test');$vehicle = $builder->createVehicle($snippet,array( xPDOTransport::UNIQUE_KEY => 'name', xPDOTransport::UPDATE_OBJECT => ,true xPDOTransport::PRESERVE_KEYS => ,false));

So, first off, we created a snippet object. Note that you'll have to specify an arbitrary ID for it, even though we wont keep it later. This is required.Then, we used the 'createVehicle' function in modPackageBuilder to create the vehicle object. Let's look at those attributes options more closely:

xPDOTransport::UNIQUE_KEY - Here you'd place the unique key that identifies the object you're creating. This will tell(string/array)MODx to search for the modSnippet with the 'name' equal to the packaged in name (here, 'Test') when updating or removing the object.For most objects, this will be 'name'; others require different settings. Some might even require an array of two or more fields.xPDOTransport::UPDATE_OBJECT - Either true or false, this tells MODx whether or not to update the object if it is found in(boolean)the DB upon install (or update). Sometimes, if the object is already there, you may not want to update it - the update might erase theuser's current settings for that object.xPDOTransport::PRESERVE_KEYS - Either true or false, this tells MODx whether or not to rewrite the primary keys when the(boolean)object is found. This can be useful if you're wanting the PKs to stay the same when you update - some PKs are auto_increment, and ifyou're wanting those to stay the same number, you'd set this to true. Note: If the object already exists, this feature only works ifxPDOTransport::UPDATE_OBJECT is set to true as well. If the object is not found, it will work regardless.

Simple enough? So our example tells it to look for a Snippet named 'Test', and if it finds it, update its contents. If it doesnt find it, create it.However, if it does find it; we told MODx not to update its PK - there's no need to adjust that in this situation.

Now, what about related objects? What if I want to package in my modMenu, along with its Action associated with the modMenu? Here's a bitmore complex scenario:

Page 222: ModX Revolution Docs 20101007

$action= $modx->newObject('modAction');$action->fromArray(array( 'id' => 1, 'namespace' => 'quip', 'parent' => '0', 'controller' => 'index', 'haslayout' => '1', 'lang_topics' => 'quip: ,file',default 'assets' => '',),'', , );true true$menu= $modx->newObject('modMenu');$menu->fromArray(array( 'text' => 'quip', 'parent' => 'components', 'description' => 'quip_desc', 'icon' => 'images/icons/plugin.gif', 'menuindex' => '0', 'params' => '', 'handler' => '',),'', , );true true$menu->addOne($action);$vehicle= $builder->createVehicle($menu,array ( xPDOTransport::PRESERVE_KEYS => ,true xPDOTransport::UPDATE_OBJECT => ,true xPDOTransport::UNIQUE_KEY => 'text', xPDOTransport::RELATED_OBJECTS => ,true xPDOTransport::RELATED_OBJECT_ATTRIBUTES => array ( 'Action' => array ( xPDOTransport::PRESERVE_KEYS => ,false xPDOTransport::UPDATE_OBJECT => ,true xPDOTransport::UNIQUE_KEY => array ('namespace','controller'), ), ),));

Okay, a bit more meat here. We're introducing 2 new parameters:

xPDOTransport::RELATED_OBJECTS - Either true or false, this will tell MODx we want to search for related objects to this(boolean)object. This must be set for the next parameter to work.xPDOTransport::RELATED_OBJECT_ATTRIBUTES - This defines the types and details of the related objects we want to grab.(array)If you note, the format is simply an associative array of attributes - similar to the parent object's attributes - where the key is the "alias" ofthe related object we want to grab. The aliases can be found in the Schema, located in .core/model/schema/modx.mysql.schema.xml

So our example above tells us on the modAction (found by looking for the modAction with a namespace of 'quip' and a controller of 'index') toinclude the related modAction object that we package in. We packaged them in manually using xPDO's addOne function on the modAction.

Also, if we wanted to package in related objects to the modAction objects, we would just have had to define that in the 'Action' attributes andaddMany (or addOne) on that action. You can go however deep in nesting that you want.

So, back to our script. To recap, so far we have:

Page 223: ModX Revolution Docs 20101007

<?php/** * Quip build script * * @ quippackage * @subpackage build */$mtime = microtime();$mtime = explode( , $mtime);" "$mtime = $mtime[1] + $mtime[0];$tstart = $mtime;set_time_limit(0);

$root = dirname(dirname(__FILE__)).'/';$sources= array ( 'root' => $root, 'build' => $root .'_build/', 'lexicon' => $root . '_build/lexicon/', 'resolvers' => $root . '_build/resolvers/', 'data' => $root . '_build/data/', 'source_core' => $root.'core/components/quip', 'source_assets' => $root.'assets/components/quip', 'docs' => $root.'core/components/quip/docs/',);unset($root);

/* override with your own defines here (see build.config.sample.php) */require_once dirname(__FILE__) . '/build.config.php';require_once MODX_CORE_PATH . 'model/modx/modx.class.php';

$modx= modX();new$modx->initialize('mgr');$modx->setLogLevel(modX::LOG_LEVEL_INFO);$modx->setLogTarget(XPDO_CLI_MODE ? 'ECHO' : 'HTML');

$modx->loadClass('transport.modPackageBuilder','', , );false true$builder = modPackageBuilder($modx);new$builder->createPackage('quip','0.1','alpha5');$builder->registerNamespace('quip', , ,'{core_path}components/quip/');false true

So, let's first package in our modActions and modMenus for our backend:

/* load action/menu */$menu = include $sources['data'].'transport.menu.php';

$vehicle= $builder->createVehicle($menu,array ( xPDOTransport::PRESERVE_KEYS => ,true xPDOTransport::UPDATE_OBJECT => ,true xPDOTransport::UNIQUE_KEY => 'text', xPDOTransport::RELATED_OBJECTS => ,true xPDOTransport::RELATED_OBJECT_ATTRIBUTES => array ( 'Action' => array ( xPDOTransport::PRESERVE_KEYS => ,false xPDOTransport::UPDATE_OBJECT => ,true xPDOTransport::UNIQUE_KEY => array ('namespace','controller'), ), ),));$builder->putVehicle($vehicle);unset($vehicle,$action); /* to keep memory low */

Wait! Notice how I put the action data in a different file? You don't have to do this - it's completely personal preference - but it does keep our buildscript clean, and isolate our actions/menus to a separate file for easy management.

Let's do the same with our system settings:

Page 224: ModX Revolution Docs 20101007

/* load system settings */$settings = include $sources['data'].'transport.settings.php';

$attributes= array( xPDOTransport::UNIQUE_KEY => 'key', xPDOTransport::PRESERVE_KEYS => ,true xPDOTransport::UPDATE_OBJECT => ,false);foreach ($settings as $setting) { $vehicle = $builder->createVehicle($setting,$attributes); $builder->putVehicle($vehicle);}unset($settings,$setting,$attributes);

Great! We've got our actions, menus and settings packaged in. Now, using our newfound knowledge about related objects, let's create a categorycalled 'Quip' and put our Snippet and Chunks in that category. We'll go through this a bit slower, so we can easily see how this works:

/* create category */$category= $modx->newObject('modCategory');$category->set('id',1);$category->set('category','Quip');

Okay, great. Step one done: category created. Now about that Snippet:

/* create the snippet */$snippet= $modx->newObject('modSnippet');$snippet->set('id',0);$snippet->set('name', 'Quip');$snippet->set('description', 'A simple commenting component.');$snippet->set('snippet',file_get_contents($sources['source_core'].'/snippet.quip.php');

Great! Note how here we're actually using the file_get_contents() function to grab the contents of the snippet from our dev environment and placeit here. This makes it easy to run the build in future iterations; no need to continually update this call - just update that file.

Now, we had some properties on that snippet...how do we put those in?

$properties = include $sources['data'].'properties.inc.php';$snippet->setProperties($properties);$category->addMany($snippet);

You'll use modSnippet's setProperties function to pass in an array of property arrays. So, let's take a look at that properties.inc.php file:

Page 225: ModX Revolution Docs 20101007

<?php/** * Default snippet properties * * @ quippackage * @subpackage build */$properties = array( array( 'name' => 'closed', 'desc' => 'If set to , the thread will not accept comments.',true new 'type' => 'combo- ',boolean 'options' => '', 'value' => ,false ), array( 'name' => 'dateFormat', 'desc' => 'The format of the dates displayed a comment.',for 'type' => 'textfield', 'options' => '', 'value' => '%b %d, %Y at %I:%M %p', ), /* ...removed others brevity... */for);

$properties;return

Simple enough. And now on to the chunks:

/* add chunks */$chunks = include $sources['data'].'transport.chunks.php';

(is_array($chunks)) {if $category->addMany($chunks);} { $modx->log(modX::LOG_LEVEL_FATAL,'Adding chunks failed.'); }else

Good. We returned an array of chunks, and used modCategory's addMany() function to add them in. We also added a sanity check just in casewe made a typo or something. Now, let's package all that into a vehicle:

/* create category vehicle */$attr = array( xPDOTransport::UNIQUE_KEY => 'category', xPDOTransport::PRESERVE_KEYS => ,false xPDOTransport::UPDATE_OBJECT => ,true xPDOTransport::RELATED_OBJECTS => ,true xPDOTransport::RELATED_OBJECT_ATTRIBUTES => array ( 'Snippets' => array( xPDOTransport::PRESERVE_KEYS => ,false xPDOTransport::UPDATE_OBJECT => ,true xPDOTransport::UNIQUE_KEY => 'name', ), 'Chunks' => array ( xPDOTransport::PRESERVE_KEYS => ,false xPDOTransport::UPDATE_OBJECT => ,true xPDOTransport::UNIQUE_KEY => 'name', ), ));$vehicle = $builder->createVehicle($category,$attr);

Great! We've got our category vehicle, complete with all the related chunks and snippet. They'll be installed in the right category when our usersinstall our package, too - so it'll look nice and sharp!

Validators and Resolvers

Validators and resolvers are basically scripts that run during the install process. Validators are run pre-install; meaning that they are run before themain package installation happens. If they return false, the installation does not proceed.

Page 226: ModX Revolution Docs 20101007

Resolvers, on the other hand, execute after the main package has installed. They can either be file or PHP scripts. A file resolver simply copiesover files into a specific target location. A PHP resolver executes a script after install.

With that said, we're going to attach 2 file resolvers, and one PHP resolver, to our script:

$vehicle->resolve('file',array( 'source' => $sources['source_core'], 'target' => ," MODX_CORE_PATH . 'components/';"return));$vehicle->resolve('file',array( 'source' => $sources['source_assets'], 'target' => ," MODX_ASSETS_PATH . 'components/';"return));$vehicle->resolve('php',array( 'source' => $sources['resolvers'] . 'setupoptions.resolver.php',));$builder->putVehicle($vehicle);

Okay, first things first. File resolvers take two options:

source - This is the target directory or script. If it's a file resolver, it must not end with a trailing slash and must be a valid directory. If it's aPHP script resolver, it must be a valid and accessible file.target - Only applicable to file resolvers, this tells MODx where to install the source files. It is an eval()'ed statement, so must be used asin the example. The standard MODx defines are available to you; use those to grab base paths to target.

So in our examples, we simply move all the files in our source core directory to modx/core/components/quip/ (since our directory that we'removing is named "quip"), and all the files in our source assets directory to modx/assets/components/quip/.

You might be asking why we're moving these to two directories. Well, in practice, it's best to keep non-web-accessible files - such as PHP scripts,tpl files, docs, etc - in the core (which can be placed outside the webroot) so that they are kept secure from web visitors. This keeps only the filesthat need to be accessed through the web by your Component in the web-accessible part of your site.

Next, we add a PHP resolver, called 'setupoptions.resolver.php'. We'll get back to this in much more detail, because it actually deals with thesetup options process we'll get to later.

And finally, we pack the vehicle into the package using the putVehicle function.

Lexicons

So now we've got a package with system settings, actions, menus, snippets, chunks, a category, and a few resolvers all set up. Let's talk aboutour lexicons.

We have our lexicon structured nicely in our \core/components/quip/lexicon directory:

Page 227: ModX Revolution Docs 20101007

As you can see, we have a subdirectory as 'en', the IANA code for English. Then, we have a 'default.inc.php' - this represents the 'default' lexicontopic. Should we want to create separate lexicon topics, we would name them 'topicname.inc.php'.

As of MODx Revolution RC-2, MODx will automatically find the lexicons in your lexicon directory, assuming that you put them in this structure inthe following place: '{namespace_path}lexicon/', where the Namespace path is the path you put for your Namespace earlier. You don't have tobuild in the lexicons directly at all; MODx will parse it for you.

This is because the lexicons are cached first from your files, then any overrides from the DB are merged and cached. This allows people to'override' your lexicons by using Lexicon Management in the Manager, should they choose to, without breaking their upgrade path for yourComponent.

Package Attributes: License, Readme and Setup Options

Each package has what are called 'package attributes', which can be passed to any resolver or validator. You could pass pretty much anythingyou want into the function modPackageBuilder::setPackageAttributes(), in an array format. There are, however, three special keys that we'll dealwith.

license (string) - This represents your license agreement. Should MODx find this not empty during install, it will prompt the user to agreeto it before they can proceed to install the package.readme (string) - This holds the readme. Before installing, if this is not empty, the user will be able to view the readme. This can be usefulto make sure people see any requirements before they install.setup-options (string) - And here is the best part - this can be an HTML form (minus the form tags) that will pass any user-inputtedoptions to the resolvers or validators. This means that you can take in user input before install, and process it during install!

So let's use these in our build script:

/* now pack in the license file, readme and setup options */$builder->setPackageAttributes(array( 'license' => file_get_contents($sources['docs'] . 'license.txt'), 'readme' => file_get_contents($sources['docs'] . 'readme.txt'), 'setup-options' => array( 'source' => $sources['build'] . 'setup.options.php' ),));

Obviously our license and readme values are being passed the contents of our license and readme files. We're doing them via file_get_contents()so that we can still store the actual files in the directory after install, should the user want to view them later.modx/core/components/quip/docs

But 'setup-options' looks a little different. We could just pass a file_get_contents() call that puts in a string, but then our setup options formwouldn't be dynamic! There might be cases where you wouldn't want that, but we do. We want this options form to upgrade well. Note that you

Page 228: ModX Revolution Docs 20101007

have to pass the file location as the 'source' parameter - remember Resolvers? Looks familiar, eh? Same idea.

Our setup.options.php file looks like this:

<?php/** * Build the setup options form. * * @ quippackage * @subpackage build *//* set some values */default$values = array( 'emailsTo' => '[email protected]', 'emailsFrom' => '[email protected]', 'emailsReplyTo' => '[email protected]',);

($options[xPDOTransport::PACKAGE_ACTION]) {switch xPDOTransport::ACTION_INSTALL:case xPDOTransport::ACTION_UPGRADE:case $setting = $modx->getObject('modSystemSetting',array('key' => 'quip.emailsTo')); ($setting != ) { $values['emailsTo'] = $setting->get('value'); }if null unset($setting);

$setting = $modx->getObject('modSystemSetting',array('key' => 'quip.emailsFrom')); ($setting != ) { $values['emailsFrom'] = $setting->get('value'); }if null unset($setting);

$setting = $modx->getObject('modSystemSetting',array('key' => 'quip.emailsReplyTo')); ($setting != ) { $values['emailsReplyTo'] = $setting->get('value'); }if null unset($setting); ;break xPDOTransport::ACTION_UNINSTALL: ;case break}

$output = '<label = >Emails To:</label>for "quip-emailsTo"<input type= name= id= width= value= />"text" "emailsTo" "quip-emailsTo" "300" "'.$values['emailsTo'].'"<br /><br />

<label = >Emails From:</label>for "quip-emailsFrom"<input type= name= id= width= value="text" "emailsFrom" "quip-emailsFrom" "300"

/>"'.$values['emailsFrom'].'"<br /><br />

<label = >Emails Reply-To:</label>for "quip-emailsReplyTo"<input type= name= id= width= value="text" "emailsReplyTo" "quip-emailsReplyTo" "300"

/>';"'.$values['emailsReplyTo'].'"

$output;return

As you can see, some new constants here. These are available to all setup options forms and resolvers:

xPDOTransport::PACKAGE_ACTION - This tells us what action is being performed on the package; it is one of the following 3 values:xPDOTransport::ACTION_INSTALL - This is set when the package is being executed as an install.xPDOTransport::ACTION_UPGRADE - This is set when the package is being upgraded.xPDOTransport::ACTION_UNINSTALL - This is set when the package is being uninstalled. This doesn't apply to setup-options,obviously, since nothing is being set up. In future Revolution releases, it will allow you to do specific options for uninstall; but notyet.

Basically, we're presenting them with a form before install that looks like this:

Page 229: ModX Revolution Docs 20101007

So that they can set or update the values of the emailsTo, emailsFrom, and emailsReplyTo system settings before they install the package. Now,the script will first check to see if those settings already exist; and if so, we'll fill them in with those values. This allows for upgrades to gogracefully, persisting the user's custom settings for those values. Pretty cool, huh?

Obviously, there's a lot you could do with this. You could set target directories for photo locations, setup basic email accounts, set login/passinformation for 3rd party web service integrations, and more. We'll leave your imagination to do the work from here on out.

Let's go back to our PHP script resolver that processes this information:

Page 230: ModX Revolution Docs 20101007

<?php/** * Resolves setup-options settings by setting email options. * * @ quippackage * @subpackage build */$success= ;false

($options[xPDOTransport::PACKAGE_ACTION]) {switch xPDOTransport::ACTION_INSTALL:case xPDOTransport::ACTION_UPGRADE:case /* emailsTo */ $setting = $object->xpdo->getObject('modSystemSetting',array('key' => 'quip.emailsTo')); ($setting != ) {if null $setting->set('value',$options['emailsTo']); $setting->save(); } {else $object->xpdo->log(xPDO::LOG_LEVEL_ERROR,'[Quip] emailsTo setting could not be found, sothe setting could not be changed.'); }

/* emailsFrom */ $setting = $object->xpdo->getObject('modSystemSetting',array('key' => 'quip.emailsFrom')); ($setting != ) {if null $setting->set('value',$options['emailsFrom']); $setting->save(); } {else $object->xpdo->log(xPDO::LOG_LEVEL_ERROR,'[Quip] emailsFrom setting could not be found, sothe setting could not be changed.'); }

/* emailsReplyTo */ $setting = $object->xpdo->getObject('modSystemSetting',array('key' => 'quip.emailsReplyTo')); ($setting != ) {if null $setting->set('value',$options['emailsReplyTo']); $setting->save(); } {else $object->xpdo->log(xPDO::LOG_LEVEL_ERROR,'[Quip] emailsReplyTo setting could not be found,so the setting could not be changed.'); }

$success= ;true ;break xPDOTransport::ACTION_UNINSTALL:case $success= ;true ;break}

$success;return

Note that $modx is not available here; you're actually running these scripts from within the transport object. The $modx object is available as adifferent name, however: $object->xpdo. $object is the object that the resolver is attached to; here, it would be the modCategory.

Our script, then, is setting the values set in the setup-options to the newly installed system settings.

And now that we've got everything packaged and ready to go, let's pack the package into a zip file and give us the time it took to build thepackage:

Page 231: ModX Revolution Docs 20101007

$builder->pack();

$mtime= microtime();$mtime= explode( , $mtime);" "$mtime= $mtime[1] + $mtime[0];$tend= $mtime;$totalTime= ($tend - $tstart);$totalTime= sprintf( , $totalTime);"%2.4f s"

$modx->log(modX::LOG_LEVEL_INFO, );"\nPackage Built.\nExecution time: {$totalTime}\n"exit();

Great, we're done! You'll only need to run this script now, and viola! A fully zipped transport package file will appear in your core/packagesdirectory.

View the Source

Related Pages

Package ManagementTransport PackagesTransport Providers

Extending modUser

Intended Audience

This article attempts to ride the line of beginners desiring to learn the basics of setting up an extended modUser class and those moreexperienced individuals needing a foundation to begin with. For fully functional applications please refer to Currenty available extended modUser

.classes

Overview

By extending the MODx Revolution authentication layer we can simply and easily build very complex and varied user subsystems rivaling that ofsocial networking, user management systems, and other applications not yet conceptualized. This ability to extend the modUser class is just oneexample of the underlying power of MODx Revolution. By following the steps detailed below you will quickly be on your way to developing yourown user "interfaces" or sub-systems.

Purpose

Extending modUser is for those situations when user authentication interaction needs overridden, extended, enhanced, etc.  The focus is purelyuser authentication. Also, please understand this is a a simplified working concept.  You can get much more complex.

The Rules

Extending modUser does NOT mean we are adding anything to the _users table in the database.  It simply means we are going to bemodxappending our own data to the end of the table by attaching our data sets via relationships and a schema. At no time should an extendedapplication actually attempt to completely replace the modUser Class.  Instead we should be using it as a platform to build upon. The onlyindication that the user has been extended will be found by the class_key being changed from "modUser" to the extended class name.

Your extension should be used to access . If the user (object) has not been extended, do not allow your extension to interact withyour extensionthem -- hence: let your extension die.

MODx Revolution already handles users and probably does not need your help. While you may use your extension on *your* data, please do notbegin writing "bloat" which is already in modUser.  In other words use the Revolution resources for your extended users, but do not create code toreplace modUser.

Lastly, get familiar with , before you begin to code.  Some methods are not one-to-one as you might assume, such as attributes, whichmodUsercan be assigned per context, resource, etc. Typically use the modUser suggestions to access modUser methods.

Steps to extending modUser

1. ) Create the schema and generate a model

The first thing we need to accomplish, is to create an extended user schema which extends modUser.  Please note that there is no aggregaterelation upwards from your "main" class which is extending modUser. An example follows:

Page 232: ModX Revolution Docs 20101007

<?xml version= encoding= ?>"1.0" "UTF-8"<model = baseClass= platform= defaultEngine=package "extendeduser" "xPDOObject" "mysql" "MyISAM"tablePrefix= >"ext_"    <!-- inherit the modx user and extend it -->    <object class= table= = >"extUser" "users" extends "modUser"        <composite alias= local= foreign= cardinality= owner= />"Phones" "id" "user" "many" "local"        <composite alias= local= foreign= cardinality= owner= />"Table2" "id" "user" "many" "local"    </object>

    <!-- track all user phone numbers -->    <object table= = >"phone_numbers" extends "xPDOSimpleObject"        <field key= dbtype= phptype= = = index= />"user" " "int "integer" null " "false default "0" "index"        <field key= dbtype= precision= phptype= = ="""areacode" "varchar" "3" "string" null " "false default/>        <field key= dbtype= precision= phptype= = ="" />"number" "varchar" "7" "string" null " "false default        <aggregate alias= local= foreign= cardinality= owner= />"extUser" "user" "id" "one" "foreign"    </object>

    <!-- user extension -->    <object table= = >"table2" extends "xPDOSimpleObject"        <field key= dbtype= phptype= = = index= />"user" " "int "integer" null " "false default "0" "index"        <field key= dbtype= precision= phptype= = />  "myspaceurl" "varchar" "255" "string" null " "false             <aggregate alias= local= foreign= cardinality= owner= />"extUser" "user" "id" "one" "foreign"    </object></model>

You will need to parse and create the model map associated with this schema. As this process is out of the scope of this topic, please refer to for further information.Using Custom Database Tables in your 3rd Party Components

2.) Edit the extuser.class.php

To access the extended class, we have to inform modUser that the user in question has been extended. The _users table in the databasemodxcontains a field specifically for this purpose: class_key. The default value in this field is modUser. As users are added to your site using yourextension we need to "force" the name of our "main" class in the schema, namely extUser in our example.

Edit the extuser.class.php file created when you generated the model. The specific file is the one found in the top of the model tree (you shouldsee a mysql directory) in this same folder. Edit the file to resemble the following:

<?php/** * @ extendeduserpackage * @subpackage user.mysql */class extUser modUser {extends function __construct(xPDO & $xpdo) { parent :: __construct($xpdo); $ ->set('class_key','extUser');this }}?>

3.) Create (or edit) extension_packages in System Settings

Access the System settings found in the System menu of the manager, and search for: extension_packages.

If the key already exists, add

, extendeduser:{core_path}components/extendeduser/model/

Note the comma at the beginning of the Value.

If the key does not exists

Page 233: ModX Revolution Docs 20101007

 Create a new system setting with name of extension_packagesKey of extension_packagesFieldtype: Textfieldvalue 

extendeduser:{core_path}components/extendeduser/model/

Note the absence of a comma at the beginning of the Value.

4.) Final Step Create a class to access and utilize your extended class

Page 234: ModX Revolution Docs 20101007

<?php/** *  File        sample.class.php (requires MODx Revolution 2.x) * Created on    Aug 18, 2010 * Project        shawn_wilkerson * @     extendedUserpackage * @version    1.0 * @category    User Extension * @author        W. Shawn Wilkerson * @link        http://www.shawnWilkerson.com * @copyright  Copyright (c) 2010, W. Shawn Wilkerson.  All rights reserved. * @license      GPL * */

(!class_exists('Sampleclass')) {if    class Sampleclass    {        function __construct(modX & $modx, array $config= array ()) {

            /* Import modx as a reference */            $ ->modx= & $modx;this

            /* Establish the environment */            $ ->extPath= $modx->getOption('core_path', ,this nullMODX_CORE_PATH).'components/extendeduser/';            $ ->modx->addPackage('extendeduser', $ ->extPath .'model/', 'ut_');this this            $ ->_config= array_merge(array (this                'userID' => $ ->modx->user->get('id'),this            ), $config);

            /* Define the user */            $ ->userObj = $ ->setUser($ ->_config['userID']);this this this            $ ->userID = $ ->userObj->get('id');this this        }

        function __destruct() {            unset ($ ->extPath, $ ->userObj, $ ->userID, $ ->_config);this this this this        }

        /**         * Returns object of type Phone.         */        function getPhoneObj() {public            $ ->userObj->getOne('Phones');this            $ ->userObj->Phones;return this        }

        /**         * Returns object utUser instance of modUser Defaults to current user.         * @param $userID         */        function getUserObj($userID) {public            $ ->modx->getObject('modUser', $userID);return this        }

        /**         * Establishes the user.         * @param $userIDint         */        function setUser($userID){public            $ ->getUserObj($userID);return this        }    }}

5.) Accessing the class

In our example we will be accessing our extended user throughout our site, therefore we load it as a service as shown in the following example:

Page 235: ModX Revolution Docs 20101007

1.

2.

3. 4. 5.

a.

b. 6.

<?php$x = $modx->getService('extendeduser','Sampleclass',$modx->getOption('core_path', ,nullMODX_CORE_PATH).'components/extendeduser/',$scriptProperties);

(!($x Extendeduser)) {if instanceof    $modx->log(modX::LOG_LEVEL_ERROR,'[Extendeduser] Could not load Extendeduser class.');    $modx->event->output( );true}

;return

Noteworthy items

Any pre existing user, will still have modUser as the class_key and therefore will be extended or produce user objects of type extUsernotunless you change itDouble check the modx.mysql.schema.xml file to make sure you are not using classes or alias it is already using, as yours will supersedethe default moduser prohibiting you access to items such as the user attributes (with alias Profile)The extUser will have a table created in the database, but the attached relations willnotThe extended class table(s) be in the same database as the regular _users tablemust modxSymptoms of step 3 (extension_packages path) not being correct:

Any user with the class_key of extUser will return an error upon login: "User cannot be found...".  If this is the admin, access yourdatabase directly, return the class_key to modUser, login correctly and then alter the path to a correct representation of the path.The snippets attached to the class will intermittently work or fail altogether

To get counts from your data (i.e. how many phone numbers does this person have) use either (any criteria can be added):

$ ->modx->getCount('extPhones', array('user' => $ ->userID));this this$ ->modx->getCount('extPhones');this

It is completely possible to have multiple extended modUser systems active at the same time.  It would even be feasible to extend JasonCoward's rpx extension into a hybrid system utilizing the benefits of both systems.  It is also completely possible to have multiple extendedmodUser applications running autonomously.  This is simply done by following this process for each of your extensions, changing only the"class_key" field to reflect the extended class belonging to each respective user.

Suggested additional considerations

The model files can be edited with methods and descriptions. Take a look at much of the MODx / xPDO models and you will see this doneextensively.

This process can be automated and captured upon user login. For brevity sake, it is best to refer you to splittingred's github, where he provides areal world application:

The plugins:           http://github.com/splittingred/modActiveDirectory/blob/master/core/components/activedirectory/elements/plugins/plugin.activedirectory.php

The events:          http://github.com/splittingred/modActiveDirectory/blob/master/core/components/activedirectory/elements/events/onauthentication.php

                            http://github.com/splittingred/modActiveDirectory/blob/master/core/components/activedirectory/elements/events/onusernotfound.php

Extended modUser Classes currently Available

modActiveDirectory an application which provides interaction with a Microsoft Domain Controller

rpm extension allows people to login via Facebook and other social networking medium

Other Development Resources

This section covers alternative development options and information for MODx developers.

Loading MODx Externally

Page 236: ModX Revolution Docs 20101007

Loading the MODx Object

Using the MODx object (and all of its respective classes) is quite simple. All you need is this code:

require_once '/absolute/path/to/modx/config.core.php';require_once MODX_CORE_PATH.'config/'.MODX_CONFIG_KEY.'.inc.php';require_once MODX_CORE_PATH.'model/modx/modx.class.php';$modx = modX();new$modx->initialize('web');

This will initialize the MODx object into the 'web' . Now, if you want to access it under a different context (and thereby changing its accessContextpermissions, policies, etc), you'll just need to change 'web' to whatever you want to load.Context

From there, you can use any MODx methods, functions, or classes.

See Also

Developer IntroductionxPDO, the db-layer for Revolution

API Reference

The MODx Revolution API Documentation can be found here:

http://api.modxcms.com

Class Reference

modX

The modX Class

This is the base class of MODx Revolution; it is used for many of the main processing methods of MODx. It extends the class.xPDO

Methods

See Also

modX.getChunk

modX::getChunk

Processes and returns the output from an HTML chunk by name.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getChunk

Page 237: ModX Revolution Docs 20101007

string getChunk (string $chunkName, [array $properties = array ()])

Example

Lets process this chunk and output its value. We have this Chunk, called "WelcomeChunk":

<p>Welcome [[+name]]!</p>

We'll put this in our Snippet:

$output = $modx->getChunk('WelcomeChunk',array( 'name' => 'John',));

$output;return

This code outputs this:

<p>Welcome John!</p>

See Also

Chunks

modX.getLoginUserName

modX::getLoginUserName

Returns the current user name, for the current or specified context.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getLoginUserName

string getLoginUserName ([string $context = ''])

Example

Grab the user's username in the current Context.

$username = $modx->getLoginUserName();

See Also

Contexts

modX.getPlaceholder

modX::getPlaceholder

Get a placeholder value by key.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getPlaceholder

Page 238: ModX Revolution Docs 20101007

mixed getPlaceholder (string $key)

Example

$value = $modx->getPlaceholder('MyPlaceholder');

See Also

modX.setPlaceholdermodX.setPlaceholdersmodX.toPlaceholdermodX.toPlaceholders

modX.setPlaceholder

modX::setPlaceholder

Sets a Placeholder value.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#setPlaceholder

void setPlaceholder (string $key, mixed $value)

Example

$modx->setPlaceholder('name','Barry');

See Also

modX.getPlaceholdermodX.setPlaceholdersmodX.toPlaceholdermodX.toPlaceholders

modX.setPlaceholders

modX::setPlaceholders

Sets a collection of placeholders stored in an array or as object vars.An optional namespace parameter can be prepended to each placeholder key in the collection, to isolate the collection of placeholders.

Note that unlike , this function does not add separators between the namespace and the placeholder key. UsemodX.toPlaceholderstoPlaceholders() when working with multi-dimensional arrays or objects with variables other than scalars so each level gets delimited by aseparator.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#setPlaceholders

void setPlaceholders (array|object $placeholders, [string $namespace = ''])

Example

Add an array of placeholders, and prefix 'my.' to their key.

Page 239: ModX Revolution Docs 20101007

$modx->setPlaceholders(array( 'name' => 'John', 'email' => '[email protected]',),'my.');

See Also

modX.toPlaceholdermodX.toPlaceholdersmodX.setPlaceholdermodX.getPlaceholder

modX.addEventListener

modX::addEventListener

Add a plugin to the eventMap within the current execution cycle.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#addEventListener

boolean addEventListener (string $event, integer $pluginId)

Example

Add a Plugin with ID 2 to the Event 'OnChunkPrerender':

$modx->addEventListener('OnChunkPrerender',12);

See Also

modXPlugins

modX.checkForLocks

modX::checkForLocks

Checks for locking on a page. A page is "locked" if another user is already viewing it. This prevents collisions.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#checkForLocks

void checkForLocks (integer $id, string $action, string $type)

Example

Check for locks on the edit_chunk action.

if ($modx->checkForLocks($modx->getLoginUserID(),'edit_chunk','edit');

See Also

modX

Page 240: ModX Revolution Docs 20101007

modX.checkSession

modX::checkSession

Checks to see if the user has a session in the specified context.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#checkSession

boolean checkSession ([string $sessionContext = 'web'])

Example

Check to see if the user has a session in the 'sports' context.

$modx->checkSession('sports');

See Also

modX

modX.executeProcessor

modX::executeProcessor

Executes a specific processor. The only argument is an array, which can take the following values:

action - The action to take, similar to connector handling.processors_path - If specified, will override the default MODx processors path.location - A prefix to load processor files from, will prepend to the action parameter.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#executeProcessor

mixed executeProcessor (array $options)

Example

Execute the Context getList processor:

$modx->executeProcessor(array( 'location' => 'context', 'action' => 'getList',));

See Also

modX

modX.getAuthenticatedUser

modX::getAuthenticatedUser

Page 241: ModX Revolution Docs 20101007

Gets the user authenticated in the specified context.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getAuthenticatedUser

unknown getAuthenticatedUser ([string $contextKey = ''])

Example

Get the authenticated user for the 'sports' context:

$user = $modx->getAuthenticatedUser('sports');

See Also

modX

modX.getCacheManager

modX::getCacheManager

Get an extended xPDOCacheManager instance responsible for MODx caching.

Overrides xPDO::getCacheManager.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getCacheManager

object getCacheManager()

Example

Get the Cache Manager to set a dummy cache file.

$cacheManager = $modx->getCacheManager();$cacheManager->set('testcachefile','test123');

See Also

modX

modX.getChildIds

modX::getChildIds

Gets all of the child resource ids for a given resource.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getChildIds

array getChildIds ([integer $id = ], [integer $depth = 10])null

Example

Page 242: ModX Revolution Docs 20101007

Get all the children IDs for the Resource 23. Limit to 6 levels deep.

$array_ids = $modx->getChildIds(23,6);

See Also

modXmodX.getParentIds

modX.getConfig

modX::getConfig

Get the configuration for the site.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getConfig

array getConfig ()

Example

Get the site config into an array.

$config = $modx->getConfig();

See Also

modX

modX.getContext

modX::getContext

Retrieve a context by name without initializing it.

Within a request, contexts retrieved using this function will cache the context data into the modX::$contexts array to avoid loading the samecontext multiple times.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getContext

&$modContext getContext (string $contextKey)

Example

Get the 'sports' Context.

$ctx = $modx->getContext('sports');

See Also

Page: Contexts

Page: modX

Page 243: ModX Revolution Docs 20101007

Page: modX.getContext

Page: Contexts

Page: modX

Page: modX.getContext

modX.getEventMap

modX::getEventMap

Gets a map of events and registered plugins for the specified context.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getEventMap

array getEventMap (string $contextKey)

Example

Get the event map for the current Context.

$map = $modx->getEventMap();

See Also

modX

modX.getLoginUserID

modX::getLoginUserID

Returns the current user ID, for the current or specified context.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getLoginUserID

string getLoginUserID ([string $context = ''])

Example

Get the current login user ID for the 'sports' context.

$id = $modx->getLoginUserID('sports');

See Also

modX

modX.getParentIds

modX::getParentIds

Gets all of the parent resource ids for a given resource.

Page 244: ModX Revolution Docs 20101007

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getParentIds

array getParentIds ([integer $id = ], [integer $height = 10])null

Example

Get all of the parent IDs for the Resource with ID 23.

$parentIds = $modx->getParentIds(23);

See Also

modXmodX.getChildIds

modX.getParser

modX::getParser

Gets the MODx parser.

Returns an instance of modParser responsible for parsing tags in element content, performing actions, returning content and/or sending otherresponses in the process.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getParser

object getParser()

Example

Get the MODx Parser object.

$parser = $modx->getParser();

See Also

modX

modX.getRegisteredClientScripts

modX::getRegisteredClientScripts

Returns all registered JavaScript and HTML blocks.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getRegisteredClientScripts

string getRegisteredClientScripts ()

Example

Page 245: ModX Revolution Docs 20101007

Get all registered scripts into an array.

$scripts = $modx->getRegisteredClientScripts();

See Also

modX

modX.getRegisteredClientStartupScripts

modX::getRegisteredClientStartupScripts

Returns all registered startup CSS, JavaScript, or HTML blocks.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getRegisteredClientStartupScripts

string getRegisteredClientStartupScripts ()

Example

Get all registered startup scripts into an array.

$startupScripts = $modx->getRegisteredClientStartupScripts();

See Also

modX

modX.getRequest

modX::getRequest

Attempt to load the request handler class, if not already loaded. Defaults to modRequest.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getRequest

boolean getRequest ([$string $class = 'modRequest'], [$path $path = ''])

Example

Load a custom Request handler class called 'myRequest' from '/path/to/myrequest.class.php':

$modx->getRequest('myRequest','/path/to/');

See Also

modX

modX.getResponse

Page 246: ModX Revolution Docs 20101007

modX::getResponse

Attempt to load the response handler class, if not already loaded. Defaults to modResponse.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getResponse

boolean getResponse ([$string $class = 'modResponse'], [$path $path = ''])

Example

Load a custom Response handler class called 'myResponse' from '/path/to/myresponse.class.php':

$modx->getRequest('myResponse','/path/to/');

See Also

modX

modX.getService

modX::getService

Load and return a named service class instance.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getService

object getService (string $name, [string $class = ''], [string $path = ''], [array $params = array()])

Examples

Get the modSmarty service.

$modx->getService('smarty','smarty.modSmarty');

Get a custom, user-defined service called 'modTwitter' from a custom path ('/path/to/modtwitter.class.php'), and pass in some custom parameters.

$modx->getService('twitter','modTwitter','/path/to/',array( 'api_key' => 3212423,));$modx->twitter->tweet('Success!');

See Also

modXMODx Services

modX.getSessionState

modX::getSessionState

Page 247: ModX Revolution Docs 20101007

Returns the state of the SESSION being used by modX.

The possible values for session state are:

modX::SESSION_STATE_UNINITIALIZEDmodX::SESSION_STATE_UNAVAILABLEmodX::SESSION_STATE_EXTERNALmodX::SESSION_STATE_INITIALIZED

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getSessionState

integer getSessionState ()

Example

$state = $modx->getSessionState();

See Also

modX

modX.getTree

modX::getTree

Get a site tree from a single or multiple modResource instances.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getTree

array getTree ([ |array $id = ], [ $depth = 10])int null int

Example

Get a tree for the Resource with ID 12. Only go 5 levels deep.

$treeArray = $modx->getTree(12,5);

See Also

modX

modX.getUser

modX::getUser

Get the current authenticated User and assigns it to the modX instance.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getUser

modUser getUser ([string $contextKey = ''])

Page 248: ModX Revolution Docs 20101007

Example

Get the current auth'ed user and print out its username.

$user = $modx->getUser();echo $user->get('username');

See Also

modX

modX.getVersionData

modX::getVersionData

Gets the modX core version data. The array contains the following keys (examples for version "MODx Revolution 2.0.0-beta-3"):

version - The current version number, eg: 2major_version - The current major version number, eg: 0minor_version - The current minor version number, eg: 0patch_level - The current release level, eg: 'beta-3'code_name - The code name for the product, eg: 'Revolution'full_version - A compiled full version name, eg: '2.0.0-beta-3'full_appname - The entire version name, eg: 'MODx Revolution 2.0.0-beta-3'

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#getVersionData

array getVersionData ()

Example

Print out the current full version:

$vers = $modx->getVersionData();echo $vers['full_version'];

See Also

modX

modX.handleRequest

modX::handleRequest

Initialize, cleanse, and process a request made to a modX site.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#handleRequest

mixed handleRequest ()

Example

Handle the current request.

Page 249: ModX Revolution Docs 20101007

$modx->handleRequest();

See Also

modX

modX.hasPermission

modX::hasPermission

Returns true if user has the specified policy permission.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#hasPermission

boolean hasPermission (string $pm)

Example

Deny the user access if they don't have the permission 'edit_chunk' in their loaded Policies.

if (!$modx->hasPermission('edit_chunk')) die('Access Denied!');

See Also

Policies

modX.initialize

modX::initialize

Initializes the modX engine into a .Context

This includes preparing the session, pre-loading some common classes and objects, the current site and context settings, extension packagesused to override session handling, error handling, or other initialization classes.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#initialize

void initialize ([string $contextKey = 'web'])

Example

Initialize the 'sports' Context.

$modx->initialize('sports');

See Also

Contexts

modX.invokeEvent

Page 250: ModX Revolution Docs 20101007

modX::invokeEvent

Invokes a specified Event with an optional array of parameters.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#invokeEvent

void invokeEvent (string $eventName, [array $params = array ()])

Example

Invoke the OnChunkRender event:

$modx->invokeEvent('OnChunkRender',array( 'id' => $chunk->get('id'),));

See Also

modX

modX.lexicon

modX::lexicon

Grabs a processed Lexicon Entry.

This may also be a modLexicon object as well, if the Lexicon has been loaded. PHP supports having objects and methods withthe same name.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#lexicon

void lexicon (string $key, [array $params = array()])

Example

Output the translation of the 'welcome_message' Entry, and sets the 'name' Placeholder in it.

echo $modx->lexicon('welcome_message',array('name' => 'John'));

See Also

Internationalization

modX.makeUrl

modX::makeUrl

Generates a URL representing a specified resource.

The scheme indicates in what format the URL is generated.

-1 : (default value) URL is relative to site_url

Page 251: ModX Revolution Docs 20101007

0 : see http1 : see httpsfull : URL is absolute, prepended with site_url from configabs : URL is absolute, prepended with base_url from confighttp : URL is absolute, forced to http schemehttps : URL is absolute, forced to https scheme

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#makeUrl

string makeUrl (integer $id, [string $context = ''], [string $args = ''], [mixed $scheme = -1])

Examples

Make a URL for the Resource with ID 4.

$url = $modx->makeUrl(4);

Make a URL for the Resource with ID 12, but make sure it's in HTTPS.

$url = $modx->makeUrl(12,'','','https');

modX.parseChunk

modX::parseChunk

Parse a chunk using an associative array of replacement variables.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#parseChunk

string parseChunk (string $chunkName, array $chunkArr, [string $prefix = '[[+'], [string $suffix =']]'])

Example

$output = $modx->parseChunk('myChunk',array('name' => 'John'));

See Also

modXmodX.getChunk

modX.regClientCSS

modX::regClientCSS

Register CSS to be injected inside the HEAD tag of a resource.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#regClientCSS

void regClientCSS (string $src)

Page 252: ModX Revolution Docs 20101007

Example

Register a CSS file to the HEAD tag:

$modx->regClientCSS('assets/css/style.css');

See Also

modXmodX.regClientHTMLBlockmodX.regClientScriptmodX.regClientStartupHTMLBlockmodX.regClientStartupScriptmodX.getRegisteredClientScriptsmodX.getRegisteredClientStartupScripts

modX.regClientHTMLBlock

modX::regClientHTMLBlock

Register HTML to be injected before the closing BODY tag.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#regClientHTMLBlock

void regClientHTMLBlock (string $html)

Example

Inject a footer into the page.

$modx->regClientHTMLBlock('<div id= >(c) 2009 MODx</div>');"footer"

See Also

modXmodX.regClientCSSmodX.regClientScriptmodX.regClientStartupHTMLBlockmodX.regClientStartupScriptmodX.getRegisteredClientScriptsmodX.getRegisteredClientStartupScripts

modX.regClientScript

modX::regClientScript

Register JavaScript to be injected before the closing BODY tag.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#regClientScript

void regClientScript (string $src, [ $plaintext = ])boolean false

Example

Page 253: ModX Revolution Docs 20101007

Add some JS to the end of the page.

$modx->regClientScript('assets/js/footer.js');

See Also

modXmodX.regClientCSSmodX.regClientHTMLBlockmodX.regClientStartupHTMLBlockmodX.regClientStartupScriptmodX.getRegisteredClientScriptsmodX.getRegisteredClientStartupScripts

modX.regClientStartupHTMLBlock

modX::regClientStartupHTMLBlock

Register HTML to be injected before the closing HEAD tag.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#regClientStartupHTMLBlock

void regClientStartupHTMLBlock (string $html)

Example

Render a faux tag element before the end of the HEAD.

$modx->regClientStartupHTMLBlock('<tag></tag>');

See Also

modXmodX.regClientCSSmodX.regClientHTMLBlockmodX.regClientScriptmodX.regClientStartupScriptmodX.getRegisteredClientScriptsmodX.getRegisteredClientStartupScripts

modX.regClientStartupScript

modX::regClientStartupScript

Register JavaScript to be injected inside the HEAD tag of a resource.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#regClientStartupScript

void regClientStartupScript (string $src, [ $plaintext = ])boolean false

Example

Register some JS to the start of the page:

Page 254: ModX Revolution Docs 20101007

$modx->regClientStartupScript('assets/js/onload.js');

See Also

modXmodX.regClientCSSmodX.regClientHTMLBlockmodX.regClientScriptmodX.regClientStartupHTMLBlockmodX.getRegisteredClientScriptsmodX.getRegisteredClientStartupScripts

modX.reloadConfig

modX::reloadConfig

Reload the config settings. Useful in cases where you've loaded some Settings dynamically.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#reloadConfig

array reloadConfig ()

Example

$modx->reloadConfig();

See Also

modXSettingsSystem Settings

modX.removeAllEventListener

modX::removeAllEventListener

Remove all registered events for the current request.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#removeAllEventListener

void removeAllEventListener ()

Example

Eliminate any other events from firing:

$modx->removeAllEventListener();

See Also

modX

Page 255: ModX Revolution Docs 20101007

modX.removeEventListener

modX::removeEventListener

Remove an event from the eventMap so it will not be invoked.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#removeEventListener

boolean removeEventListener (string $event)

Example

Prevent any Events from firing on 'OnChunkRender':

$modx->removeEventListener('OnChunkRender');

See Also

modX

modX.runSnippet

modX::runSnippet

Process and return the output from a PHP snippet by name.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#runSnippet

string runSnippet (string $snippetName, [array $params = array ()])

Example

Run the 'Welcome' snippet with some custom parameters:

$output = $modx->runSnippet('Welcome',array( 'name' => 'John'));echo $output; // prints 'Welcome John!'

See Also

modXSnippets

modX.sendError

modX::sendError

Send the user to a type-specific core error page and halt PHP execution.

The parameter 'type' can be any field, which will load the template file in core/error. MODx comes prepackaged with 2 default error pages; theseare 'unavailable' (the default), and 'fatal'.

Page 256: ModX Revolution Docs 20101007

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#sendError

void sendError ([string $type = ''], [array $options = array()])

Examples

Send an Unavailable 503 error page.

$modx->sendError('unavailable');

Send a Fatal 500 error page.

$modx->sendError('fatal');

See Also

modX

modX.sendErrorPage

modX::sendErrorPage

Send the user to a MODx virtual error page.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#sendErrorPage

void sendErrorPage ([array $options = ])null

Example

Send the user to the default Error page for the site.

$modx->sendErrorPage();

See Also

modXmodX.sendUnauthorizedPagemodX.sendForwardmodX.sendRedirect

modX.sendForward

modX::sendForward

Forwards the request to another resource without changing the URL. If the ID provided does not exist, sends to a 404 Error page.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#sendForward

Page 257: ModX Revolution Docs 20101007

void sendForward (integer $id, [string $options = ])null

Example

Send the user to Resource ID 234 without actually changing the URL.

$modx->sendForward(234);

See Also

modXmodX.sendRedirectmodX.sendErrorPage

modX.sendRedirect

modX::sendRedirect

Sends a redirect to the specified URL using the specified method.

Valid $type values include:

REDIRECT_REFRESH - Uses the header refresh methodREDIRECT_META - Sends a a META HTTP-EQUIV="Refresh" tag to the outputREDIRECT_HEADER - Uses the header location method

REDIRECT_HEADER is the default.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#sendRedirect

void sendRedirect (string $url, [integer $count_attempts = 0], [string $type = ''])

Examples

Send a redirection request to the Resource with ID 54.

$url = $modx->makeUrl(54);$modx->sendRedirect($url);

Send a redirection request to modxcms.com. Do so via the META HTTP-EQUIV refresh tag.

$modx->sendRedirect('http://modxcms.com',0,REDIRECT_META);

See Also

modXmodX.sendForwardmodX.sendErrorPage

modX.sendUnauthorizedPage

modX::sendUnauthorizedPage

Send the user to the MODx unauthorized page.

Page 258: ModX Revolution Docs 20101007

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#sendUnauthorizedPage

void sendUnauthorizedPage ([array $options = ])null

Example

Send the user to the unauth page.

$modx->sendUnauthorizedPage();

See Also

modXmodX.sendErrorPagemodX.sendForwardmodX.sendRedirect

modX.setDebug

modX::setDebug

Sets the debugging features of the modX instance.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#setDebug

boolean| setDebug ([ | $debug = ], [ $stopOnNotice = ])int boolean int true boolean false

Example

Turn debug mode on, and tell the process to stop if Notices occur:

$modx->setDebug( );true

See Also

Page: modX.setDebug

Page: modX.setDebug

modX.switchContext

modX::switchContext

Switches the primary Context for the modX instance.

Be aware that switching contexts does not allow custom session handling classes to be loaded. The gateway defines the session handling that isapplied to a single request. To create a context with a custom session handler you must create a unique context gateway that initializes thatcontext directly.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#switchContext

boolean switchContext (string $contextKey)

Page 259: ModX Revolution Docs 20101007

Example

Switch to the 'sports' Context.

$modx->switchContext('sports');

See Also

Contexts

modX.toPlaceholder

modX::toPlaceholder

Recursively validates and sets placeholders appropriate to the value type passed.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#toPlaceholder

void toPlaceholder (string $key, mixed $value, [string $prefix = ''], [string $separator = '.'])

Example

Set a placeholder and prefix its key with 'my.'

$modx->toPlaceholder('name','John','my');

See Also

modX.toPlaceholdersmodX.setPlaceholdermodX.setPlaceholdersmodX.getPlaceholder

modX.toPlaceholders

modX::toPlaceholders

Sets placeholders from values stored in arrays and objects.

Each recursive level adds to the prefix, building an access path using an optional separator.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#toPlaceholders

void toPlaceholders (array|object $subject, [string $prefix = ''], [string $separator = '.'])

Example

Set an array of placeholders and prefix with 'my.'

Page 260: ModX Revolution Docs 20101007

$modx->toPlaceholders(array( 'name' => 'John', 'email' => '[email protected]',),'my');

See Also

modX.toPlaceholdermodX.setPlaceholdermodX.setPlaceholdersmodX.getPlaceholder

modX.unsetPlaceholder

modX::unsetPlaceholder

Unsets a placeholder value by key.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#unsetPlaceholder

void unsetPlaceholder (string $key)

Example

$modx->unsetPlaceholder('myPlaceholder');

See Also

modX.unsetPlaceholdersmodX.toPlaceholdermodX.toPlaceholdersmodX.setPlaceholdermodX.setPlaceholdersmodX.getPlaceholder

modX.unsetPlaceholders

modX::unsetPlaceholders

Unset multiple placeholders, either by prefix or an array of keys.

Syntax

API Doc: http://api.modxcms.com/modx/modX.html#unsetPlaceholders

void unsetPlaceholders (string|array $keys)

Example

Unset the 'my.name' and 'my.email' Placeholders.

$modx->unsetPlaceholders(array('my.name','my.email'));

Unset all Placeholders that are prefixed with 'my.'

Page 261: ModX Revolution Docs 20101007

$modx->unsetPlaceholders('my.');

See Also

modX.unsetPlaceholdermodX.setPlaceholdermodX.setPlaceholdersmodX.toPlaceholdermodX.toPlaceholders

modChunk

The modChunk Class

This is the Chunk base class for MODx Revolution.

Methods

See Also

Page: (at)CHUNK

Page: modChunk.getContent

Page: modChunk.setContent

Page: modChunk

Page: (at)CHUNK

Page: modChunk

Page: modChunk.getContent

Page: modChunk.setContent

modChunk.getContent

modChunk::getContent

Get the source content of this chunk.

Syntax

API Doc: http://api.modxcms.com/modx/modChunk.html#getContent

void getContent ([ $options = array()])

Example

$chunk = $modx->getObject('modChunk',array('name' => 'MyChunk')); ($chunk) {if

$content = $chunk->getContent();}

See Also

Page: (at)CHUNK

Page 262: ModX Revolution Docs 20101007

Page: modChunk.getContent

Page: modChunk.setContent

Page: modChunk

Page: (at)CHUNK

Page: modChunk

Page: modChunk.getContent

Page: modChunk.setContent

modChunk.setContent

modChunk::setContent

Sets the content of this Chunk.

Syntax

API Doc: http://api.modxcms.com/modx/modChunk.html#

void setContent ( $content, [ $options = array()])

Example

$chunk->setContent('<h2>Hello!</h2>');

See Also

Page: (at)CHUNK

Page: modChunk.getContent

Page: modChunk.setContent

Page: modChunk

Page: (at)CHUNK

Page: modChunk

Page: modChunk.getContent

Page: modChunk.setContent

modUser

The modUser Class

This is the base User class for MODx Revolution.

Methods

See Also

Page: Users

Page: modUser

Page: Users

Page 263: ModX Revolution Docs 20101007

Page: modUser

modUser.isAuthenticated

modUser::isAuthenticated

Determines if this user is authenticated in a specific context.

Separate session contexts can allow users to login/out of specific sub-sites individually (or in collections).

Syntax

API Doc: http://api.modxcms.com/modx/modUser.html#isAuthenticated

boolean isAuthenticated ([string $sessionContext = 'web'])

Example

See if the User is logged into the 'web' context. If not, deny access and send to Unauthorized Page.

if (!$modx->isAuthenticated('web')) { $modx->sendUnauthorizedPage();}

See Also

Page: Users

Page: modUser

Page: Users

Page: modUser

modUser.addSessionContext

modUser::addSessionContext

Adds a new context to the user session context array.

Syntax

API Doc: http://api.modxcms.com/modx/modUser.html#addSessionContext

void addSessionContext (string $context)

Example

Add a 'sports' Context session to the user.

$modx->addSessionContext('sports');

See Also

Page: Users

Page: modUser

Page: Users

Page: modUser

Page 264: ModX Revolution Docs 20101007

modUser.changePassword

modUser::changePassword

Change the User password.

Syntax

API Doc: http://api.modxcms.com/modx/modUser.html#changePassword

boolean changePassword (string $newPassword, string $oldPassword)

Example

Change the password from 'boo123' to 'b33r4me'

$modx->changePassword('b33r4me', 'boo123');

See Also

Page: Users

Page: modUser

Page: Users

Page: modUser

modUser.endSession

modUser::endSession

Ends a user session completely, including all contexts.

Syntax

API Doc: http://api.modxcms.com/modx/modUser.html#endSession

void endSession ()

Example

End the user's session.

$user->endSession();

See Also

modUser

modUser.getSessionContexts

modUser::getSessionContexts

Returns an array of user session context keys.

Page 265: ModX Revolution Docs 20101007

Syntax

API Doc: http://api.modxcms.com/modx/modUser.html#getSessionContexts

array getSessionContexts ()

Example

Get all user seesion contexts for this user that is logged into the web and mgr contexts:

$keys = $user->getSessionContexts();print_r($keys); // prints Array ( 'web', 'mgr' );

See Also

modUser

modUser.getSettings

modUser::getSettings

Gets all user settings in array format.

Syntax

API Doc: http://api.modxcms.com/modx/modUser.html#getSettings

array getSettings ()

Example

Get all the User Settings for this User.

$settings = $user->getSettings();

See Also

modUserSettings

modUser.hasSessionContext

modUser::hasSessionContext

Checks if the user has a specific session context, or in other words, is "logged into" a certain context.

Syntax

API Doc: http://api.modxcms.com/modx/modUser.html#hasSessionContext

boolean hasSessionContext (mixed $context)

Example

See if the User has a Session for the 'sports' Context:

Page 266: ModX Revolution Docs 20101007

if ($user->hasSessionContext('sports')) { // code heredo}

See Also

modUserContexts

modUser.isMember

modUser::isMember

States whether a user is a member of a group or groups. You may specify either a string name of the group, or an array of names.

Syntax

API Doc: http://api.modxcms.com/modx/modUser.html#isMember

boolean isMember (mixed $groups)

Example

See if the User is a member of the 'Staff' group:

$user->isMember('Staff');

See if the User is a member of either the 'Staff' or 'Investors' groups.

$user->isMember(array('Staff','Investors'));

See Also

modUser

modUser.loadAttributes

modUser::loadAttributes

Loads the principal attributes that define a modUser security profile.

Syntax

API Doc: http://api.modxcms.com/modx/modUser.html#loadAttributes

void loadAttributes ( $target, [ $context = ''], [ $reload = ])false

Example

Load attributes for the 'sports' context and the modResource target.

$user->loadAttributes('modResource','sports', );true

See Also

Page 267: ModX Revolution Docs 20101007

modUser

modUser.removeSessionContext

modUser::removeSessionContext

Removes a user session context.

Syntax

API Doc: http://api.modxcms.com/modx/modUser.html#removeSessionContext

void removeSessionContext (string|array $context)

Example

Remove the session for the User in the 'sports' Context.

$user->removeSessionContext('sports');

See Also

modUserContexts

modUser.removeSessionContextVars

modUser::removeSessionContextVars

Removes the session vars associated with a specific context.

Syntax

API Doc: http://api.modxcms.com/modx/modUser.html#removeSessionContextVars

void removeSessionContextVars (string $context)

Example

Remove all session vars for the User in the 'sports' Context.

$user->removeSessionContextVars('sports');

See Also

modUserContexts

modUser.removeSessionCookie

modUser::removeSessionCookie

Removes a session cookie for a user.

Syntax

Page 268: ModX Revolution Docs 20101007

API Doc: http://api.modxcms.com/modx/modUser.html#removeSessionCookie

void removeSessionCookie (string $context)

Example

Remove the Session Cookie for the User in the 'sports' Context.

$user->removeSessionCookie('sports');

See Also

Page: Users

Page: modUser

Page: Users

Page: modUser

Case Studies and Tutorials

Case Studies and Tutorials

This page contains a list of case studies and tutorials for various MODx Revolution scenarios.

Using Custom Database Tables in your 3rd Party Components

The ScenarioOur ModelBuilding the SchemaUsing our New ModelSee Also

So you're developing your custom component for MODx Revolution, and you've run into a dilemma. You've got some data that uses a table inyour MODx database, but you want a way to use xPDO's object model to access it. This tutorial will walk you through the process of creating yourown custom schema, adding it as an xPDO model package, and querying it.

The Scenario

So let's say we want to create a custom component called "StoreFinder" that takes a zip code from a textfield and then looks up all the storelocations with that zip code and returns them in a table. Currently we'll have one table for this: (note the prefix "modx_" - this is specific to your DBconnection, done in Revolution setup.)

modx_sfinder_stores

Our component will grab all the stores with the specified zip code. Our store table will have the following fields:

idnameaddresscitystatezipcountryphonefaxactive

Page 269: ModX Revolution Docs 20101007

So now that we've got an idea of what's in our tables, let's make the schema file that defines the model. This "schema" file is an XMLrepresentation of our database table(s). It is then parsed by xPDO into PHP-format "maps", which are array representations of the schema and itsrelationships.

Our Model

First off, let's take a quick look at our directory structure. This isn't always how you have to do it - this one is specifically built this way for SVN; butit's definitely recommended, especially with the structures, since that makes creating the transport package (shouldcore/components/storefinder/we want to distribute this via Package Management) much easier.

Now, on to the model file. In our _build directory, let's create a "schema" subfolder. Then, from there, we'll create a file called"storefinder.mysql.schema.xml". Note that "mysql" is in there - yes, eventually xPDO and Revolution will support other database platforms. But fornow, we're going to do this in MySQL.

In our XML file, let's start out with the first few lines:

<?xml version= encoding= ?>"1.0" "UTF-8"<model package= baseClass= platform= defaultEngine="storefinder" "xPDOObject" "mysql" "MyISAM"phpdoc-package= phpdoc-subpackage= >"storefinder" "model"

First we'll tell the browser and parser that this is XML code with a standard XML header. Next, we're going to create a "model" tag, and put someattributes into it. They are:

package - The name of the xPDO package (note this is different than a "transport package", a Revolution term). This is how xPDOseparates different models and manages them.baseClass - This is the base class from which all your class definitions will extend. Unless you're planning on creating a customxPDOObject extension, it's best to leave it at the default.platform - The database platform you're using. At this time, xPDO only supports mysql.defaultEngine - The default engine of the database tables, usually either MyISAM or InnoDB. MODx recommends using MyISAM.phpdoc-package & phpdoc-subpackage - These are custom attributes we're going to use in our map and class files. They're notstandard xPDO attributes, but show that you can put whatever you want as attributes.

Great! Now we've got our model definition. Let's add a table tag as the next line.

<object class= table= = >"sfStore" "sfinder_stores" extends "xPDOSimpleObject"

"Object" is our representation of a table, which will generate into an xPDOObject class when we're through. There are some attributes to notehere:

class - This is the name of the class we want to be generated from the table. Here, we'll use "sfStore". Note that instead of just "Store",we prefixed it with "sf" to prevent collisions with any other packages we might install that might also have Store tables.

Page 270: ModX Revolution Docs 20101007

table - This should point to the actual database table name, minus the prefix.extends - This is the class that it extends. Note that you can make subclasses and extended classes straight from the XML. Extendedclasses will inherit their parent class's fields.

You'll see here that this table extends "xPDOSimpleObject", rather than xPDOObject. This means that the table comes already with an "id" field,that is an auto-increment primary key.

Now that we've got a table definition for our stores table, let's add some field definitions to it:

<field key= dbtype= precision= phptype= = ="name" "varchar" "100" "string" null " "false default "" index="index" /><field key= dbtype= precision= phptype= = ="" />"address" "varchar" "255" "string" null " "false default<field key= dbtype= precision= phptype= = ="" />"city" "varchar" "255" "string" null " "false default<field key= dbtype= precision= phptype= = ="" />"state" "varchar" "255" "string" null " "false default<field key= dbtype= precision= phptype= = = index="zip" "varchar" "10" "string" null " "false default "0"

/>"index"<field key= dbtype= precision= phptype= = ="" />"country" "varchar" "20" "string" null " "false default<field key= dbtype= precision= phptype= = ="" />"phone" "varchar" "20" "string" null " "false default<field key= dbtype= precision= phptype= = ="" />"fax" "varchar" "20" "string" null " "false default<field key= dbtype= precision= attributes= phptype= = "active" " "int "1" "unsigned" "integer" null " "false

= />default "0"

As you can see here, each column in our table has a field definition tag. From there, we haveattribute properties for each field. Most of these are optional, depending on the database type of the column. Some of those attribute propertiesare:

key - The key name of the column.dbtype - The DB type - such as varchar, int, text, tinyint, etc.precision - The precision of the field. Usually this is the max number of characters.attributes - Only applies to some DB types; in integers you can set to "unsigned" to make sure that the value is always positive.phptype - The corresponding PHP type of the DB field type.null - If the field can be NULL or not.default - The default starting value of the field should none be set.index - An optional field, when set, will add a type of index to the field. Some of the values are "pk", "index", and "fk".

And we'll finish by closing the object and model tags:

</object></model>

So now we have a completed XML schema for our model! You can view the full version. Let's move on to the schema build script.here

Building the Schema

Go ahead and create a 'build.config.php' file in your _build directory. It should contain this:

<?phpdefine('MODX_BASE_PATH', dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/MODxRevolution/');define('MODX_CORE_PATH', MODX_BASE_PATH . 'core/');define('MODX_MANAGER_PATH', MODX_BASE_PATH . 'manager/');define('MODX_CONNECTORS_PATH', MODX_BASE_PATH . 'connectors/');define('MODX_ASSETS_PATH', MODX_BASE_PATH . 'assets/');

...where obviously MODX_BASE_PATH will need to point to where you installed MODx Revolution. If you moved the manager or core outside ofthat base path, you'll need to adjust those defines as well. From here, create a 'build.schema.php' file in your _build directory. At the top, put this:

Page 271: ModX Revolution Docs 20101007

<?php/** * Build Schema script * * @ storefinderpackage * @subpackage build */$mtime = microtime();$mtime = explode( , $mtime);" "$mtime = $mtime[1] + $mtime[0];$tstart = $mtime;set_time_limit(0);

require_once dirname(__FILE__) . '/build.config.php';include_once MODX_CORE_PATH . 'model/modx/modx.class.php';$modx= modX();new$modx->initialize('mgr');$modx->loadClass('transport.modPackageBuilder','', , );false true$modx->setLogLevel(modX::LOG_LEVEL_INFO);$modx->setLogTarget(XPDO_CLI_MODE ? 'ECHO' : 'HTML');

$root = dirname(dirname(__FILE__)).'/';$sources = array( 'root' => $root, 'core' => $root.'core/components/storefinder/', 'model' => $root.'core/components/storefinder/model/', 'assets' => $root.'assets/components/storefinder/', 'schema' => $root.'_build/schema/',);

This will do a few things. First off, it starts up a nice execution time script for us, so we can see how long it takes to build the schema. Secondly, Itincludes our build.config.php file to tell the schema script where to find MODx Revolution. Thirdly, it loads the necessary classes, initializes themodX object, and loads the modPackageBuilder class. And finally, it sets some log levels and some base paths for our build script.

Note that you'll want to make sure the $sources array has the correct paths defined; otherwise your script wont run. Let's add a couple more linesto our schema build script:

$manager= $modx->getManager();$generator= $manager->getGenerator();

These lines will load xPDOManager and xPDOGenerator, two classes we'll need to build our schema map files.

And finally, we want to actually parse this into a file:

$generator->parseSchema($sources['schema'].'storefinder.mysql.schema.xml', $sources['model']);

$mtime= microtime();$mtime= explode( , $mtime);" "$mtime= $mtime[1] + $mtime[0];$tend= $mtime;$totalTime= ($tend - $tstart);$totalTime= sprintf( , $totalTime);"%2.4f s"

echo ;"\nExecution time: {$totalTime}\n"

exit ();

This block of code executes the schema parsing method, and then outputs the total time the script took to execute. Run it, and viola! Ourstorefinder/core/model/storefinder/ directory is now filled with all of our map and class files!

Using our New Model

You may be asking, "Okay, that's great. Now how do I these?" Well, xPDO makes it incredibly simple. Let's first create our snippet file in ourusecore/components/storefinder/ directory, and call it 'snippet.storefinder.php' -- we're going to tie into a file on the file system because it's easier toedit it using a text editor, and we want a file on the file system for our build package.

Page 272: ModX Revolution Docs 20101007

Before we proceed, let's enable testing of this snippet directly from MODx. Since we're developing this in a separate directory from our MODxinstall, let's create a snippet called 'StoreFinder' in our MODx Revolution instance, and put this inside of it (you'll need to change the first line tothe correct path):

$base_path = dirname(dirname($modx->getOption('core_path'))).'/MODxComponents/tutorials/storefinder/trunk/core/components/storefinder/';/* change above line to your path */

$o = '';$f = $base_path.'snippet.storefinder.php';

(file_exists($f)) {if $o = include $f;} {else $modx->setLogTarget('ECHO'); $modx->log(modX::LOG_LEVEL_ERROR,'StoreFinder not found at: '.$f);}

$o;return

This little helper code allows us to do our development in our own code editor of choice until we're ready to package and distribute ourComponent. Then we'll simply delete this 'StoreFinder' snippet from our MODx Revolution instance, and install our package. You can find moreabout building packages by going . If you don't want to build a transport package (we recommend doing so, it makes upgrades FAR easier!),hereyou can simply just copy the files to their proper directories in the manager.

Okay, back to our snippet. Open up 'snippet.storefinder.php' in your editor, and add this code:

<?php/** * @ storefinderpackage */$base_path = !empty($base_path) ? $base_path :$modx->getOption('core_path').'components/storefinder/';

You'll see here that we're setting a $base_path variable if and only if it's not already set. Why? Well, this allows us to do development outside ourtarget directory (like we're doing now). If no base_path is set, then we simply point it to where the component will be installed:core/components/storefinder/

Now on to the brunt of the code. You've got your snippet working, you're in an easy development environment, and now you're ready to get thatmodel working. First off, add these lines:

$modx->addPackage('storefinder',$base_path.'model/');

This will add the package to xPDO, and allow you to use all of xPDO's functions with your model. Let's test it out:

$stores = $modx->getCollection('sfStore');echo 'Total: '.count($stores);

Note the first time you run this, it might throw an error. This is because xPDO is dynamically creating your database table from your schema. Afterrunning, it should show "Total: 0".

Let's add a few records into the database for testing. Above the getCollection call, add:

Page 273: ModX Revolution Docs 20101007

$store = $modx->newObject('sfStore');$store->fromArray(array( 'name' => 'Store 1', 'address' => '12 Grimmauld Place', 'city' => 'London', 'country' => 'England', 'zip' => '12345', 'phone' => '555-2134-543',));$store->save();

$store = $modx->newObject('sfStore');$store->fromArray(array( 'name' => 'Store 2', 'address' => '4 Privet Drive', 'city' => 'London', 'country' => 'England', 'zip' => '53491', 'phone' => '555-2011-978',));$store->save();

Run this (unless you want duplicate data). That should populate your table with some data, and then output 'Total: 2', assuming youonly oncedidn't remove the getCollection lines. After you've run it, go ahead and erase those lines.

Okay, now we've got our model running smoothly! For those of you who are already familiar with component development, the second part of thistutorial will be dealing with finishing our Component's scenario. You can stop reading if you want.

Part 2 Coming Soon...

See Also

Generating the xPDO Model Codehttp://svn.modxcms.com/docs/display/revolution/PHP+Coding+in+MODx+Revolution%2C+Pt.+I

Creating a Blog in MODx Revolution

Creating a Blog in MODx RevolutionGetting the Needed Extras

Needed ExtrasOptional Extras

Creating your Blog Post TemplateHeader and FooterThe Post InfoThe Post ContentAdding Comments to Posts

Setting up TaggingCreating the Sections

Setting up the blogPost ChunkSetting up Your Blog HomeAdding Posts

Page Structure Within the SectionsAdding a New Blog Post

Setting up Your ArchivesCreating the Archives ResourceSetting up the Archivist Widget

Advanced OptionsAdding a Moderator GroupAdding a "Latest Posts" widgetAdding a "Latest Comments" widgetAdding a "Most Used Tags" widget

Conclusion

Creating a Blog in MODx Revolution

This tutorial is here to help you setup a flexible, powerful blogging solution in MODx Revolution. Since MODx Revolution is not blogging software,

Page 274: ModX Revolution Docs 20101007

but rather a full-blown Content Application Platform, it doesn't come pre-packaged with a cookie-cutter blogging solution. You'll need to setup yourblog how you want it.

Fortunately, the tools to do so are already there for your taking. This tutorial will walk you through how to set them up. It's recommended thatyou're familiar with Revolution's before we start.Tag Syntax

One thing before we start, though - this tutorial is extensive, and will show you how to set up a powerful blog with posting, archiving, tagging,commenting and more. If you don't need any specific part, just skip that part. MODx is modular, and your blog can function in any scope you like.And, again, this is only one way to do it - there are tons of ways to setup a blog in MODx Revolution.

This tutorial was based on the blog setup at . If you'd like a demo before reading, try there.splittingred.com

Getting the Needed Extras

First off, you'll want to go ahead and download and install some Extras that we'll be using in our Blog. The following is a list of mostcommonly-used Extras:

Needed Extras

getResources - For listing posts, pages and other Resources.getPage - For pagination of listings.Quip - For anything and everything in commenting.tagLister - For managing tags and doing tag-based navigation.Archivist - For managing your Archives section.

Optional Extras

Breadcrumbs - For displaying a breadcrumb navigation trail.Gallery - For managing photo Galleries.SimpleSearch - For adding a simple search box to your site.getFeed - If you want to grab other feeds in your site, such as a Twitter feed.Login - If you want to restrict commenting to logged in users only, you'll need this.

Creating your Blog Post Template

First off, you'll want to have a Template that's geared just for Blog Posts. Why? Well, if you want comments and special formatting or pagedisplays for your blog, you'll probably not want to have to do that for each Blog Post. So, the best route is to setup your own blog post template.This tutorial already assumes you have a base Template for your normal pages on the site - we'll reference that later on as 'BaseTemplate'.

We'll create one called 'BlogPostTemplate'. Our content looks something like this:

Page 275: ModX Revolution Docs 20101007

[[$pageHeader]]<div id= class= >"content" "blog-post" <h2 class= ><a href= >[[*pagetitle]]</a></h2>"title" "[[~[[*id]]]]" <p class= >"post-info" Posted on [[*publishedon:strtotime:date=`%b %d, %Y`]] | Tags: [[*tags:notempty=`[[!tolinks? &items=`[[*tags]]` &key=`tag` &target=`1`]]`]] | <a href= class= >"[[~[[*id]]]]#comments" "comments" Comments ([[!QuipCount? &thread=`blog-post-[[*id]]`]]) </a> </p>

<div class= >"entry" <p>[[*introtext]]</p> <hr /> [[*content]] </div>

<div class= >"postmeta" [[*tags:notempty=`<span class= >Tags: [[!tolinks? &items=`[[*tags]]` &key=`tag` &target=`1`]]</span>"tags" `]] <br class= />"clear" </div> <hr /> <div class= id= >[[!Quip?"post-comments" "comments" &thread=`blog-post-[[*id]]` &replyResourceId=`123` &closeAfter=`30` ]] <br /><br /> [[!QuipReply? &thread=`blog-post-[[*id]]` &notifyEmails=`[email protected]` &moderate=`1` &moderatorGroup=`Moderators` &closeAfter=`30` ]] </div></div>[[$pageFooter]]

So let's examine the Template, shall we? As we go, remember this - you can move any of these pieces around, change their parameters, andadjust their placing. This is solely a base structure - if you want your tags at the bottom, for instance, move them there! MODx doesn't restrict youfrom doing that.

Header and Footer

First off, you'll notice that I have two chunks: "pageHeader" and "pageFooter". These chunks contain my common HTML tags that I would put inthe footer and header across my site, so I can use them in different templates. Useful if I don't want to have to update any header/footer changesin each of my Templates - I can just do it in one chunk. After that, I put the pagetitle of my Resource, and make it a link that takes you to the samepage.

The Post Info

Next we get into the "info" of the post - basically the author and tags for the post. Let's look in detail:

<p class= >"post-info"Posted on [[*publishedon:strtotime:date=`%b %d, %Y`]] | Tags: [[*tags:notempty=`[[!tolinks? &items=`[[*tags]]` &key=`tag` &target=`1`]]`]] | <a href= class= >"[[~[[*id]]]]#comments" "comments" Comments ([[!QuipCount? &thread=`blog-post-[[*id]]`]])</a></p>

Page 276: ModX Revolution Docs 20101007

The first part takes the publishedon Resource field, and formats it into a nice, pretty date.

Secondly, we then display a Tag listing for this Blog Post. You can see how we reference a "tags" Template Variable - we haven't created this justyet, so dont worry - and then pass it as a property to the 'tolinks' snippet. The tolinks snippet comes with , and translates delimited tagstagListerinto links. This means our tags become clickable! We've specified a 'target' Resource of 1, or our home page. If your blog was in another pagebesides home, you'd change the ID number there.

And finally, we load a quick count of the number of comments, along with a clickable anchor tag link to load them. Note how our 'thread' propertyin the QuipCount snippet call (and later on in the Quip call) uses 'blog-post-[*id]'. This means that MODx will automatically create a new thread foreach new Blog Post we create. Neat!

The Post Content

Okay, back to our Template. We're in the content section now - note how we start with [[*introtext]]. This is a useful MODx Resource field - think ofit like a beginning excerpt for a blog post, that will show up on our main page when we're listing the latest blog posts.

Adding Comments to Posts

Okay, now we're in the comments part of BlogPostTemplate. As you can see here, we're using for our commenting system. You could feelQuipfree to use another system, such as Disqus, here if you choose. For this tutorial, we'll go with Quip. Our code is as follows:

<div class= id= >[[!Quip?"post-comments" "comments" &thread=`blog-post-[[*id]]` &replyResourceId=`19` &closeAfter=`30` ]] <br /><br /> [[!QuipReply? &thread=`blog-post-[[*id]]` &moderate=`1` &moderatorGroup=`Moderators` &closeAfter=`30` ]]</div>

Okay, cool. Note we have two Snippet calls here - one for displaying the comments for this thread ( ), and another for displaying the replyQuipform ( ).QuipReply

In our Quip snippet call, we've specified a thread ID in the manner we've described above, and then set some settings. Our comments are goingto be threaded (the default), so we need to specify a Resource ID where our Reply to Thread post is going to be (this is detailed in the Quip

. We recommend reading there for how to set it up.) with the 'replyResourceId' property.Documentation

Next, we want to specify - in both the Quip and Quip Reply calls - a 'closeAfter' property. This tells Quip to automatically close commenting onthese threads after 30 days of the thread creation (when we load it).

In our QuipReply call, we want to tell Quip to moderate all posts, and the moderators for our post can be found in the Moderators User Group(we'll explain how to set this up later in the tutorial).

There's a whole bunch of other Quip settings we could change, but we'll leave you to further customization, which you can find out how to do inthe .Quip docs

Setting up Tagging

Now that we've got our Template all setup, we need to setup the 'tags' Template Variable that we'll be using for our Tagging.

Go ahead and create a TV called 'tags', and give it a description of "Comma delimited tags for the current Resource." Next, make sure it hasaccess to the 'BlogPostTemplate' Template we created earlier.

Page 277: ModX Revolution Docs 20101007

That's it! Now you'll be able to add tags to any blog post we create, simply when editing your Resource by specifying a comma-separated list oftags.

Creating the Sections

If you want your blog to have 'Sections' (also called Categories), you'll first need to create those Resources.

For this tutorial's purpose, we'll create 2 sections: "Personal" and "Technology". Go ahead and create 2 Resources in the root of your site, andmake them 'containers'. You'll want to have their alias be 'personal' and 'technology', so your blog post URLs turn up nicely.

We'll say from here on out that our two Section Resources have IDs of 34 and 35, for reference.

Make sure you don't use the BlogPostTemplate on these, and use instead your own Base Template. These pages will end up being a way tobrowse all posts within a certain Section. In the content of these Resources, go ahead and put the following:

[[!getResourcesTag? &element=`getResources` &elementClass=`modSnippet` &tpl=`blogPost` &hideContainers=`1` &pageVarKey=`page` &parents=`[[*id]]` &includeTVs=`1` &includeContent=`1`]][[!+page.nav:notempty=`<div class= > "paging"<ul class= > "pageList" [[!+page.nav]] </ul> </div>`]]

Okay, let's explain this. getResourcesTag a wrapper snippet for and that automatically filters results by a 'tags' TV. SogetResources getPagebasically, we want to grab all published Resources within this section (and we can also filter by tag should we pass a '?tag=TagName' parameter

Page 278: ModX Revolution Docs 20101007

into the URL.

Below the getResourcesTag call, we put our pagination links, since by default getResourcesTag only shows 10 posts per page.

Setting up the blogPost Chunk

In that call, we also have a property called 'tpl' which we set to 'blogPost'. This is our Chunk that shows each result of our blog post listings. Itshould contain this:

<div class= >"post" <h2 class= ><a href= >[[+pagetitle]]</a></h2>"title" "[[~[[+id]]]]" <p class= >Posted by [[+createdby:userinfo=`fullname`]]"post-info" [[+tv.tags:notempty=` | <span class= >Tags: "tags"[[!tolinks? &items=`[[+tv.tags]]` &key=`tag` &target=`1`]]</span>`]]</p> <div class= >"entry" <p>[[+introtext: =`[[+content:ellipsis=`400`]]`]]</p>default </div> <p class= >"postmeta" <span class= >"links"<a href= class= >Read more</a>"[[~[[+id]]]]" "readmore"| <a href= class= >"[[~[[+id]]]]#comments" "comments" Comments ([[!QuipCount? &thread=`blog-post-[[+id]]`]]) </a>| <span class= >[[+publishedon:strtotime:date=`%b %d, %Y`]]</span>"date" </span> </p></div>

Cool - let's dive in. We start out by making a clickable link to the post with the pagetitle as the title. Then, we set our 'posted by' part and tag listing(similar to how we did it earlier in BlogPostTemplate).

Next, we show some of the excerpt of the content - which we store in the 'introtext' field on the content. We're also going to say that if introtext isempty, go ahead and instead just grab the first 400 characters of the content field, and add an ellipsis (...) to it if it's more than 400.

After that, we have a nice little 'read more' link which links to the post, and then our comments and publishedon date. That's it!

Setting up Your Blog Home

In our home page for our blog, which we've got in Resource ID 1 - our site start - we've got this:

Page 279: ModX Revolution Docs 20101007

[[!getResourcesTag? &elementClass=`modSnippet` &element=`getResources` &tpl=`blogPost` &parents=`34,35` &limit=`5` &includeContent=`1` &includeTVs=`1` &showHidden=`0` &hideContainers=`1` &cache=`0` &pageVarKey=`page`]][[!+page.nav:notempty=`<div class= > "paging"<ul class= > "pageList" [[!+page.nav]] </ul> </div>`]]

This allows us to show all posts from the two sections we've made, in Resources 34 and 35. It also allows us to filter by tag (since all our 'tolinks'and 'tagLister' calls have a target of 1 (this Resource's ID). In other words, by putting our getResourcesTag call here, we have automatic tagging!

You could easily make this another page than your site_start (or ID 1) - just make sure to change the 'target' properties in your tagLister andtolinks Snippet calls to reflect that.

Adding Posts

Okay, now we're ready to actually add blog posts, now that our structure is all setup.

Page Structure Within the Sections

Before we start, though, it's important to note that how you structure your posts within the section is totally up to you. You can add year and monthcontainer Resources to put these posts in, or just post them directly within the section. It's totally up to you.

If you choose to have date/year or sub-containers, make sure they have Hide from Menus checked, so that they wont show upin your getResources calls.

Remember, though, that whatever structure you build under the sections, that's not going to determine your navigation - will handle that.ArchivistWhat it will determine, however, is the URL of your blog posts. So have fun.

Adding a New Blog Post

Okay - go ahead and create a new Resource, and set it's Template to 'BlogPostTemplate'. Then you can start writing your post. You can specifyin the 'introtext' field the excerpt for the blog post, and then write the full body in the content field.

And finally, when you're done, make sure to specify the tags for your post in your newly created 'tags' TV!

Setting up Your Archives

Great - you have your first blog post! And, you've got it so you can browse it in Sections as well. Now, you're going to want to set up some way ofbrowsing old blog posts. This is where 'Archvist' comes into play.

Creating the Archives Resource

Go ahead and place a Resource in your root called 'Archives', and give it an alias of 'archives'. Then inside the content, place this:

Page 280: ModX Revolution Docs 20101007

[[!getPage? &element=`getArchives` &elementClass=`modSnippet` &tpl=`blogPost` &hideContainers=`1` &pageVarKey=`page` &parents=`34,35` &includeTVs=`1` &toPlaceholder=`archives` &limit=`10` &cache=`0`]]

<h3>[[+arc_month_name]] [[+arc_year]] Archives</h3>

[[+archives]]

[[!+page.nav:notempty=`<div class= > "paging"<ul class= > "pageList" [[!+page.nav]] </ul> </div>`]]

Look familiar? It's very similar to getResourcesTag, described above in our Section page. This time, getPage is wrapping the snippet,getArchivesand saying that we want to grab posts in Resources 34 and 35 (our Section pages). We'll set the result to a placeholder called 'archives' which wereference later.

Then, below that, we add a few placeholders that show the current browsing month and year. And finally, we have our pagination. Cool! We'redone with that. Our Resource, for reference purposes, we'll say has an ID of .30

Setting up the Archivist Widget

Okay, so now you've got a Resource to browse archives in, but you need some way of generating the months that lists posts. That's actuallypretty simple - somewhere on your site (say, in your footer, put this nice little bit:

<h3>Archives</h3><ul>[[!Archivist? &target=`30` &parents=`34,35`]]</ul>

So what the Snippet does is generate a month-by-month list of posts (you can add all kinds of other options, but see Archivist it's documentationfor that). We are saying we want its links to go to our Archives Resource (30), and to only grab posts in the Resources 34 and 35 (our SectionResources).

That's it! Archivist will actually automatically handle the rest - including all your URL generation for archives - archives/2010/05/ will show all theposts within May 2010, where archives/2009/ will show all posts in 2009. Pretty sweet, huh?

Advanced Options

Adding a Moderator Group

So earlier, in our QuipReply call, we specified a moderatorGroup of 'Moderators'. Let's go ahead and create that User Group now.

Go to Security -> Access Controls, and create a new User Group called 'Moderators'. Add any users you want in the group (including yourself!)and give them whatever role you want.

Then, go to the Context Access tab. Add an ACL (a row, basically) that gives this user group access in the 'mgr' context, with a minimum role ofMember (9999), and the Access Policy of 'QuipModeratorPolicy'.

What this does is allow anyone in the 'Moderators' usergroup to moderate posts in your threads, and also notifies them via email when new postsare made. They can then either login to the manager to moderate comments, or click on links directly in the emails to approve or reject thecomments. Your ACL should look something like this:

Page 281: ModX Revolution Docs 20101007

Save your User Group, and that's it! You might have to flush sessions (Security -> Flush Sessions) and re-login to reload your permissions, butQuip will handle the rest.

Adding a "Latest Posts" widget

You're probably going to want a "Latest Posts" somewhere on the site, and no fear - adding it is quite easy.

First off, you'll want to place this call wherever you want the list to appear:

[[!getResources? &parents=`34,35` &hideContainers=`1` &tpl=`latestPostsTpl` &limit=`5` &sortby=`publishedon`]]

So we're telling to display a top 5 list of Resources in your Section Resources (34,35), and sort by their publishedon date.getResources

Then, create the `latestPostsTpl` chunk, which you've specified with the 'tpl' call in the getResources snippet call. Put this as the chunk's content:

<li> <a href= >[[+pagetitle]]</a>"[[~[[+id]]]]" [[+publishedon:notempty=`<br /> - [[+publishedon:strtotime:date=`%b %d, %Y`]]`]]</li>

And boom! Latest blog posts displaying on your site:

Adding a "Latest Comments" widget

What about a widget that shows a few of the latest comments across your posts? Simple - Quip packages a nice little snippet called that can handle this easily.QuipLatestComments

Place the call wherever you want the comment list to show:

Page 282: ModX Revolution Docs 20101007

[[!QuipLatestComments? &tpl=`latestCommentTpl`]]

Now create a chunk called 'latestCommentTpl':

<li class= >"[[+cls]][[+alt]]" <a href= >[[+body:ellipsis=`[[+bodyLimit]]`]]</a>"[[+url]]" <br /><span class= >by [[+name]]</span>"author" <br /><span class= >[[+createdon:ago]]</span>"ago"</li>

Before we proceed, there's a few things to note - QuipLatestComments will automatically truncate the comment and add an ellipsis past the&bodyLimit property passed into it, which defaults to 30 characters. Secondly, note the 'ago' we used here. This filter is built intoOutput FilterMODx Revolution, and translates a timestamp into a nice, pretty 'two hours, 34 minutes' (or two other time metrics, such as min/sec, year/mo,mo/week) format.

Note also that it will default to showing the 5 latest. The result:

You can see the for more configuration options.documentation for the snippet

Adding a "Most Used Tags" widget

This part is ridiculously easy; does this for you. Just place this wherever you want:tagLister

[[!tagLister? &tv=`tags` &target=`1`]]

And tagLister will check the TV 'tags', and create links that go to the target (here, Resource ID 1) with the top 10 tags being used. There's a tonmore , but we'll leave you with this.configuration options

Conclusion

So we've got a full blog setup! It should look something like this in our tree now:

Page 283: ModX Revolution Docs 20101007

Again, there's far more customization and things you could add to your blog. This tutorial is meant as a starting point, but feel free to customizeand add things to your liking - the great part about MODx is that you can very easily customize, tweak and scale any solution: including a blog!

Remember, this tutorial was based off of , if you'd like to see a full-scale demo of it in action.splittingred.com

PHP Coding in MODx Revolution, Pt. I

The Simple HowThe ModelSee Also

So, a lot of people have been asking about the new codebase. Is it coder-friendly? Will it be a big deviation from 0.9.6/Evolution? Does it supportOOP projects? Is it faster? Will it be easy to learn?

In these tutorials, we plan to answer those questions with a resounding, "yes."

The codebase in Revolution has switched to , an object relational bridge modeling tool built by Jason Coward. In layman's terms, thisxPDOmeans that all the database tables are now represented by PHP objects (which you'd expect with any ORM). Chunks are represented by'modChunk' objects, snippets by 'modSnippet' objects and so on.

The Simple How

So, how does one actually get an object in the new modx? Well, used to, you had to do and remember a myriad of different functions:

// The old way of doing things in MODx 1.x and earlier$doc = $modx->getDocument(23);$doc = $modx->getDocument(45,'pagetitle,introtext');$chunk = $modx->getChunk('chunkName');

// or even more convoluted$res = $modx->db->select('id,username',$table_prefix.'.modx_manager_users');$users = array();

($modx->db->getRecordCount($res))if{ ($row = $modx->db->getRow($res)) {while array_push($users,$row); }}

$users;return

Not anymore. Things are much simpler, and there's really only a few functions you'll need. Lets look at some examples:

Page 284: ModX Revolution Docs 20101007

// getting a chunk with ID 43$chunk = $modx->getObject('modChunk',43);

// getting a chunk with name 'TestChunk'$chunk = $modx->getObject('modChunk',array( 'name' => 'TestChunk'));

// getting a collection of chunk objects, then outputting their names$chunks = $modx->getCollection('modChunk');foreach ($chunks as $chunk) { echo $chunk->get('name'). ;"<br />\n"}

// getting a resource (i.e. a page) that is published, with a alias of 'test'$document = $modx->getObject('modResource',array( 'published' => 1, 'alias' => 'test',));

The Model

So, you're probably asking, Where is the list of table names to object names map? It can be found in"core/model/schema/modx.mysql.schema.xml". (You'll note the 'mysql' - yes, this means that MODx will in the near future support otherdatabases) From there you can view an XML representation of all the MODx DB tables.

For example, modChunk:

<object class= table= = >"modChunk" "site_htmlsnippets" extends "modElement" <field key= dbtype= precision= phptype= = ="name" "varchar" "50" "string" null " "false default "" index="unique" /> <field key= dbtype= precision= phptype= = ="description" "varchar" "255" "string" null " "false default

/>"Chunk" <field key= dbtype= precision= phptype= = = />"editor_type" " "int "11" "integer" null " "false default "0" <field key= dbtype= precision= phptype= = = />"category" " "int "11" "integer" null " "false default "0" <field key= dbtype= precision= phptype= = ="cache_type" "tinyint" "1" "integer" null " "false default "0"/> <field key= dbtype= phptype= />"snippet" "mediumtext" "string" <field key= dbtype= precision= attributes= phptype= ="locked" "tinyint" "1" "unsigned" " "boolean null "

= />"false default "0" <aggregate alias= class= key= local= foreign="Category" "modCategory" "id" "category" "id"cardinality= owner= />"one" "foreign"</object>

You can also define your own schemas for your own components and add them as packages - more on that in a future article. Lets go into theschema:

<object class= table= = >"modChunk" "site_htmlsnippets" extends "modElement"

The property tells you what the name of the class will be. The property shows the actual MySQL table, and shows what objectclass table extendsit extends. modElement is a base class for all Elements in MODx - snippets, modules, chunks, templates, etc.

<field key= dbtype= precision= phptype= = ="name" "varchar" "50" "string" null " "false default "" index="unique" />

This tag represents a column in the database. Most of these attributes are pretty straightforward.

<aggregate alias= class= key= local= foreign= cardinality="modCategory" "modCategory" "id" "category" "id" owner= />"one" "foreign"

Okay, this is where we get into DB relationships. An relationship is a relationship where, in laymans terms, if you were to delete thisAggregatechunk, it wouldn't delete the Category that it's related to. If it were a relationship, it would. There is "dependence" in the CompositeComposite

Page 285: ModX Revolution Docs 20101007

relationship that is related to the other object. For an example, let's get all the modContextSettings for a modContext:

$context = $modx->getObject('modContext','web');$settings = $context->getMany('ContextSettings');foreach ($settings as $setting) { echo 'Setting name: '.$setting->get('key').' <br />'; echo 'Setting value: '.$setting->get('value').' <br />';}

Pretty easy, huh? We'll get into creating and removing objects, as well as more complex queries, such as inner joins, limits, sorting and others, inthe .next article

See Also

xPDO: Defining a SchemaxPDO: Related Objects

PHP Coding in MODx Revolution, Pt. II

Creating ObjectsRemoving an ObjectMore Complex QueriesSee Also

In this article, we'll talk about creating and removing objects (and their respective rows in the database), as well as more complex queries.

Creating Objects

Creating objects is pretty simple. It's important to note, however, that a row is never actually added to the database until the object's save()command is run. So, on to the code:

// let's create a Template$template = $modx->newObject('modTemplate');

// now, lets save some data into the fields$template->set('templatename','TestTemplate');$template->set('description','A test template.');

// we could have also done it like :this$data = array( 'templatename' => 'TestTemplate', 'description' => 'A test template.',);$template->fromArray($data);

// okay, now we're ready. let's save. ($template->save() === ) {if false

die('An error occurred saving!');while}

It's that simple.

Removing an Object

Okay, so assuming we have the same previous object and now want to remove it (you could also grab another object, of course), the code issimply:

$template->remove();

Yes. That's it. Done. It will also remove any composite relationships - with modTemplates, these are the modTemplateVarTemplate objects, whichmap Templates to TVs. Those will cascade and be removed.

Page 286: ModX Revolution Docs 20101007

More Complex Queries

Okay, so obviously you are going to need to do some more complex queries than we've dealt with. That's where the xPDOQuery object comes in.This allows you to build abstract query objects that emulate more advanced SQL commands. So, lets try to grab the third 10 resources (so 21-30),ordered by menuindex, that are either 1) published and searchable, or 2) created by the user with username 'george123'.

$c = $modx->newQuery('modResource');$c->leftJoin('modUser','PublishedBy');$c->where(array( 'modResource.published' => 1, 'modResource.searchable' => 1,));$c->orCondition(array( 'PublishedBy.username' => 'george123',), ,1);null$c->sortby('menuindex','ASC');$c->limit(10,20);

$resources = $modx->getCollection('modResource',$c);

A couple of things to note. One, note that innerJoin first passes the class name, then the alias. And in orCondition, the 3rd parameter is the groupnumber, which effectively groups the conditions into proper parenthesis (the first 2 in the first parenthetical group, the 3rd in another).

xPDOQuery supports the the methods: join, rightJoin, leftJoin, innerJoin, andCondition, orCondition, sortby, groupby, limit, bindGraph,bindGraphNode, and select.

Obviously, you can go pretty wild here with complex queries. The nice thing about xPDO in MODx is that there's really a ton of different ways todo most things - you could also have used $modx->getCollectionGraph for this as well.

In the , we'll talk about how this is used in the context of MODx processors with JSON.next article

See Also

xPDO: Creating ObjectsxPDOObject::removexPDOQuery

PHP Coding in MODx Revolution, Pt. III

In MODx, form processing is handled by 'Processors', which are isolated files located in the MODx core directory. They are accessed through'Connectors', which handle AJAX requests from the User Interface (UI), which require a REQUEST variable named 'action' that specifies whichprocessor to send to. Processors are sent the sanitized REQUEST data, and then when finished respond with a JSON message back to thebrowser.

This allows for quick, easy requests that reduce the load on the server and the browser. You can also do multiple, asynchronous requests toprocessors in this method.

We'll look in-depth at the processor for creating a Chunk, and show you how MODx processors work.

First off, let's assume that we're sending the following data into the POST array to the connector, which has the REQUEST "action" variable set to'create', loading the proper create.php variable. In the JS, the connector is MODx.config.connectors_url+'element/chunk.php, which resolves to (inour default setup):

/modx/connectors/element/chunk.php

From there the connector will verify the request, and then send it to the proper processor, at:

/modx/core/model/modx/processors/element/chunk/create.php

And now on to the processor:

Page 287: ModX Revolution Docs 20101007

<?php/** * @ modxpackage * @subpackage processors.element.chunk */$modx->lexicon->load('chunk');

First off, we include the root index.php file for the processors, which does some slight variable checking and includes licensing. Then, we load theproper lexicon foci. In MODx Revolution, i18n language files are separated into smaller files by their 'foci', which is a term we've coined for 'focusarea'. Here, we want all language strings with foci 'chunk'. This saves processing power by only loading relevant i18n strings.

if (!$modx->hasPermission('new_chunk')) $modx->error->failure($modx->lexicon('permission_denied'));

This checks to make sure the user has the correct permissions to run this processor. If not, then it sends a failure response back to the browservia $modx->error->failure(). The response is a string message translated via the lexicon.

// valuesdefaultif ($_POST['name'] == '') $_POST['name'] = $modx->lexicon('chunk_untitled');

// get rid of invalid chars$_POST['name'] = str_replace('>','',$_POST['name']);$_POST['name'] = str_replace('<','',$_POST['name']);

// the name already exists chunk, send back an errorif for this$name_exists = $modx->getObject('modChunk',array('name' => $_POST['name']));

($name_exists != ) $modx->error->failure($modx->lexicon('chunk_err_exists_name'));if null return

Note now how we're sanitizing variables, and checking to make sure there already isn't a Chunk with this name.

// category$category = $modx->getObject('modCategory',array('id' => $_POST['category']));

($category == ) {if null $category = $modx->newObject('modCategory'); (empty($_POST['category'])) {if $category->set('id',0); } {else $category->set('category',$_POST['category']); $category->save(); }}

Okay, here, we allow dynamic Category creation. If the category specified exists, it will later assign it to that category. If not, then it creates thecategory in the database and prepares it for later association to the Chunk.

// invoke OnBeforeChunkFormSave event$modx->invokeEvent('OnBeforeChunkFormSave',array( 'mode' => modSystemEvent::MODE_NEW, 'id' => $_POST['id'],));

Events are pretty much the same invoke-wise in Revolution as they were in 096 - however they are more optimized in their loading.

$chunk = $modx->newObject('modChunk', $_POST);$chunk->set('locked',isset($_POST['locked']));$chunk->set('snippet',$_POST['chunk']);$chunk->set('category',$category->get('id'));

($chunk->save() === ) {if false $modx->error->failure($modx->lexicon('chunk_err_save'));return}

Page 288: ModX Revolution Docs 20101007

Important: note the 2nd parameter of the newObject() method. This is basically the same as $obj->fromArray() - it allows you to specify an array ofkey-value pairs to assign to the new object.

// invoke OnChunkFormSave event$modx->invokeEvent('OnChunkFormSave',array( 'mode' => modSystemEvent::MODE_NEW, 'id' => $chunk->get('id'),));

Again, more event invoking.

// log manager action$modx->logManagerAction('chunk_create','modChunk',$chunk->get('id'));

Now, how manager actions work in Revolution is a little different. This stores a lexicon string key ('chunk_create'), the class key of the objectbeing modified, and the actual ID of the object. This allows for more detailed manager action reporting.

$cacheManager= $modx->getCacheManager();$cacheManager->clearCache();

Let's simply and easily clear the cache. Pretty easy, huh?

return $modx->error->success('',$chunk->get(array('id', 'name', 'description', 'locked','category')));

Now, send a success response back to the browser. The parameters of $modx->error->success() are as follows:

1: $message - A string message to send back. Used to report details about a success (or failure).2: $object - An xPDOObject or array of data fields to convert into JSON and send back to the browser.

So basically, here, we're sending back the Chunk information - minus the content, which could be big and unnecessary and complicated to send.This will allow the UI to handle the creation properly.

Next, we'll talk about how to create your own schemas and add them dynamically into the MODx framework, without having to modify the core.

Loading Pages in the Front-End via AJAX and jQuery Tabs

The ProblemCreating the ResourcesDoing the Front-End LoadingWait, I want the Page Titles as the tab headers!

Using getResourcesUsing WayfinderUsing a getField Snippet

Conclusion

The Problem

We want in our site to use to load our Resources via AJAX. How do we do that in MODx? This tutorial will show you just how easy itjQuery's tabsis to accomplish this in MODx Revolution.

Creating the Resources

In the Resources you want to load via the tabs, you'll need to just create all your Resources with the Template being (or a minimal templateblankwith only the things you want inside the tabs). This will make sure that we're not loading anything besides the wanted material - you wouldn't wantto load your whole page header and footer into each tab!

Doing the Front-End Loading

Now we'll use jQuery's fun tabs() command to create the front-end loading system. The code would look something like this (pulled from jqueryUI's docs):

Page 289: ModX Revolution Docs 20101007

<script type= >"text/javascript"$(function() { $( ).tabs(); });"#tabs"</script>

<div id= >"tabs" <ul> <li><a href= >Resource with ID 92</a></li>"[[~92]]" <li><a href= >Resource with ID 546</a></li>"[[~546]]" <li><a href= >Resource with ID 123</a></li>"[[~123]]" </ul></div>

Great! So this loads the pages via Ajax.

Wait, I want the Page Titles as the tab headers!

There are a few ways you can do this; one, you can use , , or use a getField snippet.getResources Wayfinder

Using getResources

For getResources, make sure you use the 'tpl' property, which you can create as a Chunk named 'myRowTpl' (or whatever you want), looks likethis:

<li id= ><a href= title= >[[+pagetitle]]</a></li>"[[+id]" "[[~[[+id]]]]" "[[+longtitle]]"

and in our tabs page:

<script type= >"text/javascript"$(function() { $( ).tabs(); });"#tabs"</script>

<div id= >"tabs" <ul>[[getResources? &parents=`123` &depth=`1` &tpl=`myRowTpl` &includeContent=`1` &includeTVs=`1`]] </ul></div>

Using Wayfinder

For Wayfinder, make sure your rowTpl template, which you can create as a Chunk named 'myRowTpl' (or whatever you want), looks like this:

<li[[+wf.id]][[+wf.classes]]><a href= title= >[[+wf.linktext]]</a></li>"[[+wf.link]]" "[[+wf.title]]"

and in our tabs page:

<script type= >"text/javascript"$(function() { $( ).tabs(); });"#tabs"</script>

<div id= >"tabs" <ul>[[Wayfinder? &startId=`123` &level=`1` &rowTpl=`myRowTpl`]] </ul></div>

Using a getField Snippet

Or, you can use a Snippet such as this one to grab the pagetitle:

Page 290: ModX Revolution Docs 20101007

<?php/** * Grabs a field a specified Resourcefor *//* setup some properties */default$id = $modx->getOption('id',$scriptProperties, );false$field = $modx->getOption('field',$scriptProperties,'pagetitle');

($id) { /* grab the resource object */if $resource = $modx->getObject('modResource',$id); ($resource == ) '';if null return} { /* no id specified, use current doc */else if $resource =& $modx->resource;}

/* the field value */return $resource->get($field);return

?>

Call this Snippet getField like so in our tabs page:

<script type= >"text/javascript"$(function() { $( ).tabs(); });"#tabs"</script>

<div id= >"tabs" <ul> <li><a href= >[[getField? &id=`92` &field=`pagetitle`]]</a></li>"[[~92]]" <li><a href= >[[getField? &id=`546` &field=`pagetitle`]]</a></li>"[[~546]]" <li><a href= >[[getField? &id=`123` &field=`pagetitle`]]</a></li>"[[~123]]" </ul></div>

However, the getField solution is not as fast or elegant as the Wayfinder solution, since it has to make a query every tab.

Conclusion

Note that all you're doing is pointing the href tags to the actual document IDs, just like a normal link. The trick is you're making your Template forthe Documents be blank (or minimal) so that it only loads the parsed content itself.

This will successfully load your MODx Resources into jQuery tabs.

Managing Resources and Elements via SVN

The Problem

When working in collaboration, teams of developers and designers often collaborate via Subversion (SVN) to make development easier betweenmultiple people. MODx, however, stores its data in the database. This has many benefits generally, but DB-stored code cannot beversion-controlled via SVN.

However, the solution in MODx Revolution is quite simple.

The Solution

For Resources, it's simple. Just use , and point the content to a file in your SVN checkout.Static Resources

For Elements, all you need is a simple "include" . The code:snippet

if (!file_exists($file)) '';return$o = include $file;

$o;return

Page 291: ModX Revolution Docs 20101007

You can then call it like so in your Static Resources:

[[include? &file=`/path/to/my/svn/checkout/snippet.php`]]

And you're done. You can also use tags within the 'file' parameter, such as this:

[[include? &file=`[[++assets_path]]/js/myscript.js`]]

Conclusion

This allows you to easily manage content via SVN. It can be achieved with and as well; just plop the include snippet wherever youTemplates TVsneed filesystem-based files.

xPDO XML Schema File vs. Table Structure Examples

Before you StartA simple table: session

The xPDO XML:The MySQL CREATE TABLE statement:Things to Note

system_settingsXMLMySQL

user_group_rolesXML

This is a work in progress

The XML files used by xPDO to define database tables are meant to be created in a certain format. One of the easiest ways to get familiar withthis format is to look at existing XML schemas and compare them to the actual database tables which they represent.

Although xPDO is built to be database agnostic, and in the future it will support other databases, for the point of familiar comparison, MySQL isused in these comparisons.

Before you Start

Note that the schema file contains definitions of many tables, and we're using it as a referencecore/model/schema/modx.mysql.schema.xmlfor all the tables mentioned on this page.

In this schema file, each table is defined as an , and all objects are wrapped in the following model tag:object

<model = baseClass= platform= defaultEngine= phpdoc- =package "modx" "xPDOObject" "mysql" "MyISAM" package phpdoc-subpackage="">"modx"

<!-- all table objects are defined in here --></model>

Also note that each object defines a attribute, but this attribute does NOT include any table prefix you may have defined for your site.table

Also note that xPDO defines foreign relationships in both directions; if a column is a foreign key, the XML definition will reflect that in the definitionof that object, but if an id from a table is used as a foreign key in another table, this dependency will noted in tables; this isn't the case withbothevery ORM out there.

A simple table: session

The table is a good table for a simple example because it contains no foreign keys; in other words, it has no composite or aggregatesessionrelations to worry about.

The xPDO XML:

Page 292: ModX Revolution Docs 20101007

1.

2. 3.

<object class= table= = >"modSession" "session" extends "xPDOObject" <field key= dbtype= precision= phptype= = index= "id" "varchar" "40" "string" null " "false "pk"

="" />default <field key= dbtype= precision= phptype= = attributes="access" " "int "20" "timestamp" null " "true

/>"unsigned" <field key= dbtype= phptype= />"data" "text" "string" </object>

The MySQL CREATE TABLE statement:

CREATE TABLE `modx_session` ( `id` varchar(40) NOT NULL '',default `access` (20) unsigned NULL,int default `data` text, PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1

Things to Note

The XML precision matches up exactly to MySQL precision defined after each datatype: it reflects how many characters are visible in acolumn. E.g. int(2) could store any 2 digit number.The in the XML corresponds to the definition in MySQL.null="false" NOT NULLattributes="unsigned" in the XML corresponds directly to the definition in MySQLUNSIGNED

system_settings

This is a fairly simple table too, but it includes 2 foreign keys.

XML

<object class= table= = >"modSystemSetting" "system_settings" extends "xPDOObject" <field key= dbtype= precision= phptype= = ="key" "varchar" "50" "string" null " "false default ""

pk" />index=" <field key= dbtype= phptype= = ="" />"value" "text" "string" null " "false default <field key= dbtype= precision= phptype= = ="xtype" "varchar" "75" "string" null " "false default

/>"textfield" <field key= dbtype= precision= phptype= = ="namespace" "varchar" "40" "string" null " "false default

/>"core" <field key= dbtype= precision= phptype= = ="" />"area" "varchar" "255" "string" null " "false default <field key= dbtype= phptype= = attributes="editedon" "timestamp" "timestamp" null " "false "ON

/>UPDATE CURRENT_TIMESTAMP" <aggregate alias= class= local= foreign="ContextSetting" "modContextSetting" "key" "key"cardinality= owner= />"one" "local" <aggregate alias= class= local= foreign="Namespace" "modNamespace" "namespace" "name"cardinality= owner= />"one" "foreign" </object>

MySQL

CREATE TABLE `modx_system_settings` ( `key` varchar(50) NOT NULL '',default `value` text NOT NULL, `xtype` varchar(75) NOT NULL 'textfield',default `namespace` varchar(40) NOT NULL 'core',default `area` varchar(255) NOT NULL '',default `editedon` timestamp NOT NULL '0000-00-00 00:00:00' on update CURRENT_TIMESTAMP,default PRIMARY KEY (`key`)) ENGINE=MyISAM DEFAULT CHARSET=latin1

user_group_roles

Page 293: ModX Revolution Docs 20101007

This table includes a single foreign key... actually, its id is as a foreign key by another table. This is a good reminder that in xPDO, theusedforeign key relationships are defined in both directions.

XML

CREATE TABLE `modx_user_group_roles` ( `id` (10) unsigned NOT NULL auto_increment,int `name` varchar(255) NOT NULL, `description` mediumtext, `authority` (10) unsigned NOT NULL '9999',int default PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`), KEY `authority` (`authority`)) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1

Adding Custom Fields to Manager Forms

Adding a Custom Field

Adding custom fields to manager forms - such as the Create Chunk, Update Resource, etc - in MODx Revolution is fairly straightforward. You justuse the On*FormRender Plugin events.

We want to add a field called 'Home' that puts an address field into the manager interface, and then stores it into the longtitle value (this is not the

best place to store it, but let's go along with it for tutorial purposes ).

To do so, we'd create a and associate it to the and events. Our code would look like this:Plugin OnDocFormRender OnDocFormSave

Page 294: ModX Revolution Docs 20101007

<?php/** * Register a form field to forms */

($modx->event->name) {switch 'OnDocFormPrerender':case /* you want to add custom scripts, css, etc, register them here */if ;break 'OnDocFormRender':case $v = ''; (isset($scriptProperties['resource'])) {if /* on the update screen, so set the value */ $v = $scriptProperties['resource']->get('longtitle'); } {else /* on the create screen, so set the */default $profile = $modx->user->getOne('Profile'); $v = $profile->get('address'); } /* now the HTML */do $fields = '<div class= >"x-form-item x-tab-item" <label class= style= >Home</label>"x-form-item-label" "width:150px;" <div class= >"x-form-element" <input type= name= value= class= />"text" "home" "'.$v.'" "x-form-text x-form-field" </div></div>'; $modx->event->output($fields);

;break 'OnDocFormSave':case /* processing logic here. */do $resource =& $scriptProperties['resource']; $resource->set('longtitle',$_POST['home']); $resource->save(); ;break}

;return

Note the CSS classes and styling in the form HTML. Those are unnecessary; but will make the form "match" the styling of the rest of the fields.

MODx Community Information

This section is currently under construction.

Getting a MODx Account

This section is under construction.

Simply signup here: http://modxcms.com/community/register/

Filing Bug Reports

Page 295: ModX Revolution Docs 20101007

This section is under construction.

Bug reports can be filed in JIRA at http://bugs.modx.com

Becoming a Core Contributor

The ResourcesBut how do I get a sign-on?I've submitted my CLA, now what? I want to commit!My patch was rejected! What?!See Also

So, you've seen MODx Revolution, and are itching to get in on the development. But, to your dismay, you're confused on how to start thatprocess. This article will help you get to your level of commitment in development - be it an active coder or simply a tester who submits patches.

The Resources

MODx has moved to an -driven development environment, comprised of Jira, Fisheye/Crucible, and Confluence. All resources use anAtlassianSSO-driven authentication interface, so no need for multiple logins. For now, you only need 2 - one for the Atlassian apps, and the other for theMODx forums. (And we're working on getting the forums to SSO!)

JIRA - MODx's new bugtracker. It combines detailed tracking with Fisheye SVN integration. All new bugs will be submitted via JIRA.Fisheye/Crucible - This is a detailed SVN reporting and reviewing interface that allows for peer reviews of committed code.Confluence - The new wiki for MODx.

But how do I get a sign-on?

Simple. Just for a modxcms.com SSO (single-sign on) login and you're there! You'll instantly have access to and , and beregister Jira Fisheyeable to submit bugs and review recent commits. MODx team administrators will then grant you access according to team needs, and you'll be ableto quickly start submitting Jira patches and more!

If you want to contribute to , the official documentation wiki, work on bugs, or actually commit some code, the first step is to fill out andConfluencesend in a right after creating a JIRA account. A CLA protects your contributions, but also gives MODxContributor License Agreement (CLA)and it's user base clear permission to use those contributions any way that is compliant with the MODx license (GPL), and it's based on—morelike copied directly from—the same one used by Apache and the Dojo Foundation.

I've submitted my CLA, now what? I want to commit!

We applaud your eagerness. Honestly, no joke, we do. MODx needs eager developers. However, there is a level of relationship that we like todevelop with people before they become core devs. You've got access to Jira now, and probably have noticed some bugs or have some featurerequests. So use it! Submit those bugs and ideas to Jira, and include in Jira patches for them. Please, no political jokes hidden in the comments.Really.

You can submit a patch by using (SVN). For the current time, MODx is on SVN for development, although this will soon be moving to Subversion. Simply and start working on your patch. Then, you can use SVN's "Create Patch" to create the patch and submitGit checkout MODx Revolution

it to JIRA.

After an unspecified, arbitrary amount of time (usually decided by a game of Risk in which one of us usually ends up regretting taking overAustralia after they skipped Africa, and ends the game by throwing the board at the others while yelling Orwellian quotations) the core dev teamwill then approach you with SVN commit privileges. From there you'll be able to submit commits just like the rest of the team, and have thosecommits reviewed by fellow team members in Crucible. Don't worry if your first Crucible review is scathing - we usually do that to the newbies. Atleast we don't do the glue-on-the-keyboard initiation anymore (darn lawyers).

My patch was rejected! What?!

Every so once in a while, a patch submitted doesn't make it into the core. It's not because we don't like you. In all honesty, Jason loves darts, andbefore each patch approval he staples them to the wall and we choose the one he hits while blindfolded. (Okay, so that's not true. He's notblindfolded.)

Sometimes a patch you submit wont make it in. That may be for a myriad of reasons:

The patch wasn't a part of the Core Design PhilosophyWe decided to move the feature request to a component rather than the coreSomeone else provided a more elegant patch

Page 296: ModX Revolution Docs 20101007

The patch caused too many other issues to ariseThe patch was submitted in , which although we had a hoot reading, was pretty useless in the endlolcode

So don't take offense. We really appreciate contributions to MODx, and we seriously consider everything that this wonderfulany and allcommunity gives to it. MODx has thrived because of this community. However, some things just wont match with the MODx vision and designphilosophy; so be patient with us, and know we really like people who submit patches. A ton. Did we mention we really like patch submitters?

See Also

Development Environments

Recommended Development Tools and Environments for MODx Revolution

In developing MODx Revolution, the MODx Team has found the following environments invaluable:

Netbeans

Netbeans 6.8Netbeans Subversion and JIRA plugins

Eclipse

Eclipse 3.2.+ (recommend latest 3.5.1)Web Standard Tools Project (WST) 2.0.1 ( )http://download.eclipse.org/webtools/updates/Subclipse 1.6.5 ( )http://subclipse.tigris.org/update_1.6.xPHPEclipse 1.2.3 ( )http://update.phpeclipse.net/update/nightlySpket IDE 1.6.18 ( )http://spket.com/update/

Installation

Simply install the latest Eclipse ClassicStart up eclipse / select a workspaceUse the Install Software option under the help menuRight click and copy each of the links above (doing them in order doesn't hurt)Click the "Add" buttonName the "repo" WST, Subclipse, PHPEclipse, or Spket, as it relates to the URLPaste the URLClick OKRepeat for each of the links above as necessaryIndividual notes:

WST - select the latest Web Tools Platform (takes quite a while)Subclipse - simply install the Subclipse optionPHPEclipse - install everything offeredSpket - Install everything offered

Other IDEs

For Mac:

TextMate - IDECoda - IDEVersions - SVN clientsvnX - SVN client

For PC:

UltraEdit - IDEE - IDETortoiseSVN - SVN clientKate - IDE for Linux / KDE

Development Server Environments

We also MacPorts, XAMPP and MAMP, and the following tools/libraries in the development of MODx Revolution:

Page 297: ModX Revolution Docs 20101007

PHPUnit - this drives the PHP 5.1+ unit testing framework for xPDO, and we'll be adding a test harness to MODx soonSimpleTest - this drives the PHP 4/5.0.x unit testing framework for xPDO, and we'll be adding a test harness to MODx soonPHPDocumentor - all of the classes in MODx Revolution are documented in PHPDoc format, and we'll be developing tutorials and otherextended documentation for inclusion in the PHPDocs in DocBook XML formatPhing - will be used to allow automation of nightly builds, various distribution builds, unit testing, and many other development tasks

MODx PHP Coding Standards

GeneralParenthesisClassesVariablesFunction Arguments and Class VariablesArraysConstantsFile StructurePrefixing

General

Beginning brackets do NOT linebreak. They start one space after the end parenthesis, as according to traditional Unix policy.Do not do any real logic in object constructors. Create class methods to do so.null, true and false should always be lowercase.Avoid embedded assignments (ex: $d = ($a = $b + $c) is bad).Never use extract().Avoid using global variables if at all possible.Document EVERYTHING.

Parenthesis

Do not put parenthesis next to keywords. Put a space between.Do put parenthesis next to function names.Do not use parenthesis in return statements when it's not necessary. Example:

if ($test) {}

($test == $other) {while}array_push($one,$two);

$test;return

Do use parenthesis when using include, require, include_once, and require_once.not

Classes

All ''core'' classnames, unless stated otherwise for special conditions, will be prefixed with the "mod" prefix: ie, modChunk, modTemplate,etc.All method names will be camelCase and will start with a lowercase letter.All private methods and variables must be prefixed with the underscore _ character.

class modFactor { $publicVar;public $_privateVar;private function _privateFunc() { }private function publicFunc() { }public}

Variables

Note these are not function arguments.

Use all lowercase letters.Separate words with the underscore.

Function Arguments and Class Variables

Page 298: ModX Revolution Docs 20101007

The first letter is lowercase, rest are camelCase. Example:

class modFactor { function testFunc($testVar, array &$anotherTest = array()) {public $ ->_privateVar = $testVar;this $local_variable =& $anotherTest; }}

Arrays

Array index names use the underscore _, not the dash as their separator. This prevents errors with magic_quotes.Array index names are always lowercase. Spaces are represented by an underscore.Array index names are always encapsulated with single quotes.Example:

$_lang['chunk_create_text'] = 'Test';

Constants

Constants must be in all UPPERCASE letters.Use only if absolutely necessary.

File Structure

Always name PHP class files in name.class.php format.

Prefixing

Lexicon strings for Components need to be prefixed:

$_lang['mycomponent.welcome_message'] = 'Welcome!';

Always prefix class names; eg: 'finBank', 'finTransaction', etc.Always prefix names; eg: 'finStatement', 'finDeposit'Chunk

Using GitHub

This section is under construction.

See .Git Installation