1. Getting Started
      1. Video Quick-Start Series
      2. Server Requirements
        1. MySQL 5.0.51 Issues
      3. Installation
        1. Basic Installation
          1. MODx Revolution on Debian
          2. Problems with WAMPServer 2.0i
          3. Lighttpd Guide
          4. Installation on a server running ModSecurity
          5. MODX and Suhosin
          6. Nginx Server Config
        2. Successful Installation, Now What Do I Do?
        3. Successful Installation, Now What Do I Do?
        4. Advanced Installation
        5. Git Installation
        6. Command Line Installation
          1. The Setup Config Xml File
        7. Troubleshooting Installation
        8. Using MODx Revolution from SVN
      4. An Overview of MODX
        1. Glossary of Revolution Terms
          1. Explanation of Directory Structure
        2. Roadmap
        3. MODX Revolution Framework Structure Ideology
        4. What's New in 2.3
    2. FAQs & Troubleshooting
      1. CMP Development FAQs & Troubleshooting
    3. Making Sites with MODx
      1. Structuring Your Site
        1. Resources
          1. Content Types
          2. Named Anchor
          3. Static Resource
          4. Symlink
            1. Using Resource Symlinks
          5. Weblink
        2. Templates
        3. Chunks
        4. Using Snippets
      2. Tag Syntax
      3. Customizing Content
        1. Template Variables
          1. Creating a Template Variable
          2. Adding a Custom TV Type - MODX 2.2
          3. Bindings
            1. CHUNK Binding
            2. DIRECTORY Binding
            3. EVAL Binding
            4. FILE Binding
            5. INHERIT Binding
            6. RESOURCE Binding
            7. SELECT Binding
          4. Template Variable Input Types
          5. Template Variable Output Types
            1. Date TV Output Type
            2. Delimiter TV Output Type
            3. HTML Tag TV Output Type
            4. Image TV Output Type
            5. URL TV Output Type
          6. Adding a Custom TV Input Type
          7. Adding a Custom TV Output Type
          8. Creating a multi-select box for related pages in your template
          9. Accessing Template Variable Values via the API
        2. Properties and Property Sets
        3. Input and Output Filters (Output Modifiers)
          1. Custom Output Filter Examples
      4. Commonly Used Template Tags
        1. Date Formats
    4. Administering Your Site
      1. Settings
        1. System Settings
          1. access_category_enabled
          2. date_timezone
          3. access_context_enabled
          4. access_resource_group_enabled
          5. allow_duplicate_alias
          6. allow_forward_across_contexts
          7. allow_multiple_emails
          8. allow_tags_in_post
          9. archive_with
          10. automatic_alias
          11. auto_check_pkg_updates
          12. auto_check_pkg_updates_cache_expire
          13. auto_menuindex
          14. base_help_url
          15. blocked_minutes
          16. cache_action_map
          17. cache_context_settings
          18. cache_db
          19. cache_db_expires
          20. cache_db_session
          21. cache_default
          22. cache_disabled
          23. cache_format
          24. cache_handler
          25. cache_json
          26. cache_json_expires
          27. cache_lang_js
          28. cache_lexicon_topics
          29. cache_noncore_lexicon_topics
          30. cache_resource
          31. cache_resource_expires
          32. cache_scripts
          33. cache_system_settings
          34. clear_cache_refresh_trees
          35. compress_css
          36. compress_js
          37. concat_js
          38. container_suffix
          39. cultureKey
          40. custom_resource_classes
          41. default_per_page
          42. default_template
          43. editor_css_path
          44. editor_css_selectors
          45. emailsender
          46. emailsubject
          47. enable_dragdrop
          48. error_page
          49. extension_packages
          50. failed_login_attempts
          51. feed_modx_news
          52. feed_modx_news_enabled
          53. feed_modx_security
          54. feed_modx_security_enabled
          55. fe_editor_lang
          56. filemanager_path
          57. filemanager_path_relative
          58. filemanager_url
          59. filemanager_url_relative
          60. forgot_login_email
          61. friendly_alias_lowercase_only
          62. forward_merge_excludes
          63. friendly_alias_max_length
          64. friendly_alias_restrict_chars
          65. friendly_alias_restrict_chars_pattern
          66. friendly_alias_strip_element_tags
          67. friendly_alias_translit
          68. friendly_alias_translit_class
          69. friendly_alias_translit_class_path
          70. friendly_alias_trim_chars
          71. friendly_alias_urls
          72. friendly_alias_word_delimiter
          73. friendly_alias_word_delimiters
          74. friendly_urls
          75. friendly_url_prefix
          76. friendly_url_suffix
          77. global_duplicate_uri_check
          78. hidemenu_default
          79. link_tag_scheme
          80. mail_charset
          81. mail_encoding
          82. mail_smtp_auth
          83. mail_smtp_helo
          84. mail_smtp_hosts
          85. mail_smtp_keepalive
          86. mail_smtp_pass
          87. mail_smtp_port
          88. mail_smtp_prefix
          89. mail_smtp_single_to
          90. mail_smtp_timeout
          91. mail_smtp_user
          92. mail_use_smtp
          93. manager_date_format
          94. manager_direction
          95. manager_favicon_url
          96. manager_language
          97. manager_lang_attribute
          98. manager_theme
          99. manager_time_format
          100. context_tree_sort
          101. context_tree_sortby
          102. context_tree_sortdir
          103. session_enabled
          104. modx_charset
          105. new_file_permissions
          106. new_folder_permissions
          107. password_generated_length
          108. password_min_length
          109. phpthumb_allow_src_above_docroot
          110. phpthumb_cache_maxage
          111. phpthumb_cache_maxfiles
          112. phpthumb_cache_maxsize
          113. phpthumb_cache_source_enabled
          114. phpthumb_document_root
          115. phpthumb_error_bgcolor
          116. phpthumb_error_fontsize
          117. phpthumb_error_textcolor
          118. phpthumb_far
          119. phpthumb_imagemagick_path
          120. phpthumb_nohotlink_enabled
          121. phpthumb_nohotlink_erase_image
          122. phpthumb_nohotlink_text_message
          123. phpthumb_nohotlink_valid_domains
          124. phpthumb_nooffsitelink_enabled
          125. phpthumb_nooffsitelink_erase_image
          126. phpthumb_nooffsitelink_require_refer
          127. phpthumb_nooffsitelink_text_message
          128. phpthumb_nooffsitelink_valid_domains
          129. phpthumb_nooffsitelink_watermark_src
          130. phpthumb_zoomcrop
          131. principal_targets
          132. proxy_auth_type
          133. proxy_host
          134. proxy_password
          135. proxy_port
          136. proxy_username
          137. publish_default
          138. rb_base_dir
          139. rb_base_url
          140. request_controller
          141. request_param_alias
          142. request_param_id
          143. resource_tree_node_name
          144. resource_tree_node_tooltip
          145. richtext_default
          146. search_default
          147. server_offset_time
          148. server_protocol
          149. session_cookie_domain
          150. session_cookie_lifetime
          151. session_cookie_path
          152. session_cookie_secure
          153. session_handler_class
          154. session_name
          155. settings_version
          156. signupemail_message
          157. site_name
          158. site_start
          159. site_status
          160. site_unavailable_message
          161. site_unavailable_page
          162. strip_image_paths
          163. symlink_merge_fields
          164. tree_default_sort
          165. tree_root_id
          166. tvs_below_content
          167. udperms_allowroot
          168. ui_debug_mode
          169. unauthorized_page
          170. upload_maxsize
          171. use_alias_path
          172. use_browser
          173. use_editor
          174. use_multibyte
          175. welcome_screen
          176. which_editor
          177. which_element_editor
          178. xhtml_urls
      2. Using Friendly URLs
      3. Contexts
        1. Creating a Subdomain from a Folder using Virtual Hosts
        2. Using One Gateway Plugin to Manage Multiple Domains
      4. Customizing the Manager
        1. Customizing the Manager via Plugins
        2. Form Customization Profiles
        3. Form Customization Sets
          1. Customizing Tabs via Form Customization
          2. MODX GitHub Contributor's Guide
        4. Manager Templates and Themes
      5. MODX GitHub Integrator's Guide
      6. Security
        1. Hardening MODX Revolution
        2. Policies
          1. ACLs
          2. Permissions
            1. Permissions - Administrator Policy
            2. Permissions - Resource Policy
          3. PolicyTemplates
        3. Resource Groups
        4. Roles
        5. Security Standards
        6. Security Tutorials
          1. More on the Anonymous User Group
          2. Creating a Second Super Admin User
          3. Giving a User Manager Access
          4. Making Member-Only Pages
          5. Restricting an Element from Users
        7. Troubleshooting Security
          1. Resetting a User Password Manually
        8. User Groups
        9. Users
      7. Installing a Package
        1. Troubleshooting Package Management
      8. Upgrading MODX
        1. Upgrading to Revolution 2.0.5
        2. Upgrading from 2.0.x to 2.1.x
        3. Upgrading from Versions Earlier than 2.0.5
        4. Upgrading to 2.2.x
        5. Upgrading to Revolution 2.0.0-rc-2
        6. Troubleshooting Upgrades
        7. Upgrading from MODx Evolution
          1. Functional Changes from Evolution
      9. Moving Your Site to a New Server, or to Root from Subfolder
      10. Media Sources
        1. Adding a Media Source
        2. Assigning Media Sources to TVs
        3. Media Source Types
          1. Media Source Type - File System
          2. Media Source Type - S3
        4. Securing a Media Source
          1. Creating a Media Source for Clients Tutorial
      11. Dashboards
        1. Assigning a Dashboard to a User Group
        2. Creating a Dashboard Widget
        3. Dashboard Widget Types
          1. Dashboard Widget Type - File
          2. Dashboard Widget Type - HTML
          3. Dashboard Widget Type - Inline PHP
          4. Dashboard Widget Type - Snippet
        4. Managing Your Dashboard
    5. Developing in MODx
      1. Code Standards
      2. Overview of MODx Development
        1. Developer Introduction
          1. Getting Started Developing
        2. Extras Directories
        3. Setting up a Development Environment
      3. Basic Development
        1. Plugins
          1. System Events
            1. OnBeforeCacheUpdate
            2. OnBeforeChunkFormDelete
            3. OnBeforeChunkFormSave
            4. OnBeforeDocFormDelete
            5. OnBeforeDocFormSave
            6. OnBeforeEmptyTrash
            7. OnBeforeManagerLogin
            8. OnBeforeManagerLogout
            9. OnBeforeManagerPageInit
            10. OnBeforePluginFormDelete
            11. OnBeforePluginFormSave
            12. OnBeforeSaveWebPageCache
            13. OnBeforeSnipFormDelete
            14. OnBeforeSnipFormSave
            15. OnBeforeTempFormDelete
            16. OnBeforeTempFormSave
            17. OnBeforeTVFormDelete
            18. OnBeforeTVFormSave
            19. OnBeforeUserActivate
            20. OnBeforeUserFormDelete
            21. OnBeforeUserFormSave
            22. OnBeforeWebLogin
            23. OnBeforeWebLogout
            24. OnCacheUpdate
            25. OnCategoryBeforeRemove
            26. OnCategoryBeforeSave
            27. OnCategoryRemove
            28. OnCategorySave
            29. OnChunkBeforeRemove
            30. OnChunkBeforeSave
            31. OnChunkFormDelete
            32. OnChunkFormPrerender
            33. OnChunkFormRender
            34. OnChunkFormSave
            35. OnChunkRemove
            36. OnChunkSave
            37. OnContextBeforeRemove
            38. OnContextBeforeSave
            39. OnContextFormPrerender
            40. OnContextFormRender
            41. OnContextRemove
            42. OnContextSave
            43. OnDocFormDelete
            44. OnDocFormPrerender
            45. OnDocFormRender
            46. OnDocFormSave
            47. OnDocPublished
            48. OnDocUnPublished
            49. OnEmptyTrash
            50. OnFileManagerUpload
            51. OnHandleRequest
            52. OnInitCulture
            53. OnLoadWebDocument
            54. OnLoadWebPageCache
            55. OnManagerAuthentication
            56. OnManagerLogin
            57. OnManagerLoginFormPrerender
            58. OnManagerLoginFormRender
            59. OnManagerLogout
            60. OnManagerPageAfterRender
            61. OnManagerPageBeforeRender
            62. OnManagerPageInit
            63. OnPageNotFound
            64. OnPageUnauthorized
            65. OnParseDocument
            66. OnPluginBeforeRemove
            67. OnPluginBeforeSave
            68. OnPluginEventRemove
            69. OnPluginFormDelete
            70. OnPluginFormPrerender
            71. OnPluginFormRender
            72. OnPluginFormSave
            73. OnPluginRemove
            74. OnPluginSave
            75. OnPropertySetBeforeRemove
            76. OnPropertySetBeforeSave
            77. OnPropertySetRemove
            78. OnPropertySetSave
            79. OnResourceGroupBeforeRemove
            80. OnResourceGroupBeforeSave
            81. OnResourceGroupRemove
            82. OnResourceGroupSave
            83. OnRichTextBrowserInit
            84. OnRichTextEditorInit
            85. OnRichTextEditorRegister
            86. OnSiteRefresh
            87. OnSiteSettingsRender
            88. OnTemplateVarBeforeRemove
            89. OnTemplateVarBeforeSave
            90. OnTemplateVarRemove
            91. OnTemplateVarSave
            92. OnUserActivate
            93. OnUserBeforeRemove
            94. OnUserBeforeSave
            95. OnUserChangePassword
            96. OnUserFormDelete
            97. OnUserFormSave
            98. OnUserNotFound
            99. OnUserRemove
            100. OnUserSave
            101. OnWebAuthentication
            102. OnWebLogin
            103. OnWebLogout
            104. OnWebPageComplete
            105. OnWebPageInit
            106. OnWebPagePrerender
        2. Snippets
          1. Adding CSS and JS to Your Pages Through Snippets
          2. How to Write a Good Chunk
          3. How to Write a Good Snippet
          4. Templating Your Snippets
        3. xPDO
      4. Advanced Development
        1. Caching
          1. Setting up Memcache in MODX
        2. Custom Manager Pages
          1. Custom Manager Pages in 2.3
          2. Actions and Menus
            1. Action List
          3. Custom Manager Pages Tutorial
          4. MODExt
            1. MODx.combo.ComboBox
            2. MODx.Console
            3. MODx.FormPanel
            4. MODx.grid.Grid
            5. MODx.grid.LocalGrid
            6. MODx.msg
            7. MODx.tree.Tree
            8. MODx.Window
            9. MODExt Tutorials
              1. 1. Ext JS Tutorial - Message Boxes
              2. 2. Ext JS Tutorial - Ajax Include
              3. 3. Ext JS Tutorial - Animation
              4. 4. Ext JS Tutorial - Manipulating Nodes
              5. 5. Ext JS Tutorial - Panels
              6. 7. Ext JS Tutoral - Advanced Grid
              7. 8. Ext JS Tutorial - Inside a CMP
            10. MODExt MODx Object
        3. Custom Resource Classes
          1. Creating a Resource Class
            1. Creating a Resource Class - Step 2
            2. Creating a Resource Class - Step 3
            3. Creating a Resource Class - Step 4
        4. Extending modUser
        5. From the Command Line (CLI)
        6. Internationalization
          1. Adding a Translation
        7. MODx Services
          1. modFileHandler
          2. modMail
          3. modRegistry
        8. Namespaces
        9. Package Management
          1. Creating a 3rd Party Component Build Script
          2. Providers
          3. Transport Packages
        10. Using runProcessor
        11. Validating Requests: Tokens and Nonces
        12. Developing RESTful APIs
      5. Other Development Resources
        1. Summary of Legacy Code Removed in 2.1
        2. API Reference
        3. Class Reference
          1. modResource
            1. modResource.isMember
          2. modChunk
            1. modChunk.getContent
            2. modChunk.setContent
          3. modUser
            1. modUser.addSessionContext
            2. modUser.changePassword
            3. modUser.endSession
            4. modUser.getSessionContexts
            5. modUser.getSettings
            6. modUser.hasSessionContext
            7. modUser.isAuthenticated
            8. modUser.isMember
            9. modUser.loadAttributes
            10. modUser.removeSessionContext
            11. modUser.removeSessionContextVars
            12. modUser.removeSessionCookie
          4. modX
            1. modX.addEventListener
            2. modX.checkForLocks
            3. modX.checkSession
            4. modX.executeProcessor
            5. modX.getAuthenticatedUser
            6. modX.getCacheManager
            7. modX.getChildIds
            8. modX.getChunk
            9. modX.getConfig
            10. modX.getContext
            11. modX.getEventMap
            12. modX.getLoginUserID
            13. modX.getLoginUserName
            14. modX.getParentIds
            15. modX.getParser
            16. modX.getPlaceholder
            17. modX.getRegisteredClientScripts
            18. modX.getRegisteredClientStartupScripts
            19. modX.getRequest
            20. modX.getResponse
            21. modX.getService
            22. modX.getSessionState
            23. modX.getTree
            24. modX.getUser
            25. modX.getVersionData
            26. modX.handleRequest
            27. modX.hasPermission
            28. modX.initialize
            29. modX.invokeEvent
            30. modX.lexicon
            31. modX.makeUrl
            32. modX.parseChunk
            33. modX.regClientCSS
            34. modX.regClientHTMLBlock
            35. modX.regClientScript
            36. modX.regClientStartupHTMLBlock
            37. modX.regClientStartupScript
            38. modX.reloadConfig
            39. modX.removeAllEventListener
            40. modX.removeEventListener
            41. modX.runProcessor
            42. modX.runSnippet
            43. modX.sendError
            44. modX.sendErrorPage
            45. modX.sendForward
            46. modX.sendRedirect
            47. modX.sendUnauthorizedPage
            48. modX.setDebug
            49. modX.setPlaceholder
            50. modX.setPlaceholders
            51. modX.switchContext
            52. modX.toPlaceholder
            53. modX.toPlaceholders
            54. modX.unsetPlaceholder
            55. modX.unsetPlaceholders
        4. Loading MODx Externally
        5. Reserved Parameters
    6. Case Studies and Tutorials
      1. Developing an Extra in MODX Revolution
        1. Developing an Extra in MODX Revolution, Part II
        2. Developing an Extra in MODX Revolution, Part III
      2. Developing an Extra in MODX Revolution - MODX 2.1 and Earlier
        1. Developing an Extra in MODX Revolution, Part II - MODX 2.1 and Earlier
        2. Developing an Extra in MODX Revolution, Part III - MODX 2.1 and Earlier
      3. PHP Coding in MODx Revolution, Pt. I
        1. PHP Coding in MODx Revolution, Pt. II
        2. PHP Coding in MODx Revolution, Pt. III
      4. Using Custom Database Tables in your 3rd Party Components
      5. Creating a Blog in MODx Revolution
      6. Loading Pages in the Front-End via AJAX and jQuery Tabs
      7. Reverse Engineer xPDO Classes from Existing Database Table
      8. Integrating a Template into MODX Tutorial
      9. Quick and Easy MODX Tutorials
        1. Automated Server-Side Image Editing
      10. Adding Custom Fields to Manager Forms
      11. Create a Multilingual Website with migxMultiLang
      12. Managing Resources and Elements via SVN
    7. MODX Community Information
      1. Becoming a Core Contributor
      2. Filing Bug Reports
      3. Getting a MODx Account
      4. Using GitHub

