Changeset 457449
- Timestamp:
- 10/30/2011 09:06:20 PM (14 years ago)
- Location:
- preserved-html-editor-markup/trunk
- Files:
-
- 2 edited
-
readme.txt (modified) (3 diffs)
-
sb_preserved_markup.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
preserved-html-editor-markup/trunk/readme.txt
r456532 r457449 1 1 === Preserved HTML Editor Markup === 2 2 Contributors: marcuspope 3 Donate link: http://www. springbox.com/contact/3 Donate link: http://www.marcuspope.com/ 4 4 Tags: wpautop, editor, markup, html, white space, HTML5, WYSIWYG, visual, developer 5 5 Requires at least: 3.2.1 … … 23 23 1. Orphaned text content will not be wrapped in any tag - so you will want to make sure your theme inherently wraps the post content in a div tag (or some other block element) for valid HTML markup. 24 24 25 1. White space is preserved; newlines, spaces and tabs will remain in your markup for the most part. For performance reasons, it will only preserve spaces if 4 spaces are used consecutively - i.e. an expanded tab in developer terms. It will not preserve intra-tag white space like <p >. 25 1. White space is preserved; newlines, spaces and tabs will remain in your markup for the most part. For performance reasons, it will only preserve spaces if 4 spaces are used consecutively - i.e. an expanded tab in developer terms. It will not preserve intra-tag white space like <p >. 26 26 27 There are a couple of bugs in the parsing logic that I'm aware of and I will work to iron them out over the coming weeks. 27 There are a couple of bugs in the parsing logic that I'm aware of and I will work to iron them out over the coming weeks. 28 28 29 29 Known issues: … … 59 59 == Changelog == 60 60 61 = 1.1 = 62 * Refactored for support of < php5.3 by replacing function references with static function array refs 61 63 = 1.0 = 62 64 * Initial creation of plugin -
preserved-html-editor-markup/trunk/sb_preserved_markup.php
r456532 r457449 3 3 /* 4 4 Plugin Name: Preserved HTML Editor Markup 5 Plugin URI: http://www. springbox.com/wordpress/5 Plugin URI: http://www.marcuspope.com/wordpress/ 6 6 Description: A Wordpress Plugin that preserves HTML markup in the TinyMCE editor, especially when switching between 7 7 html and visual tabs. Also adds support for HTML5 Block Anchors. 8 Author: Marcus E. Pope, Springbox.com,marcuspope8 Author: Marcus E. Pope, marcuspope 9 9 Author URI: http://www.marcuspope.com 10 10 Version: 1.0 11 11 12 Copyright 2011 Marcus E. Pope (email : m arcus.pope@springbox.com)12 Copyright 2011 Marcus E. Pope (email : me@marcuspope.com) 13 13 14 14 This program is free software; you can redistribute it and/or modify … … 27 27 */ 28 28 29 add_action('plugins_loaded', array(' SB_WP_Preserved_Markup', 'init'), 1);29 add_action('plugins_loaded', array('MP_WP_Preserved_Markup', 'init'), 1); 30 30 31 class SB_WP_Preserved_Markup { 31 class MP_WP_Preserved_Markup { 32 33 public static function remove_evil() { 34 //remove evil: wpautop will break html5 markup! 35 remove_filter('the_content', 'wpautop'); 36 } 37 38 public static function init_tiny_mce($init) { 39 //Setup tinymce editor with necessary settings for better general editing 40 $tags = "pre[*],iframe[*],object[*],param[*]"; //add pre and iframe to allowable tags for 41 if (isset($init['extended_valid_elements'])) { 42 $tags = $init['extended_valid_elements'] . "," . $tags; 43 } 44 $init['extended_valid_elements'] = $tags; 45 $init['forced_root_block'] = false; //prevent tinymce from wrapping a root block level element (typically a <p> tag) 46 $init['force_p_newlines'] = false; 47 $init['remove_linebreaks'] = false; 48 $init['force_br_newlines'] = true; 49 $init['remove_trailing_nbsp'] = false; 50 $init['relative_urls'] = true; 51 $init['convert_urls'] = false; 52 $init['remove_linebreaks'] = false; 53 $init['doctype'] = '<!DOCTYPE html>'; 54 $init['apply_source_formatting'] = false; 55 $init['convert_newlines_to_brs'] = false; 56 $init['fix_list_elements'] = false; 57 $init['fix_table_elements'] = false; 58 $init['verify_html'] = false; 59 60 /* 61 Allow for html5 anchor tags 62 http://dev.w3.org/html5/markup/a.html 63 http://dev.w3.org/html5/markup/common-models.html#common.elem.phrasing 64 http://www.tinymce.com/wiki.php/Configuration:valid_children 65 */ 66 $init['valid_children'] = "+a[em|strong|small|mark|abbr|dfn|i|b|s|u|code|var|samp|kbd|sup|sub|q|cite|span|bdo|bdi|br|wbr|ins|del|img|embed|object|iframe|map|area|script|noscript|ruby|video|audio|input|textarea|select|button|label|output|datalist|keygen|progress|command|canvas|time|meter|p|hr|pre|ul|ol|dl|div|h1|h2|h3|h4|h5|h6|hgroup|address|blockquote|section|nav|article|aside|header|footer|figure|table|f|m|fieldset|menu|details]"; 67 68 return $init; 69 } 70 71 public static function fix_editor_content($html) { 72 remove_filter('the_editor_content', "wp_richedit_pre"); 73 return $html; 74 } 75 76 public static function content_replace_callback($a) { 77 $s = $a[0]; 78 $s = preg_replace("/(\r\n|\n)/m", '<mep-preserve-nl>', $s); 79 $s = preg_replace("/\t/m", '<mep-preserve-tab>', $s); 80 $s = preg_replace("/\s/m", '<mep-preserve-space>', $s); 81 return $s; 82 } 83 84 public static function fix_wysiwyg_content($c) { 85 //If the page is rendered with the WYSIWYG editor selected by default, content is processed in PHP land 86 //instead of using the JS land "equivalent" logic (I quote equivalent because there are sooooo many 87 //discrepancies between what JS wpautop and PHP wpautop functions do it's laughable. 88 if (wp_default_editor() == "tinymce") { 89 //First we inject temporary whitespace markers in pre and code elements because they won't 90 //be corrupted when the user switches to html mode.* (actually IE9 will remove the first 91 //newline from a pre tag if there are no non-whitespace characters before the newline.) 92 $c = preg_replace_callback( 93 '/<(pre|code)[^>]*>[\s\S]+?<\/\\1>/m', 94 array( 95 'MP_WP_Preserved_Markup', 96 'content_replace_callback' 97 ), 98 $c); 99 100 //Now let's preserve whitespace with html comments so that they can be converted back when switching to 101 //the html mode. FIXME: assuming four spaces is bad mmkay, what if I like only two spaces for a tab? 102 //and this could produce bad markup if a user had <p class="test">hello</p> in their markup. So 103 //work on a more flexible /\s/g approach when \s is inside or outside a tag definition 104 $c = preg_replace("/(\r\n|\n)/", "<!--mep-nl-->", $c); //preserve new lines 105 $c = preg_replace("/(\t|\s\s\s\s)/", "<!--mep-tab-->", $c); //preserve indents 106 107 //Now we can restore all whitespace originally escaped in pre & code tags 108 $c = preg_replace("/<mep-preserve-nl>/m", "\n", $c); 109 $c = preg_replace("/<mep-preserve-tab>/m", "\t", $c); 110 $c = preg_replace("/<mep-preserve-space>/m", " ", $c); 111 112 //finish up with functions that WP normally calls on the_editor_content 113 $c = convert_chars($c); 114 $c = htmlspecialchars($c, ENT_NOQUOTES); 115 } 116 117 return $c; 118 } 119 120 public static function fix_post_content($post) { 121 //If the user clicks save while in the Visual (WYSIWYG) tab, we'll need to strip the whitespace placeholders 122 //before inserting the data into the database to prevent duplication of whitespace 123 //WTF: ok so I ran into a problem of duplicating newlines when saving from the Visual tab, so I added this 124 // code to strip what I thought was my whitespace markers not being converted back in JS land before being 125 // sent to the server. (in the same way that if you load the page on the Visual tab, the parsing logic 126 // occurs on the server instead of the client!) But after add this code I couldn't reproduce the issue 127 // the post_content never contained any mep-xxx comments. I'm leaving this code in here, because it's 128 // the probable explanation for duplicated newlines, but I'm also not sure how the Visual content is 129 // transfered from the iframe to the textarea. 130 if (isset($post['post_content'])) { 131 $post['post_content'] = preg_replace('/<\!--mep-nl-->/m', "\r\n", $post['post_content']); 132 $post['post_content'] = preg_replace('/<\!--mep-tab-->/m', " ", $post['post_content']); 133 } 134 return $post; 135 } 136 137 public static function admin_init() { 138 //Add full attribute support for special tags 139 add_filter( 'tiny_mce_before_init', array( 140 'MP_WP_Preserved_Markup', 141 'init_tiny_mce' 142 )); 143 144 /* fix WP html editor on client side */ 145 wp_enqueue_script('admin-js', WP_PLUGIN_URL.'/'.str_replace(basename( __FILE__),"",plugin_basename(__FILE__))."admin.js"); 146 147 add_filter('the_editor', array( 148 'MP_WP_Preserved_Markup', 149 'fix_editor_content' 150 ), 1); 151 152 add_filter('the_editor_content', array( 153 'MP_WP_Preserved_Markup', 154 'fix_wysiwyg_content' 155 ), 1); 156 157 add_filter('wp_insert_post_data', array( 158 'MP_WP_Preserved_Markup', 159 'fix_post_content' 160 ), 1); 161 } 32 162 33 163 public static function init() { 164 add_action('init', array( 165 'MP_WP_Preserved_Markup', 166 'remove_evil' 167 )); 34 168 35 add_action('init', function() { 36 //remove evil: wpautop will break html5 markup! 37 remove_filter('the_content', 'wpautop'); 38 }); 39 40 add_action('admin_init', function() { 41 42 //Add full attribute support for special tags 43 add_filter( 'tiny_mce_before_init', function($init) { 44 $tags = "pre[*],iframe[*],object[*],param[*]"; //add pre and iframe to allowable tags for 45 if (isset($init['extended_valid_elements'])) { 46 $tags = $init['extended_valid_elements'] . "," . $tags; 47 } 48 $init['extended_valid_elements'] = $tags; 49 $init['forced_root_block'] = false; //prevent tinymce from wrapping a root block level element (typically a <p> tag) 50 $init['force_p_newlines'] = false; 51 $init['remove_linebreaks'] = false; 52 $init['force_br_newlines'] = true; 53 $init['remove_trailing_nbsp'] = false; 54 $init['relative_urls'] = true; 55 $init['convert_urls'] = false; 56 $init['remove_linebreaks'] = false; 57 $init['doctype'] = '<!DOCTYPE html>'; 58 $init['apply_source_formatting'] = false; 59 $init['convert_newlines_to_brs'] = false; 60 $init['fix_list_elements'] = false; 61 $init['fix_table_elements'] = false; 62 $init['verify_html'] = false; 63 64 /* 65 Allow for html5 anchor tags 66 http://dev.w3.org/html5/markup/a.html 67 http://dev.w3.org/html5/markup/common-models.html#common.elem.phrasing 68 http://www.tinymce.com/wiki.php/Configuration:valid_children 69 */ 70 $init['valid_children'] = "+a[em|strong|small|mark|abbr|dfn|i|b|s|u|code|var|samp|kbd|sup|sub|q|cite|span|bdo|bdi|br|wbr|ins|del|img|embed|object|iframe|map|area|script|noscript|ruby|video|audio|input|textarea|select|button|label|output|datalist|keygen|progress|command|canvas|time|meter|p|hr|pre|ul|ol|dl|div|h1|h2|h3|h4|h5|h6|hgroup|address|blockquote|section|nav|article|aside|header|footer|figure|table|f|m|fieldset|menu|details]"; 71 72 return $init; 73 }); 74 75 /* fix WP html editor */ 76 wp_enqueue_script('admin-js', WP_PLUGIN_URL.'/'.str_replace(basename( __FILE__),"",plugin_basename(__FILE__))."admin.js"); 77 78 add_filter('the_editor', function($html) { 79 remove_filter('the_editor_content', "wp_richedit_pre"); 80 return $html; 81 }, 1); 82 83 add_filter('the_editor_content', function($c) { 84 //If the page is rendered with the WYSIWYG editor selected by default, content is processed in PHP land 85 //instead of using the JS land "equivalent" logic (I quote equivalent because there are sooooo many 86 //discrepancies between what JS wpautop and PHP wpautop functions do it's laughable. 87 if (wp_default_editor() == "tinymce") { 88 //First we inject temporary whitespace markers in pre and code elements because they won't 89 //be corrupted when the user switches to html mode.* (actually IE9 will remove the first 90 //newline from a pre tag if there are no non-whitespace characters before the newline.) 91 $c = preg_replace_callback('/<(pre|code)[^>]*>[\s\S]+?<\/\\1>/m', function($a) { 92 $s = $a[0]; 93 $s = preg_replace("/(\r\n|\n)/m", '<mep-preserve-nl>', $s); 94 $s = preg_replace("/\t/m", '<mep-preserve-tab>', $s); 95 $s = preg_replace("/\s/m", '<mep-preserve-space>', $s); 96 return $s; 97 }, $c); 98 99 //Now let's preserve whitespace with html comments so that they can be converted back when switching to 100 //the html mode. FIXME: assuming four spaces is bad mmkay, what if I like only two spaces for a tab? 101 //and this could produce bad markup if a user had <p class="test">hello</p> in their markup. So 102 //work on a more flexible /\s/g approach when \s is inside or outside a tag definition 103 $c = preg_replace("/(\r\n|\n)/", "<!--mep-nl-->", $c); //preserve new lines 104 $c = preg_replace("/(\t|\s\s\s\s)/", "<!--mep-tab-->", $c); //preserve indents 105 106 //Now we can restore all whitespace originally escaped in pre & code tags 107 $c = preg_replace("/<mep-preserve-nl>/m", "\n", $c); 108 $c = preg_replace("/<mep-preserve-tab>/m", "\t", $c); 109 $c = preg_replace("/<mep-preserve-space>/m", " ", $c); 110 111 //finish up with functions that WP normally calls on the_editor_content 112 $c = convert_chars($c); 113 $c = htmlspecialchars($c, ENT_NOQUOTES); 114 } 115 116 return $c; 117 }, 1); 118 119 add_filter('wp_insert_post_data', function($post) { 120 //If the user clicks save while in the Visual (WYSIWYG) tab, we'll need to strip the whitespace placeholders 121 //before inserting the data into the database to prevent duplication of whitespace 122 //WTF: ok so I ran into a problem of duplicating newlines when saving from the Visual tab, so I added this 123 // code to strip what I thought was my whitespace markers not being converted back in JS land before being 124 // sent to the server. (in the same way that if you load the page on the Visual tab, the parsing logic 125 // occurs on the server instead of the client!) But after add this code I couldn't reproduce the issue 126 // the post_content never contained any mep-xxx comments. I'm leaving this code in here, because it's 127 // the probable explanation for duplicated newlines, but I'm also not sure how the Visual content is 128 // transfered from the iframe to the textarea. 129 if (isset($post['post_content'])) { 130 $post['post_content'] = preg_replace('/<\!--mep-nl-->/m', "\r\n", $post['post_content']); 131 $post['post_content'] = preg_replace('/<\!--mep-tab-->/m', " ", $post['post_content']); 132 } 133 return $post; 134 }, 1); 135 }); 169 add_action('admin_init', array( 170 'MP_WP_Preserved_Markup', 171 'admin_init' 172 )); 136 173 } 137 174 }
Note: See TracChangeset
for help on using the changeset viewer.