{"id":93,"date":"2012-05-24T00:00:33","date_gmt":"2012-05-24T00:00:33","guid":{"rendered":"http:\/\/blog.law.gmu.edu\/webservices\/?p=93"},"modified":"2025-03-14T08:12:12","modified_gmt":"2025-03-14T12:12:12","slug":"notes-on-modx-for-main-site","status":"publish","type":"post","link":"https:\/\/sls.gmu.edu\/web\/2012\/05\/24\/notes-on-modx-for-main-site\/","title":{"rendered":"Notes On MODX For Main Site"},"content":{"rendered":"<h2>Notes from Paul Bohman<\/h2>\n<ul>\n<li>I added some system event names (in the database table modx_system_eventnames) to make up for the fact that they were not part of the base code. I needed these events to make the shadowmaker plugin work<\/li>\n<li>I altered the default sort order for the webpage tree in manager\/frames\/nodes.php. I set it up so that it uses library-style alphabetization by default (so it ignores \u201cThe \u201c, \u201cA \u201c, \u201cAn \u201c etc at the beginning of pagetitle names). This modification will need to be done every time you upgrade MODx, because it\u2019s not part of the core code.<\/li>\n<li>I had to modify <strong>document.parser.class.inc.php<\/strong> in a few places to make the shadowmaker plugin work correctly. This modification will need to be done every time you upgrade MODx, as long as the shadowmaker plugin is being used.<\/li>\n<\/ul>\n<h2>Templates<\/h2>\n<p>Templates cannot have raw PHP code, but they can call snippets, chunks, and template variables.<\/p>\n<p>The main files for the templates of the current site are found in assets\/templates. The files for the current site have a \u201c2010\u201d prefix. I\u2019m using the \u201cinc\u201d snippet to call them in.\u00a0 In that same folder are files for more involved templates, such as course_info, course_instance_info, and faculty_profile. If you update any of these files, you\u2019ll need to clear the cache to see a change. You can clear the cache by using the Site &gt; Clear Cache option or by saving any page (or snippet or chunk) in MODx.<\/p>\n<h2>Template Variables<\/h2>\n<p>Template variables are assigned to templates. If a template variable is not assigned to a given template, you can\u2019t call that template variable.\u00a0To call a template variable in a template, use the following syntax:<\/p>\n<p>[*templateVariableName*]<\/p>\n<p>To use PHx with a template variable, refer to the documentation at\u00a0<a href=\"https:\/\/wiki.modxcms.com\/index.php\/PHx\">https:\/\/wiki.modxcms.com\/index.php\/PHx<\/a><\/p>\n<h2>Chunks<\/h2>\n<p>Snippets are bits of HTML code. Raw PHP code is not allowed, but chunks can call snippets, template variables, and other chunks.<\/p>\n<p>To call a chunk in MODx, use the following syntax:<br \/>\n{{chunkName}}<\/p>\n<h2>MODx Plugins<\/h2>\n<p>Plugins can potentially run on all the pages, based on a chosen trigger.<\/p>\n<h2>New Document Default Values<\/h2>\n<p>This plugin sets a few default values for new documents, which can be modified and customized.\u00a0 I set the default value of \u201cmenuindex\u201d to 990, which was an arbitrary high number, allowing for up to 989 other documents to be listed before the default documents in menus, using the \u201cNavigation\u201d script (which is a modified version of the Wayfinder script that comes with MODx).<\/p>\n<p>TO DO: It would be good to modify the script so that it always sets the template to \u201cblank\u201d when creating a new weblink. Right now it inherits the parent template, which is good for documents, but which breaks weblinks.<\/p>\n<h2>Page TOC Generator<\/h2>\n<p>This plugin creates a page-specific table of contents based on the headings on that page. It\u2019s somewhat configurable. It\u2019s usually best to put the starting code in the pre-content field and the ending code in the post-content field because otherwise the code can be accidentally deleted or altered in the TinyMCE WYSIWYG interface, which will ruin the output.<\/p>\n<h2>Shadowmaker (\u201cNEW ShadowMaker LEAVE ON ALWAYS\u201d)<\/h2>\n<p>This is a plugin that I created to make querying template-based data easier and more straightforward. Unfortunately it also complicates MODx upgrades, because I had to modify the source code, and it does slow down the save\/edit\/delete\/publish process slightly, though its effect there is minimal. The one that really slows down that process is the old ShadowMaker plugin, which really needs to be abandoned, but can\u2019t be until some scripts are updated.<\/p>\n<p>The basic idea behind this plugin is to take all of the template variables, which are in the modx_site_tmplvar_contentvalues table and put them in a single table for each template, so that each template essentially acts as it\u2019s own database table. That way, you can do queries like \u201cselect * from [faculty table] where lname = \u201csmith\u201d. That kind of query isn\u2019t possible to do directly in the native MODx table structure. It reduces the need for joins, and makes joining more straightforward. At least that was the goal.<\/p>\n<p>The way that ShadowMaker works is that it intercepts all save\/edit\/delete\/undelete\/publish\/unpublish actions, using the System Event Names in the modx_system_eventnames table, and updates the derivative tables accordingly. These tables use \u201csm_\u201d as the prefix, followed by the id number (sm_4, sm_5, sm_7, etc.).<\/p>\n<p>In addition, I created some shadowmaker join tables which are also automatically updated in the sm_relationships table.<\/p>\n<p>Basically, it\u2019s PHP-based database trigger system. The code isn\u2019t perfect. It can be refined quite a bit, and I hope you do that\u2026 or that you find an alternative that you think is better, but it seems to be working. It does it\u2019s job.<\/p>\n<p>Several scripts query the derivative tables directly, rather than the MODx native tables, so if you do update or eliminate the ShadowMaker plugin, you\u2019ll have to also update those scripts.<\/p>\n<h2>ShadowMaker (the old one, entitled \u201cShadowMaker TURN ON FOR COURSES ONLY\u201d).<\/h2>\n<p>This was the first attempt at creating a trigger-like system. It\u2019s horribly inefficient, it slows down the save\/edit process in the MODx manager considerabley, and really needs to be eliminated, but it can\u2019t be eliminated yet because the course schedule script uses the tables that this plugin creates (shadow_course_instances), and so do the working paper scripts\u00a0 (shadow_working_papers). You\u2019ll have to first rewrite those scripts before you can get rid of this plugin.<\/p>\n<p>If I were going to do this, I would probably rewrite those scripts to use the ShadowMaker tables created by the new ShadowMaker script. It would require joining them in several ways, especially for the course schedule script, but I think this would be more efficient than trying to query the native MODx tables. I might be wrong on that point. You\u2019ll have to take a closer look at the database setup and decide for yourself what kind of query would be the most efficient.<\/p>\n<h2>Replacements<\/h2>\n<p>This plugin runs on the rendered content right before it is served out to the browser. It does miscellaneous things like rewrite same-page links so that they work properly (when using MODx it\u2019s best to use the &lt;base&gt; tag, which then messes up same-page links, and this plugin fixes that problem), and also attempts to put all list items on the same line to avoid CSS display problems in IE6 when there are spaces or line breaks between list items when the CSS is set to display:block for these items. This part of the script doesn\u2019t work perfectly, but it mostly works. You can add other replacements to this script as necessary to correct issues as you discover them. It does add an extra layer to the PHP code, which probably slows it down somewhat, but I don\u2019t think it makes a huge difference. I think other factors slow down page rendering more than this plugin.<\/p>\n<h2>PHx<\/h2>\n<p>I didn\u2019t write this one, but it\u2019s quite useful. It extends the functionality of MODx placeholders, allowing for various kinds of logic. It\u2019s not as powerful as something like Smarty templates, but it\u2019s based on the same type of idea. I used the phx plugin extensively on the main law school web site, so you\u2019ll have to learn how it works. See <a href=\"https:\/\/wiki.modxcms.com\/index.php\/PHx\">https:\/\/wiki.modxcms.com\/index.php\/PHx<\/a>.\u00a0 I\u2019ll admit that the if\/then logic of phx can get really messy. Some of my templates are hard to read because phx is not as clean as PHP code, but it does work. It probably slows the rendering down somewhat too. I didn\u2019t use it on the last iteration of the site. I used plain PHP instead, and to be honest, I didn\u2019t see much of a difference in rendering time. I think the biggest factor in rendering time is the site cache system, in particular the siteCache.idx.php file, which is 1.66MB last time I checked. That\u2019s a problem with the way MODx is written, and you really can\u2019t do anything about that unless you invent your own caching system.<\/p>\n<h2>Snippets<\/h2>\n<p>Snippets are bits of PHP code. You can\u2019t insert raw PHP code in a template or document in MODx, so you have to do this through snippets.<\/p>\n<p>To call a snippet in MODx, use a syntax like this:<br \/>\n[[snippetName? &amp;parameter1=`foo` &amp;parameter2=`bar`]]<\/p>\n<p>To call a snippet that should NOT be cached, used this syntax:<br \/>\n[!snippetName? &amp;parameter1=`foo` &amp;parameter2=`bar`!]<\/p>\n<h2>alphaSort<\/h2>\n<p>This script allows you to sort a list of items using library alphabetization style. It can be used within other scripts. I employed the same sorting technique in my modification to the MODx source code.<\/p>\n<h2>antiSpam <\/h2>\n<p>This snippet is used in conjunction with the eForm snippet. It has some basic features intended to block a few common spam techniques with online forms. This snippet could be greatly expanded upon and improved, but we haven\u2019t had too much trouble with form spam, so I haven\u2019t touched it in quite a while.<\/p>\n<h2>breadcrumbs<\/h2>\n<p>This is a reasonably flexible script that creates a breadcrumb trail. I use it on the current site.<\/p>\n<h2>classInterface<\/h2>\n<p>The purpose of this script is to allow access to PHP classes from within MODx without having to create a new snippet for each one. I don\u2019t think this is currently being used on the site, but it could potentially be used to call PEAR classes, or other custom classes. The benefit of using this script, besides not having to create a new snippet every time, is that it keeps the site cache file smaller by eliminating all the extra snippets that would be in there otherwise. I haven\u2019t taken advantage of this script recently, and it probably needs to be looked at again to make it more robust, but the idea is still a good one.<\/p>\n<h2>Ditto<\/h2>\n<p>Ditto is the fastest, easiest way to pull data from MODx. I use it extensively on the site to pull in information from various sources. Spend some time reading over the information at <a href=\"https:\/\/ditto.modxcms.com\/\">https:\/\/ditto.modxcms.com\/<\/a>, especially <a href=\"https:\/\/ditto.modxcms.com\/files\/snippet-ditto-php.html\">https:\/\/ditto.modxcms.com\/files\/snippet-ditto-php.html<\/a> and <a href=\"https:\/\/ditto.modxcms.com\/tutorials\/basic_filtering.html\">https:\/\/ditto.modxcms.com\/tutorials\/basic_filtering.html<\/a> <strong><\/strong><\/p>\n<h2>DittoPlus<\/h2>\n<p>This is a script that I wrote to extend Ditto. I don\u2019t remember at the moment where this is being used, but I\u2019m pretty sure it\u2019s being used somewhere within the code, possibly in the course schedule script.<\/p>\n<h2>eForm<\/h2>\n<p>This script allows you to create a submission form in a web page. It\u2019s quite configurable. You create a chunk for the form, a chunk for the email that it sends, and a chunk for the \u201cthank you\u201d message that displays on the screen after the user submits the form. It has some validation functionality built into it, though it\u2019s not the most flexible script in how it handles validation errors. The script is used in places like <a href=\"https:\/\/www.law.gmu.edu\/contact\">https:\/\/www.law.gmu.edu\/contact<\/a> and on the forms available at <a href=\"https:\/\/www.law.gmu.edu\/academics\/lrwa\/\">https:\/\/www.law.gmu.edu\/academics\/lrwa\/<\/a><\/p>\n<p><strong>NOTE:<\/strong> You will have to update those forms every semester. You may come up with a better way of handling those forms, because I admit it\u2019s a little cumbersome to match up the email addresses with the names of the form fields, but it does work if you\u2019re careful.<\/p>\n<p><strong>NOTE 2:<\/strong> If you ever need to allow for multiple document submissions, there should be an example in the list of eForm forms still from a previous semester that you can look at.<\/p>\n<h2>ErroneousRex<\/h2>\n<p>I wrote this script to help with 404 errors. It is activated when a user arrives at the 404 page. The script first replaces certain strings in the url and tries to redirect based on those replacements. If those don\u2019t work, it tries some regex replacements. If those don\u2019t work, it goes to the \u201credirect\u201d table in the database and looks for replacements there. The redirect table has two kinds of replacements:<\/p>\n<ol>\n<li>Old url -&gt; new url<\/li>\n<li>Old url -&gt; MODx id<\/li>\n<\/ol>\n<p>When entering data into this table, it is definitely much better to use the MODx id method than the new url method, because that will help ensure that the redirect will still work even if the page is moved again later. But in some cases it makes sense to use the new url, so that method is available too.<\/p>\n<p><strong>IMPORTANT NOTE:<\/strong> If the ErroneousRex script is not successful in redirecting to an active page, it creates an entry in the \u201clog_errors\u201d table. You should check this table frequently to see if there are bad links on the site that need to be fixed.<\/p>\n<p><strong>TO DO:<\/strong> It would be great to update the ErroneousRex script so that it sends an email when certain kinds of errors are logged, such as bad links that aren\u2019t flagged as malicious. We get quite a few hacking attempts on the site that are logged in the log_errors table, but which I flag with a \u201c1\u201d in the malicious field. Usually those have no effect, but I do look at them from time to time to see if there is a pattern that I should be aware of.<\/p>\n<p><strong>TO DO:<\/strong> It would be great to create an admin front end for this script so that Deborah and other people could add or edit redirects without having to log in to the phpMyAdmin database interface.<\/p>\n<p>The replacements and regex replacements are in the snippet itself, and have to be modified there, at least as the snippet is currently written.<\/p>\n<h2>eval_get_subject_category_id, etc.<\/h2>\n<p>The snippets that start with \u201ceval_\u201d are generally scripts that are used to generate drop down lists or other similar features related to template variables within the manager interface. This particular script, for example, gets the ids of the subject categories, then converts those ids into human readable words, based on the pagetitles of the documents. In the database, the id is stored, making it easier to keep track of things if the pagetitle changes in the future. See the course_subject_category template variable to understand how the snippet is used.<\/p>\n<h2>FlexibleSiteIndex<\/h2>\n<p>I wrote this snippet so that we could create a site index by entering in terms on the pages themselves. It takes into account page deletions, unpublished pages, etc. It\u2019s pretty robust, and can create a single page, as the law school site does currently, or it can create separate pages for each letter of the alphabet.\u00a0 See <a href=\"https:\/\/www.law.gmu.edu\/assets\/snippets\/flexiblesiteindex\/docs\/instructions\">https:\/\/www.law.gmu.edu\/assets\/snippets\/flexiblesiteindex\/docs\/instructions<\/a> for instructions. Also, the code is available at <a href=\"https:\/\/modxcms.com\/extras\/package\/152\">https:\/\/modxcms.com\/extras\/package\/152<\/a> I may never update it again, but if I do, it will be available there.<\/p>\n<h2>ifMu<\/h2>\n<p>This script checks to see if the current user is a member of a given group. It can be used to grant or exclude access behind password protected areas. It\u2019s not currently being used on the site.<\/p>\n<h2>inc<\/h2>\n<p>This is a simple script (in fact, I suppose it could\/should be simplified even more) that simply includes a file. It acts like the \u201cinclude\u201d function in PHP, but since MODx doesn\u2019t allow raw PHP code in documents (it only allows it in snippets), the only way to include something in MODx is to create a chunk. That\u2019s fine, except that every time you create a chunk it increases the size of the main site cache file, which slows down the site. So I created the \u201cinc\u201d snippet to add \u201cinclude\u201d functionality without bloating the site cache. I\u2019m not using this script a whole lot on the site right now, but it would probably be a good idea to take some of the chunks that are currently there and move them to files, then use the \u201cinc\u201d snippet to call them. That will streamline the main site cache file a bit.<\/p>\n<h2>LastUpdated<\/h2>\n<p>Displays the date of when a page was last updated. The date format is configurable. See the snippet for details.<\/p>\n<p><strong>NOTE:<\/strong> It cannot determine when data within the page from snippets was last updated (e.g. if you use Ditto to call other pages, some of those pages may have been updated more recently than the page you\u2019re currently on). It only checks the date that the page itself was last updated.<\/p>\n<h2>Navigation<\/h2>\n<p>This is a modified version of the Wayfinder script that comes with MODx. I had to put in some customizations for our site\u2019s needs, but it\u2019s essentially the same thing. NOTE: you can\u2019t use both Navigation and Wayfinder on the same page. You can only use one or the other, or else it will cause a PHP error.<\/p>\n<h2>phx:convert_course_attributes etc.<\/h2>\n<p>All of the snippets that start with \u201cphx:\u201d are written as extensions to the PHx plugin. They allow for data manipulation within the template variables. I\u2019ve used these snippets for relatively simple data conversions for the most part, but I imagine it could be written to do some more powerful things if necessary, though if it gets too complex, it is probably better to write a separate PHP snippet instead.<\/p>\n<h2>randomizer<\/h2>\n<p>This snippet isn\u2019t being used at all on the current site, but it could be used in place of the static banner images that we currently have on each page. In fact, that was my original intention\u2014to have these be randomly chosen images from a list\u2014but I ran out of time and didn\u2019t get that done.<\/p>\n<h2>random_banners (random content)<\/h2>\n<p>Even though the script is called \u201crandom_banners\u201d it could really be renamed random_content. I used this script on the previous site, but it\u2019s not currently being used, though it could be in the future. You supply it with a comma-delimited list of pagetitles or ids, the script picks one of them at random, and displays the \u201ccontent\u201d field from that page. The advantage of this script is that it allows you to include any content that you like, so you can include not only the image, but also its alt text, a link around it\u2026 or even paragraphs and whatever else you want.<\/p>\n<h2>Script<\/h2>\n<p>I wrote this plugin so that I could include any PHP script I wanted to without having to create a new snippet every time. With this snippet, all you do is say which script you want to run, include whatever parameters you need in the call to the script, and you\u2019re good to go. I also included a few hacks so that the parameters could include a standard SQL statement. MODx does not allow the equals sign (\u201c=\u201d) or the greater than (&gt;) or less than (&lt;) signs in snippet calls, so I wrote some strings that will be replaced during script execution. So you would write something like this: \u201cselect * from sm_4 where id ((EQUALS)) 5\u201d. The \u201c((EQUALS)\u201d text will be replaced with an \u201c=\u201d sign.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Notes from Paul Bohman I added some system event names (in the database table modx_system_eventnames) to make up for the fact that they were not part of the base code. I needed these events to make the shadowmaker plugin work I altered the default sort order for the webpage tree in manager\/frames\/nodes.php. I set it &hellip; <a href=\"https:\/\/sls.gmu.edu\/web\/2012\/05\/24\/notes-on-modx-for-main-site\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Notes On MODX For Main Site&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[4],"tags":[22],"class_list":["post-93","post","type-post","status-publish","format-standard","hentry","category-cms","tag-modx"],"_links":{"self":[{"href":"https:\/\/sls.gmu.edu\/web\/wp-json\/wp\/v2\/posts\/93","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sls.gmu.edu\/web\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sls.gmu.edu\/web\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sls.gmu.edu\/web\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sls.gmu.edu\/web\/wp-json\/wp\/v2\/comments?post=93"}],"version-history":[{"count":0,"href":"https:\/\/sls.gmu.edu\/web\/wp-json\/wp\/v2\/posts\/93\/revisions"}],"wp:attachment":[{"href":"https:\/\/sls.gmu.edu\/web\/wp-json\/wp\/v2\/media?parent=93"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sls.gmu.edu\/web\/wp-json\/wp\/v2\/categories?post=93"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sls.gmu.edu\/web\/wp-json\/wp\/v2\/tags?post=93"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}