Creating a Blog in MODx Revolution

Last edited by Susan Ottwell on Aug 21, 2013.

Creating a Blog in MODx Revolution

MODX Revolution 2.2+ users can simply install Articles, which does everything below automatically for you, in an intuitive and easy-to-use interface.

This tutorial is here to help you setup a flexible, powerful blogging solution in MODx Revolution. Since MODx Revolution is not blogging software, 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 your blog 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 that you're familiar with Revolution's Tag Syntax before we start.

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 splittingred.com. If you'd like a demo before reading, try there.

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 most commonly-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 page displays 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:

[[$pageHeader]]
<div id="content" class="blog-post">
  <h2 class="title"><a href="[[~[[*id]]]]">[[*pagetitle]]</a></h2>
  
  <p class="post-info">
  Posted on [[*publishedon:strtotime:date=`%b %d, %Y`]] | 
  Tags: [[*tags:notempty=`[[!tolinks? &items=`[[*tags]]` &tagKey=`tag` &target=`1`]]`]] | 
  <a href="[[~[[*id]]]]#comments" class="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">Tags: [[!tolinks? &items=`[[*tags]]` &tagKey=`tag` &target=`1`]]</span>
    `]]
    <br class="clear" />
  </div>
  <hr />
  <div class="post-comments" id="comments">[[!Quip?
      &thread=`blog-post-[[*id]]`
      &replyResourceId=`123`
      &closeAfter=`30`
    ]]
    <br /><br />
    [[!QuipReply?
       &thread=`blog-post-[[*id]]`
       &notifyEmails=`my@email.com`
       &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, and adjust 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 you from 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 in the 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 changes in 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 same page.

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]]` &tagKey=`tag` &target=`1`]]`]] | 
<a href="[[~[[*id]]]]#comments" class="comments">
  Comments ([[!QuipCount? &thread=`blog-post-[[*id]]`]])
</a>
</p>

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 just yet, so dont worry - and then pass it as a property to the 'tolinks' snippet. The tolinks snippet comes with tagLister, and translates delimited tags into 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 page besides 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' property in 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 for each 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 of it 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 Quip for our commenting system. You could feel free 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="post-comments" id="comments">[[!Quip?
    &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 (Quip), and another for displaying the reply form (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 going to 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 Documentation. We recommend reading there for how to set it up.) with the 'replyResourceId' property. For a quick example, if your &replyResourceId points to page 123, then on page 123, you should put something like the following:

[[!QuipReply]]
<br />
[[!Quip]]

Next, we want to specify - in both the Quip and Quip Reply calls - a 'closeAfter' property. This tells Quip to automatically close commenting on these 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 in the Quip docs.

What is Threading?
If you enable threaded comments, then users can comment on other comments. Non-threaded comments allow users to only comment on the original blog post.

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 has access to the 'BlogPostTemplate' Template we created earlier.

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 of tags.

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, and make 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 to browse 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 getResources and getPage that automatically filters results by a 'tags' TV. So basically, we want to grab all published Resources within this section (and we can also filter by tag should we pass a '?tag=TagName' parameter 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. It should contain this:

<div class="post">
    <h2 class="title"><a href="[[~[[+id]]]]">[[+pagetitle]]</a></h2>
    <p class="post-info">Posted by [[+createdby:userinfo=`fullname`]]
 [[+tv.tags:notempty=` | <span class="tags">Tags: 
