We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 26435
    • 1,193 Posts
    it’s 2007, and I FINALLY have time to look at this stuff!
    phew!

    Uh... the header thing... I forgot about that, and It was supposed to be commented out, but now I don’t know if it is necessary or not.

    michalc, you seem to be fairly brushed up on this stuff, so I am going to wait for further recommendations from you before proceeding, but would it be more efficient, with less code overhead to remove the php header? I am thinking about this, and It seems like the header might be necessary, but I don’t know if onWebPagePrerender is the right trigger for it now. I will have to see when the document parser sends the header and then issue the header call right after that.

    I apologize for my short tone, it is not your fault, and you are not asking too many questions or asking irritating questions. Quite the opposite, you are asking all the right questions for this plugin. I respect that you want to make this function as well as it can for the MODx community that chooses to use it. I just finished a 77 hour work week! and I am looking forward to some time off (the next 6 days... yay!). That’s no excuse for my tone, but I definitely had some pressing issues that were demanding my attention, and I could not fully appreciate what you were trying to say until now. You were right. I was wrong. Thank you for leading me to revisit this issue. I am sure between the two of us (and whoever else wants to contribute), we can get this working really reliably.

    -sD-
    Dr. Scotty Delicious, Scientist.
      Husband, Father, Brother, Son, Programmer, Atheist, Nurse, Friend, Lover, Fighter.
      All of the above... in no specific order.


      I send pointless little messages
      • 19315
      • 84 Posts
      It’s all ok. Perhaps if I had mentioned what part of the code I was referring to in my first post, this all could have been cleared up much sooner!

      I’m unsure about what the best thing to do is. However, I will try to come up with a recommendation for comment.
      would it be more efficient, with less code overhead to remove the php header

      I don’t really know about how much overhead the header call makes compared to the string replacement, but to me it seems to make more sense to have the php header call, and to (possibly) remove the string replacement in the document, for a few reasons:

      • I did hint above, but it does seem that the string replacement will change all "text/html" in the document to "application/xhtml+xml", but I’m unsure what the state of the document is in when OnWebPagePrerender is triggered. Perhaps a search to limit it to the head section would be better. However, unless it is a quite sophisticated search I do worry that there will be some, perhaps obscure, case where it will change text in the document content. I don’t really know about regular expressions so I am guessing. This would also have to cover RSS/Atom feeds, and be sure that it doesn’t change text in them either.
      • (I’m assuming here that the str_replace is to change the mime http-equiv tag). According to the HTML 4.01 specs, I think that the character encoding in the HTTP header takes precedence over the character encoding in a meta http-equiv tag. However, I couldn’t find any info on what precedence there is for MIME type for XHTML, but I would guess its the HTTP header. I think MODx sends the MIME type, with encoding type, in the HTTP header anyway, so I would think to be safe this should always be changed to the appropriate type.
      • I hinted above that if the HTTP header sends the MIME type and encoding, then it seems the meta http-equiv tag is a bit superfluous. At least the W3C validator doesn’t complain about any of my pages that don’t have a http-equiv.
      A possible argument against doing this, as you mention, is to make sure that somewhere else in MODx doesn’t set the HTTP header after the header call in this plugin. I have tested the code I suggested previously, with only a header call, and no string replacement, and it seems to work. However, obviously this could be a special case and some other setup may not work. I don’t know whether my suggested setup is safe in this respect.

      Another issue, that hasn’t been mentioned really, is the hard coding of the encoding type (UTF-8 for example). This is a short plugin, so it would be easy for people to change the encoding if they want, but it would break if it were updated. I was thinking that perhaps it should be an parameter to the plugin, but looking at the docs at http://modxcms.com/modx-tags.html , there is a tag [(etomite_charset)], that perhaps could be used? Putting all this together, my suggested code is:

      $event = &$modx->Event;
      switch ($event->name) {
      	case "OnWebPagePrerender":
      	$charset = "[(etomite_charset)]";
              $browserAcceptsXHTMLMIME = stristr($_SERVER['HTTP_ACCEPT'], 'application/xhtml+xml');
              $documentIsXHTML = $modx->documentObject['contentType']=="text/html";
      	if ($documentIsXHTML && $browserAcceptsXHTMLMIME) {
      		header("Content-type: application/xhtml+xml; ".$charset);
      	}
      	break;
      
      	default:
      	return;
      	break;
      }

      (I have only tested a modified version of this code, as I currently use a different setup where all my pages are set as application/xhtml+xml in the manager, as I mentioned earlier). This code would also perhaps be coupled with a recommendation to remove the meta http-equiv tag from templates. One thing: I notice the default templates for MODx include a meta http-equiv content-type tag, so perhaps there is a reason for having them that I am unaware of.

      There is something else that is now crossing my mind. I said earlier that my suggested code for my setup was not presented as a fix to the plugin, however what about having it included, but only activated if a particular parameter is set? Thus in one "mode", the default, the plugin would convert types "text/html"->"application/xhtml+xml" when required, and in the other "mode" the plugin would convert "application/xhtml+xml" to "text/html" when required. However I fear this is perhaps needlessly overcomplicating the issue.

      Michal.
        • 26435
        • 1,193 Posts
        Michal,
        Maybe the second option is what we should be focusing on.
        As web developers, we could set all our xhtml pages to be served with a custom content type of "application/xhtml+xml" in the manager, then using this plugin, we could check to see if the browser can handle that content type, and if not, send a " header("Content-type: text/html"); "
        //<?php
        /**
         * @package		xhtml+xml plugin for modx
         *
         * serves page as 'application/xhtml+xml' if the browser can 
         * accept the mimetype, otherwise, defaults to 'text/html'
         *
         * PHP versions 4 and 5
         *
         * LICENSE: GPL [ http://www.gnu.org/copyleft/gpl.html ]
         *
         * @category   MODx Plugin
         * @package    xhtml+xml
         * @author     Scotty Delicious <[email protected]>
         * @author     Michal C <_@_._>
         * @copyright  2006 Scotty Delicious: Fine Pirate Rock Music.
         * @license    http://www.gnu.org/copyleft/gpl.html GPL Version 2, June 1991
         * @version    1.1
         * @link       http://modxcms.com/PLUGIN-applicationxhtmlxml-1.0-1239.html
         * @see        http://scottydelicious.com
         * @since      File available since Release 1.0
         * @deprecated N/A
         */
        
        /**
         * @install		Copy this to a new plugin and set System Event to
         *				onWebPagePrerender.
         */
        
        // if the MODx Document has a custom content type of "application/xhtml+xml",
        if ($modx->documentObject['contentType'] == "application/xhtml+xml") {
        	
        // and browser cannot handle xhtml+xml mime type
            if(!stristr($_SERVER['HTTP_ACCEPT'],'application/xhtml+xml')){
        	
        // then send the text/html header, otherwise, serve as intended.
                header("Content-type: text/html");
                // we could do a string replace here too, but after some testing,
         		// it does not appear am that it is needed.
            }
        }
        


        What do you think?
        if you wouldn’t mind appending your info in the 2nd @author tag michal, then I could get this posted in the repository.

        -sD-
        Dr. Scotty Delicious, Scientist.
          Husband, Father, Brother, Son, Programmer, Atheist, Nurse, Friend, Lover, Fighter.
          All of the above... in no specific order.


          I send pointless little messages
          • 19315
          • 84 Posts
          Hi,

          This seems all fine. I’m not that familar with plugins though: should there still be a test on what event triggered the plugin code?

          Also, I think that the character encoding should also be in the header. I think this is necessary if there is no meta http-equiv tag. I realised the code I posted earlier was incorrect. Firstly I missed a "; charset=" from the header, and secondly I didn’t realise the [( )] tags was not processed, and "[(etomite_charset)]" was actually sent to the browser in the HTTP header. Looking in the documentParser source, and with a bit of testing, I think something like the following work should work fine:
          //<?php
          /**
           * @package		xhtml+xml plugin for modx
           *
           * serves page as 'application/xhtml+xml' if the browser can 
           * accept the mimetype, otherwise, defaults to 'text/html'
           *
           * PHP versions 4 and 5
           *
           * LICENSE: GPL [ http://www.gnu.org/copyleft/gpl.html ]
           *
           * @category   MODx Plugin
           * @package    xhtml+xml
           * @author     Scotty Delicious <[email protected]>
           * @author     Michal Charemza <[email protected]>
           * @copyright  2006 Scotty Delicious: Fine Pirate Rock Music.
           * @license    http://www.gnu.org/copyleft/gpl.html GPL Version 2, June 1991
           * @version    1.1
           * @link       http://modxcms.com/PLUGIN-applicationxhtmlxml-1.0-1239.html
           * @see        http://scottydelicious.com
           * @since      File available since Release 1.0
           * @deprecated N/A
           */
          
          /**
           * @install		Copy this to a new plugin and set System Event to
           *				onWebPagePrerender.
           */
          
          // if the MODx Document has a custom content type of "application/xhtml+xml",
          if ($modx->documentObject['contentType'] == "application/xhtml+xml") {
          	
          // and browser cannot handle xhtml+xml mime type
              if(!stristr($_SERVER['HTTP_ACCEPT'],'application/xhtml+xml')){
          	
          // then send the text/html header, otherwise, serve as intended.
                  $charset = $modx->config['modx_charset'];
                  header("Content-type: text/html; charset=".$charset);
                  // we could do a string replace here too, but after some testing,
           		// it does not appear am that it is needed.
              }
          }

          I don’t know if there is a better way to get at the charset, but $modx->config[’modx_charset’] seems to work.
            • 26435
            • 1,193 Posts
            No dude... that is the perfect way to get the charset!
            nice work. I will update the repository with this (version1.1)

            as for the sytem event’s, onWebPagePrerender is going to be the best choice as it is the last system event before the document parser’s outputContent echoes the final documentOutput. Since the whole document being rendered is wrapped in an "ob" object the last thing that happens after OnWebPagePrerender is
            echo $this->documentOutput;


            So, I think we should leave it there to make sure it is not overruled by any other events.

            -sD-
            Dr. Scotty Delicious, Scientist.
              Husband, Father, Brother, Son, Programmer, Atheist, Nurse, Friend, Lover, Fighter.
              All of the above... in no specific order.


              I send pointless little messages
              • 26435
              • 1,193 Posts
              Ok, updated to version 1.1 in the repository!
              Nice work Michal.

              -sD-
              Dr. Scotty Delicious, Scientist.
                Husband, Father, Brother, Son, Programmer, Atheist, Nurse, Friend, Lover, Fighter.
                All of the above... in no specific order.


                I send pointless little messages
                • 19315
                • 84 Posts
                I’ve actually just been looking into this again, and it looks like the issue is more complicated than just the http header: http://www.w3.org/International/tutorials/tutorial-char-enc/#Slide0250. From this I gather that, for XHTML documents (that is, with an XHTML doctype):

                - Specifying character encoding in the http header is not necessary (but you can)
                - For XHTML served as an XML MIME type (such as application/xhtml+xml), the XML declaration *should* be used , and the meta http-equiv tag *should not* be used
                - For XHTML served as text/html, the XML declaration is not necessary (and it will have undesirable effects in some user agents, i.e. break IE, so I think it’s a bad idea), and the meta http-equiv tag *should* be used.

                Thus, (I think!) that to adhere to the W3C recommendations (and to avoid problems with IE), the XML declaration/prologue should be used when, and only when, the document is served as XML, and the meta http-equiv tag should be used when, and only when, the document is served as text/html. Thus I have written two short snippets that I now include in templates. Note that they both use the custom content type of application/xhtml+xml set in the manager for the documents to be served as application/xhtml+xml to compliant browsers. The first to be used at the very top before the DOCTYPE:
                <?php
                $docIsXHTML = ($modx->documentObject['contentType'] == "application/xhtml+xml");
                $userCanHandleXHTML = (stristr($_SERVER['HTTP_ACCEPT'],'application/xhtml+xml'));
                $charset = $modx->config['modx_charset'];
                
                $output = "";
                
                if ($docIsXHTML && $userCanHandleXHTML) {
                  $output = '<?xml version="1.0" encoding="'.$charset.'"?>';
                }
                
                return $output;
                ?>


                The second is used at the very top of the head section:
                <?php
                $docIsXHTML = ($modx->documentObject['contentType'] == "application/xhtml+xml");
                $userCanHandleXHTML = (stristr($_SERVER['HTTP_ACCEPT'],'application/xhtml+xml'));
                $charset = $modx->config['modx_charset'];
                
                $output = "";
                
                if (($docIsXHTML && !$userCanHandleXHTML) || !$docIsXHTML) {
                  $output .= '<meta http-equiv="Content-Type" content="text/html; charset='.$charset.'" />';  
                }
                
                return $output;
                ?>


                *However* this is still not the end of the story! To specify the language of the page the situation is more complex: http://www.w3.org/TR/i18n-html-tech-lang/#ri20040429.092928424. I think that if the doc is served as an XML type, then only the xml:lang attribute should be used. However, if it is served as text/html, then both the xml:lang and lang attributes should be used. Thus I have quickly written a 3rd snippet, to be used in the html tag (or any other tag that you want to specify the language of). The parameter "lang" is the official code of the language (e.g. "en" for English).
                <?php
                // Parameters to snippet call
                $lang = isset($lang) ? $lang : "";
                
                // Determine user capabilities and page type
                $userCanHandleXHTML = (stristr($_SERVER['HTTP_ACCEPT'],'application/xhtml+xml'));
                $docIsXHTML = ($modx->documentObject['contentType'] == "application/xhtml+xml");
                
                // Always include XML language declaration
                $output = 'xml:lang="'.$lang.'" ';
                
                // Only include html language attribute if the document is not served as XHTML
                if (!$docIsXHTML || !$userCanHandleXHTML) {
                 $output = $output.'lang="'.$lang.'"';
                }
                
                return $output;
                ?>


                What do people think? Have I got through the W3C recommendations correctly? Should these maybe be placed in the extras for the plugin? By the way... I just had a peek at the source of the MODx home page and I don’t think it specifies the language at all... ;-)

                Michal.

                EDIT: Corrected mistakes in snippets
                  • 19315
                  • 84 Posts
                  As another small note, the W3C homepage serves its XHTML as application/xhtml+xml (at least to Firefox), but uses the meta http-equiv tag, and uses both xml:lang and the lang attributes. It doesn’t even follow its own recommendations!

                  Michal.
                    • 9564
                    • 13 Posts
                    First, I’d like to thank you for that script. It solved a lot of problems.

                    While I need some more changes to the header of any document, depending on the DOCTYPE, I used chunks, inserted a str_replace() to your code and added the system-event "OnLoadWebDocument" to get the changed string parsed.

                    I’d like to reference style elements when serving as XML like mentioned in the XHTML 1.0 spec.
                    In this case it’s the best way to me, to replace the whole header, having a placeholder for it in the template.

                    First I tried without checking the event and just run the script once on "OnLoadWebDocument", but that would surpress the header. Here is your modified xhtml+xml script as it worked for me, using MODx 0.9.6.1B:
                    <?php
                    //<?php
                    /**
                     * @package		xhtml+xml plugin for modx
                     *
                     * serves page as 'application/xhtml+xml' if the browser can 
                     * accept the mimetype, otherwise, defaults to 'text/html'
                     *
                     * PHP versions 4 and 5
                     *
                     * LICENSE: GPL [ http://www.gnu.org/copyleft/gpl.html ]
                     *
                     * @category   MODx Plugin
                     * @package    xhtml+xml
                     * @author     Scotty Delicious <[email protected]>
                     * @author     Michal Charemza <[email protected]>
                     * @author     Thomas Heuer <[email protected]>
                     * @copyright  2006 Scotty Delicious: Fine Pirate Rock Music.
                     * @license    http://www.gnu.org/copyleft/gpl.html GPL Version 2, June 1991
                     * @version    1.1
                     * @link       http://modxcms.com/PLUGIN-applicationxhtmlxml-1.0-1239.html
                     * @seehttp://scottydelicious.com
                     * @since      File available since Release 1.0
                     * @deprecated N/A
                     */
                    
                    /**
                     * @install		Copy this to a new plugin and set System Event to
                     *				onWebPagePrerender.
                     */
                    
                    // if the MODx Document has a custom content type of "application/xhtml+xml",
                    if ($modx->documentObject['contentType'] == "application/xhtml+xml")
                    {
                    	// and browser cannot handle xhtml+xml mime type
                    	if(!stristr($_SERVER['HTTP_ACCEPT'],'application/xhtml+xml'))
                    	{
                    		$event = &$modx->Event;
                    		switch ($event->name)
                    		{
                    			case "OnLoadWebDocument":
                    				// insert old-fashioned html-header; using chunks
                    				$modx->documentContent = str_replace('{{xml_header}}', '{{html_header}}', $modx->documentContent);
                    				break;
                    			case "OnWebPagePrerender":
                    				// then send the text/html header, otherwise, serve as intended.
                    				$charset = $modx->config['modx_charset'];
                    				header("Content-type: text/html; charset=".$charset);
                    				// we could do a string replace here too, but after some testing,
                    				// it does not appear am that it is needed.
                    				break;
                    		}
                    	}
                    }
                    ?>


                    These are my (shortened) headers, saved as chunks; while the template starts with "{{xml_header}}".
                    {{html_header}}:
                    <?xml version="1.0" ?>
                    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
                    <html xmlns="http://www.w3.org/1999/xhtml">
                    <head>
                    	<title>[*pagetitle*] - [(site_name)]</title>
                    	<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
                    
                    	<link rel="stylesheet" href="/assets/templates/orange/screen.css" type="text/css" media="screen, projection" />
                    </head>
                    

                    {{xml_header}}:
                    <?xml version="1.0" encoding="UTF-8"?>
                    <?xml-stylesheet href="/assets/templates/orange/screen.css" type="text/css" media="screen, projection"?>
                    
                    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
                    	"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
                    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" >
                    <head>
                    	<title>[*pagetitle*] - [(site_name)]</title>
                    </head>
                    


                    The only thing, I’m not sure about is, whether I need the META-tag for content-type and charset, because this is already done by HTTP-headers or XML declaration (which includes the encoding declaration). See also: XHTML Media Types and RFC3023.

                    Comments are welcome,

                    Thomas