We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 20135
    • 188 Posts
    I have an odd problem, which has only come up with the latest version of MODx.

    I posted here (http://forums.modx.com/thread/69810/auto-tag-tv-type-in-newspublisher?page=2) about a solution I had for using autoTag TVs with NewsPublisher and jquery ui to create a list by which the user could populate a NP field. At the time, this worked beautifully, but recently needed to update MODx to 2.2.14. Since then, a bug has been created that has been difficult to isolate. Let me go through the error first.

    You'll see in the forum post I previously mentioned that I have followed the steps originally outlined, and have even posted my own version of the chunk, which still looks like this:
    <div id="np-[[+npx.fieldName]]-container" class="np-text">
      [[+np.error_[[+npx.fieldName]]]]
      <label class="fieldlabel" for="np-[[+npx.fieldName]]" [[+npx.readonly]] title="[[+npx.help]]">[[+npx.caption]]: </label>
      <input name="[[+npx.fieldName]]" class="text" id="np-[[+npx.fieldName]]" type="text"  value="[[+np.[[+npx.fieldName]]]]"  maxlength="[[+npx.maxlength]]" />
    </div>
      
    <script>
     $(function() {
        var [[+npx.fieldName]]Tags = [ [[!tagLister? &tv=`[[+npx.fieldName]]` &tpl=`npTagTplJSON` &parents=`213` &sortBy=`tag` &limit=`0` &outputSeparator=`,`]] ];
        function split( val ) {
          return val.split( /,\s*/ );
        }
        function extractLast( term ) {
          return split( term ).pop();
        }
      
        $( "#np-[[+npx.fieldName]]" )
          // don't navigate away from the field on tab when selecting an item
          .bind( "keydown", function( event ) {
            if ( event.keyCode === $.ui.keyCode.TAB &&
                $( this ).data( "ui-autocomplete" ).menu.active ) {
              event.preventDefault();
            }
          })
          .autocomplete({
            minLength: 0,
            source: function( request, response ) {
              // delegate back to autocomplete, but extract the last term
              response( $.ui.autocomplete.filter(
                [[+npx.fieldName]]Tags, extractLast( request.term ) ) );
            },
            focus: function() {
              // prevent value inserted on focus
              return false;
            },
            select: function( event, ui ) {
              var terms = split( this.value );
              // remove the current input
              terms.pop();
              // add the selected item
              terms.push( ui.item.value );
              // add placeholder to get the comma-and-space at the end
              terms.push( "" );
              this.value = terms.join( ", " );
              return false;
            }
        });
    });
     
    </script>
    

    The error shows in tagLister snippet call - the npx.fieldName placeholder isn't parsing before the snippet is called.

    If...
    [[+npx.fieldName]] = performers

    ... then this call fails to produce a result:
    [[!tagLister? &tv=`[[+npx.fieldName]]` &tpl=`npTagTplJSON` &parents=`213` &sortBy=`tag` &limit=`0` &outputSeparator=`,`]]

    ...but this call works successfully, :
    [[!tagLister? &tv=`performers` &tpl=`npTagTplJSON` &parents=`213` &sortBy=`tag` &limit=`0` &outputSeparator=`,`]]


    I think the problem is in NewsPublisher itself; it's no longer accounting for the placeholder nested in the tagLister snippet call, because tagLister is being parsed before NewPublisher deals with its own placeholders in the chunk.

    So I need a solution here - can anyone help me work out how to make this work?
      • 3749
      • 24,544 Posts
      I wonder if the extra square brackets in this line are confusing the MODX parser:

      [ [[!tagLister? &tv=`[[+npx.fieldName]]` &tpl=`npTagTplJSON` &parents=`213` &sortBy=`tag` &limit=`0` &outputSeparator=`,`]] ]


      NewsPublisher doesn't really parse anything. It just replaces its placeholders with str_replace() and generally calls getChunk() without a second argument, so I think the problem is occurring before NP gets things. I could be wrong.

      I did a quick test calling $modx->getChunk() on a chunk with this content:

      [[!tagLister? &tv=`[[+npx.fieldName]]` &tpl=`npTagTplJSON` &parents=`213` &sortBy=`tag` &limit=`0` &outputSeparator=`,`]]
      var [[+npx.fieldName]]Tags = [ [[!tagLister? &tv=`[[+npx.fieldName]]` &tpl=`npTagTplJSON` &parents=`213` &sortBy=`tag` &limit=`0` &outputSeparator=`,`]] ];


      Both lines come through unchanged.

      I've left a debugging function in the NewsPublisher class file, so you might be able to get a clue to what's happening by creating a chunk called 'debug' and writing to it with lines like this in the NP class file to see what the unprocessed Tpl chunks contain at various points:

      $this->my_debug($tpl);


      Passing true as a second argument will clear the current content of the chunk.

      Another thing to try would be to add this line at the top of the TagLister snippet to see exactly what it's getting for properties:

      echo '<pre>' . print_r($scriptProperties, true);

        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
        • 20135
        • 188 Posts
        Bob, I discovered something odd. I ran all of the tests you suggested without great success. However I ran some tests on the tagLister snippet, around line 117:
        if ($sortBy == 'publishedon') {
            $c->sortby('Resource.publishedon',$sortDir);
        } else if (in_array($sortBy,array('rand','random','rand()'))) {
            $c->sortby('RAND()','');
        }
        print $tv;
        print $c->toSQL();
        $tags = $modx->getCollection('modTemplateVarResource',$c);
        

        I started by returning or simply printing the value of $tv, and got 'performers' as I expected (ellipses mine)...
        performers SELECT ... WHERE ( `TemplateVar`.`name` = 'performers' ... )

        So then I added a die() function within the snippet:
        if ($sortBy == 'publishedon') {
            $c->sortby('Resource.publishedon',$sortDir);
        } else if (in_array($sortBy,array('rand','random','rand()'))) {
            $c->sortby('RAND()','');
        }
        print $tv;
        $c->prepare();
        print $c->toSql();
        die();
        $tags = $modx->getCollection('modTemplateVarResource',$c);
        

        The response that I got was for an unprocessed placeholder, as follows (ellipses mine):
        [[+npx.fieldName]] SELECT ... WHERE ( `TemplateVar`.`name` = '[[+npx.fieldName]]' ... )

        What I'm thinking is that NP runs getChunk on the npOuterTagTpl chunk as I have it in the post above, and when it does that, MODx processes the tagLister snippet BEFORE NP has had a chance to process the chunk for its placeholders. Does that sound right?

        Would the solution be to change the process of evaluating the placeholders so that, rather than using str_replace, you set all the placeholders in an array to pass to getChunk? [ed. note: moniarde last edited this post 9 years, 10 months ago.]
          • 3749
          • 24,544 Posts
          Good detective work. Things do get strange when you placeholder set by one snippet in the tag for another snippet, then throw dynamic JavaScript code into the mix. wink

          I don't think you're idea will work, but I could be wrong. A few things to try first, if you haven't already:

          Try calling TagLister cached. That should cache it with the placeholder intact, which could work. The rest of the tag is not dynamic, so it shouldn't hurt and might speed things up to boot.

          If that doesn't work, try TagLister cached and the placeholder uncached (!):

          [[!+npx.fieldName]]


          Finally, try both TagLister and the placeholder tag uncached.
            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
            • 20135
            • 188 Posts
            Quote from: BobRay at Jun 24, 2014, 05:52 AM
            Good detective work. Things do get strange when you placeholder set by one snippet in the tag for another snippet, then throw dynamic JavaScript code into the mix. wink

            I don't think you're idea will work, but I could be wrong. A few things to try first, if you haven't already:

            Try calling TagLister cached. That should cache it with the placeholder intact, which could work. The rest of the tag is not dynamic, so it shouldn't hurt and might speed things up to boot.

            If that doesn't work, try TagLister cached and the placeholder uncached (!):

            [[!+npx.fieldName]]


            Finally, try both TagLister and the placeholder tag uncached.
            Tried all of those options without success.

            Is there a way of putting the output of [[!+npx.fieldName]] into another placeholder that isn't directly attached to NP? The [[!+npx.fieldName]] is working everywhere else, and maybe if there's a workaround for getting that value sooner, it might inject the value into tagLister prior to processing tagLister.
              • 3749
              • 24,544 Posts
              You can always use a snippet to get or set placeholders. The trick will be to have it run at the right time.

              <?
              $ph = $modx->getPlaceholder('npx.fieldName');
              $modx->setPlaceholder('myPlaceholder', $ph);
              


              I'm not sure it will work, though because IIRC, as you suspect, NP replaces the 'npx.' placeholders with str_replace(), so they're not "real" placeholders that are replaced by MODX.

              You could always add code to the NP class file that sets a real placeholder with the code above at the point where the str_replace() occurs. Again, I'm not sure that it would work, but it might.

              What's strange is that nothing is parsed during getChunk() except placeholders that are either sent in the function call or set as properties. I've just tested this again to make sure. All snippet and unset placeholder tags come through untouched.

              The TagLister snippet tag should be coming through untouched and NP should be replacing that placeholder long before MODX executes the snippet. The only change I can think of in later versions of MODX that might be a factor is that MODX no longer allows MODX tags in the $_POST unless you have the allow_tags_in_post System Setting set.
                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
                • 20135
                • 188 Posts
                Ok, I'm heading back to newspublisher.class.php to try and run perform the placeholder change manually, using what functions you've already put into the code. The autotag code which has been added is sitting at around line 860ish, and looks just like this:
                case 'autotag':
                	$formTpl .= $this->_displaySimple($name, 'TagOuterTpl', '');
                break;     
                

                Given that $name has already been established up on line 808, it would be reasonable to assume that I could run your function strReplaceAssoc using $name as such:
                case 'autotag':
                	$PHs = array('[[+npx.fieldname]]' => $name, '[[+npx.maxlength]]' => '');
                	$formTpl .= $this->strReplaceAssoc($PHs, $this->getTpl('TagOuterTpl'));
                break;     
                

                That should work right?

                PS. Your suggestion earlier that I test [[!+npx.fieldname]] was never going to work, because of this very thing. str_replace would never have distinguished the exclamation mark!

                Update:
                Won't work - getTpl could be the culprit here. getTpl is your chunk that utilises getChunk, but getChunk is parsing tagLister before I can get to it. sad

                Help me out here Bob, how can I make the switch before getChunk processes the chunk? Is there a way to capture the raw chunk, do a quick str_replace for that field, store the chunk in a variable and push that through getChunk or its root functions? [ed. note: moniarde last edited this post 9 years, 10 months ago.]
                  • 3749
                  • 24,544 Posts
                  The thing is, getChunk() is not processing the snippet tag. I've made this mistake multiple times. You can't use echo or print to see what's happening because MODX is processing things after that, but before you see them. The only reliable and convenient way to see the actual value of strings at a certain point in the code is to either write it to the error log or to a chunk. I do the second.

                  The NewsPublisher class still has my debugging function, so all you have to do is something like this in that class:

                  $this->my_debug('<br />Tpl: ' . $tpl);


                  Then right-click on the debug chunk and select "Quick Update" to see what's there. Sending true as a second argument to my_debug() will clear the chunk before writing, but don't use it right away because often your code is executing more often than you think it is, so you want to see that.

                  Keep in mind that the field name has many different values as NP does its work, all of which get used for that placeholder (unless your NP form has only one field). In that case you should be able to just hard-code the field name in the Tpl chunk. You could also do that if there is only one field that uses that particular chunk.


                    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