[[!tolinks? &items=`[[+tv.tags]]` &tagKey=`tag` &target=`1`]]
</span>`]]</p>
    <div class="entry">
        <p>[[+introtext]]</p>
    </div>
    <p class="postmeta">
      <span class="links">
<a href="[[~[[+id]]]]" class="readmore">Read more</a>
| <a href="[[~[[+id]]]]#comments" class="comments">
    Comments ([[!QuipCount? &thread=`blog-post-[[+id]]`]])
  </a>
| <span class="date">[[+publishedon:strtotime:date=`%b %d, %Y`]]</span>
      </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.

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:

[[!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 and tolinks 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 month container 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 up in your getResources calls.

Remember, though, that whatever structure you build under the sections, that's not going to determine your navigation - Archivist will handle that. What 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 specify in 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 of browsing 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:

[[!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 getArchives snippet, and 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 we reference 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're done 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 actually pretty 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 Archivist Snippet does is generate a month-by-month list of posts (you can add all kinds of other options, but see it's documentation for 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 Section Resources).

That's it! Archivist will actually automatically handle the rest - including all your URL generation for archives - archives/2010/05/ will show all the posts 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 of Member (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 posts are made. They can then either login to the manager to moderate comments, or click on links directly in the emails to approve or reject the comments. Your ACL should look something like this:

Save your User Group, and that's it! You might have to flush sessions (Security -> Flush Sessions) and re-login to reload your permissions, but Quip 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 getResources to display a top 5 list of Resources in your Section Resources (34,35), and sort by their publishedon date.

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="[[~[[+id]]]]">[[+pagetitle]]</a>
  [[+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 QuipLatestComments that can handle this easily.

Place the call wherever you want the comment list to show:

[[!QuipLatestComments? &tpl=`latestCommentTpl`]]

Now create a chunk called 'latestCommentTpl':

<li class="[[+cls]][[+alt]]">
    <a href="[[+url]]">[[+body:ellipsis=`[[+bodyLimit]]`]]</a>
    <br /><span class="author">by [[+name]]</span>
    <br /><span class="ago">[[+createdon:ago]]</span>
</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' Output Filter we used here. This filter is built into MODx 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 documentation for the snippet for more configuration options.

Adding a "Most Used Tags" widget

This part is ridiculously easy; tagLister does this for you. Just place this wherever you want:

[[!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 ton more configuration options, but we'll leave you with this.

Conclusion

So we've got a full blog setup! It should look something like this in our tree now:

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 customize and 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 splittingred.com, if you'd like to see a full-scale demo of it in action.

Suggest an edit to this page.