We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 39251
    • 53 Posts
    (Revo 2.2) I've been doing a heavily-customized back-end for an enormous website and the conflicts I'm having with form customizations are driving me crazy. If I wanted to hack this to give some sort of priority order, where's the best place to start? I'm usually better at tracing code, but I'm trying to do this through a nasty case of the flu and I've never poked this part of the code before.

    An alternate to priority order would be to expand the constraint fields to handle ANDs and ORs. Or EVALs?

    So far I've gotten as far as checkFormCustomizationRules() in modmanagercontroller.class.php. If I can do this with a plug-in, obviously I'd rather do that than edit core files.

    Maybe related, maybe not, how can I set it up so that some resources cannot have child resources created for them, or that they can only have child resources of a specific type created? What generates those right-click menus? As with the above, if there's not already a way to do this I'm happy to program it, I just need to know the best place to start.
      If there's a better way to do it, I'll find it.
      • 39251
      • 53 Posts
      By the way, here's an example.

      For every page using template "Inner," hide the introtext field.
      For every page using template "Inner", with a parent = 250, show the introtext field and label it "Intro:"

      When I output all of the rules being applied, they're coming in this order, which I'm assuming is the order the rules were created:
          [14] => MODx.renameLabel("modx-panel-resource",["introtext"],["Intro:"]);
      .
          [18] => MODx.hideField("modx-panel-resource",["introtext"]);
      


      So I need to first get it applying the rules in the right order, and then override any that conflict. Somewhere it's turning the $fieldArray['visible'] from modFormCustomizationSet into MODx.hideField(). So I either need to remove that rule if there's a conflict, or get it to add a MODx.showField() to override it...
        If there's a better way to do it, I'll find it.
        • 3749
        • 24,544 Posts
        I could be wrong, but I think the rules will generally be implemented in the order that you create them (though it's definitely not guaranteed), so you might get them in the right order by deleting and re-creating some. Changing the order of the rules in the DB, might also be an option.


        ------------------------------------------------------------------------------------------
        PLEASE, PLEASE specify the version of MODX you are using.
        MODX info for everyone: http://bobsguides.com/modx.html
          Did I help you? Buy me a beer
          Get my Book: MODX:The Official Guide
          MODX info for everyone: http://bobsguides.com/modx.html
          My MODX Extras
          Bob's Guides is now hosted at A2 MODX Hosting
          • 39251
          • 53 Posts
          Yeah, they are. I thought about that (easiest hack ;-) but that would involve changing the IDs, which would likely lead to all kinds of bad things. I did kind of solve the order problem by adding to the sort in checkFormCustomizationRules() around line 777 (v2.2.2):

                  $c->sortby('modActionDom.rank','DESC');
          				
                  // CB: Additional sorts from least to most specific
                  $c->sortby('FCSet.action','ASC');
                  $c->sortby('FCSet.template','ASC');
                  $c->sortby('FCSet.constraint','ASC');
          


          That works as a band-aid, applying rules with constraints after ones with no constraints. (It's not perfect, as then it starts applying the constraints in alphabetical order, but at this point I don't have competing constraints to worry about.)

          I also modified this part, just to make it a bit cleaner so it wasn't putting the same rule in multiple times:
                      // CB: Only add rule if it doesn't already exist
                      //if (!empty($r)) $rules[] = $r;
                      if (!empty($r)) {
                        if (!in_array($r, $rules)) $rules[] = $r;
                      }
          


          That doesn't solve my problem of field visibility, though. The customization rules only add a fieldVisible rule if you hide a field (which explains my problem with over-riding hidden fields). I think I need to somehow track if a resource matches multiple sets and ignore any fieldVisible rules in all but the last one.
            If there's a better way to do it, I'll find it.
            • 39251
            • 53 Posts
            Ok, this appears to work, although I haven't heavily tested it. All edits done to Revo v2.2.2. /core/model/modx/modmanagercontroller.class.php, in the function checkFormCustomizationRules().

            First, when retrieving the rules, this is how I sorted them, starting at line 775:
                    // $c->sortby('modActionDom.rank','DESC');
                            
                    // CB: Sort from least to most specific
                    $c->sortby('FCSet.template','ASC');
                    $c->sortby('FCSet.constraint','ASC');
                    $c->sortby('modActionDom.set','ASC');
                    $c->sortby('modActionDom.rank','ASC');
            

            I then created a special array to hold just the fieldVisible rules. I only want to use the rules from the last set that applies to the resource, so I wipe this array out every time the set ID changes. This starts at line 811 (counting lines added above):
                        $r = $rule->apply();
                        
                        // CB: If the Set ID has changed, reset the array for holding field visibility rules
                        if (!setID || $rule->get('set') != $setID) {
                          $visibilityRules = array();
                          $setID = $rule->get('set');
                        }
                        
                        // CB: Add the current rule to the appropriate array
                        //if (!empty($r)) $rules[] = $r;
                        if (!empty($r)) {
                          if ($rule->get('rule') == 'fieldVisible') {
                            if (!in_array($r, $visibilityRules)) $visibilityRules[] = $r;
                          } else {
                            if (!in_array($r, $rules)) $rules[] = $r;
                          }
                        }
            


            Then after the foreach loop, before outputting the rules, I add the fieldVisible rules to the rest of the rules, at line 828:
                    // CB: Add the field visibility rules (if any) to the rules array
                    if (!empty($visibilityRules)) $rules = array_merge($rules, $visibilityRules);
            
                    // ************** DEBUG OUTPUT *********************
                    // if (!empty($rules)) { print_r($rules); die; }
            				
                    if (!empty($rules)) {
                        $this->ruleOutput[] = '<script type="text/javascript">Ext.onReady(function() {'.implode("\n",$rules).'});</script>';
                    }
            


            I'm sure there are all kinds of potential issues with this, but it seems to be working in the brief bit of testing that I did. Comments, improvements, etc., very much welcome.

            Also, is there a way to code this so I'm not editing a core file? I'd rather do this in some way that doesn't get wiped out when I upgrade.
              If there's a better way to do it, I'll find it.
              • 3749
              • 24,544 Posts
              You should be able to do at least some of it with your own custom plugin tied to OnDocFormPrerender and/or OnDocFormRender. That would be the official method and would survive upgrades.

              This might help: http://www.cmslesstraveled.com/index/archive/2012/setting-templates-automatically.html


              And this: http://rtfm.modx.com/display/revolution20/Adding+Custom+Fields+to+Manager+Forms


              Neither is exactly what you want, but might give you some ideas.

              There's a little info here on customizing the right-click menu. It's for the Element tree, but might get you started: https://forums.modx.com/thread/75133/elements-tree-toolbar-modification




              All the Resource fields are available in the $scriptProperties array in OnDocFormRender and OnDocFormPrerender when updating an existing resource and can be modified or responded to.


              You might also file a feature request at http://bugs.modx.com for being able to rank FC rules to control the order of application and/or priority.


              ------------------------------------------------------------------------------------------
              PLEASE, PLEASE specify the version of MODX you are using.
              MODX info for everyone: http://bobsguides.com/modx.html
                Did I help you? Buy me a beer
                Get my Book: MODX:The Official Guide
                MODX info for everyone: http://bobsguides.com/modx.html
                My MODX Extras
                Bob's Guides is now hosted at A2 MODX Hosting
                • 39251
                • 53 Posts
                Had to update my code to deal with moving template variables. It appears that once MODx.moveTV() has moved a TV once, running it again does nothing.
                            // CB: Add the current rule to the appropriate array
                            //     fieldVisible: Add to the visibilityRules array
                            //     tvMove: Overwrite any previous tvMove rules for that TV
                            //     All others: Just add to the rules array
                            //if (!empty($r)) $rules[] = $r;
                            if (!empty($r)) {
                              if ($rule->get('rule') == 'fieldVisible') {
                                if (!in_array($r, $visibilityRules)) $visibilityRules[] = $r;
                              } elseif (($rule->get('rule') == 'tvMove') && (!in_array($r, $rules))) {
                                $found = false;
                                $action = substr($r, 0, strpos($r, '],')+2);
                                for ($i=0; $i < count($rules); $i++) {
                                  if (strpos($rules[$i], $action) !== false) { 
                                    $rules[$i] = $r; 
                                    $found = true; 
                                  }
                                }
                                if (!$found) $rules[] = $r;
                              } else {
                                if (!in_array($r, $rules)) $rules[] = $r;
                              }
                            }
                

                Making TVs visible or not seems to be done somewhere else. If I uncheck the "visible" checkbox on any of the sets, it doesn't change the output of these rules. So unlike the regular resource fields, I can't override it these like I did with the fieldVisible rules. So far I've been able to get around this because I hide the modx-panel-resource-tv tab, so if I don't want a TV showing, I leave it there, and if I do, I move it to the Document tab.

                Let me know if I'm breaking any etiquette rules by posting my code updates here. I'm hoping it'll be helpful to someone, and it forces me to quadruple-check everything because I don't want to post stupid code in the forum. ;-) That, and maybe someone will see this and think of better ways to do it.

                How could I modify this so it ran in one of the Rendering events? That is an obvious place for it, and I could then copy and hack this function all I wanted, but the original outputs the javascript for these rules right in the function, so I'd have to somehow keep it from running. It's called from render() in modmanagercontroller.class.php and there doesn't seem to be a way to override it.

                I guess I could make the entire FC Profile inactive to keep it from running there and then have my function ignore inactive profiles and only pay attention to active/inactive sets? It makes me cringe a bit, although it would work, at least until I actually wanted to make a Profile inactive for real. smiley

                Thanks for those other links! Those are going to be a huge help with a couple of other issues I'm having. Another thing I've been having an awful time with in the FC section is dealing with child templates. Knowing more how FC works, I see why, but that will be MUCH easier to deal with using a plug-in.

                I looked through the bug list (going by title, I think a LOT of those bugs are related to the priority issues I'm attempting to "fix" here), but I found one with a link that seems to indicate this priority ordering has been added:
                https://github.com/modxcms/revolution/commit/ca1d09775114baa05c28a2c4b7bfea62fc36014b

                I see the rank field in the modx_actiondom table, and the original code did order the rules using that rank, but the ranking isn't per set, it seems to be per rule, and I can't tell what's setting it. Have I missed something in the interface or is that for future use?
                  If there's a better way to do it, I'll find it.
                  • 39251
                  • 53 Posts
                  Oops. Found a bug in the line where I merge the arrays. It helps if the arrays BOTH exist:
                          // CB: Add the field visibility rules (if any) to the rules array
                          if (!empty($rules) && !empty($visibilityRules)) $rules = array_merge($rules, $visibilityRules);
                  
                    If there's a better way to do it, I'll find it.
                    • 3749
                    • 24,544 Posts
                    Posting your code is encouraged.

                    I'm afraid I don't know enough about how the FC rules are implemented or how TV visibility can be controlled in the plugins to be any more help. Maybe someone else can step in.



                    ------------------------------------------------------------------------------------------
                    PLEASE, PLEASE specify the version of MODX you are using.
                    MODX info for everyone: http://bobsguides.com/modx.html
                      Did I help you? Buy me a beer
                      Get my Book: MODX:The Official Guide
                      MODX info for everyone: http://bobsguides.com/modx.html
                      My MODX Extras
                      Bob's Guides is now hosted at A2 MODX Hosting