{"id":59,"date":"2005-06-23T10:02:39","date_gmt":"2005-06-23T00:02:39","guid":{"rendered":"http:\/\/www.thunderguy.com\/semicolon\/wordpress\/safe-title-wordpress-plugin\/"},"modified":"2006-11-25T19:17:21","modified_gmt":"2006-11-25T09:17:21","slug":"safe-title-wordpress-plugin","status":"publish","type":"page","link":"https:\/\/thunderguy.com\/semicolon\/wordpress\/safe-title-wordpress-plugin\/","title":{"rendered":"Safe Title: a WordPress plugin"},"content":{"rendered":"<p><em>Latest version is 0.1.<\/em><\/p>\n<p>Safe Title is a <a href=\"http:\/\/wordpress.org\/\">WordPress<\/a> plugin that allows you to use HTML in post titles in the default WordPress theme.<\/p>\n<p><strong>Warning<\/strong>: You probably don&#8217;t need to use this plugin. It&#8217;s more an interesting technical experiment than a useful addition to the WordPress canon. Please read the notes below.<\/p>\n<p>When posting to your WordPress blog, sometimes you just want to use HTML in the title. You want to make some words stand out with <span style=\"color:red\">color<\/span>, or use <i>italics<\/i> or a <code>code<\/code> font. (Here&#8217;s an <a href=\"\/semicolon\/2003\/08\/14\/java-sql-date-is-not-a-real-date\/\">example of an HTML post title<\/a> on this very website.)<\/p>\n<p>Sadly, the default theme included with WordPress 1.5 can&#8217;t handle this; it fails to strip HTML tags from the title when it appears inside an HTML attribute, and you end up with a deformed post title. I initially solved this problem by creating a special template tag that strips tags from the title, but this meant I had to edit my theme to use the new tag. Wouldn&#8217;t it be nicer to create a plugin that would do it automatically, thus magically &#8220;fixing&#8221; the default theme?<\/p>\n<p>I amused myself by finding a way to do it. It&#8217;s easy to add a filter to <code>the_title<\/code> to strip the tags. The hard part is when the filter has to decide whether to actually strip the tags or not. It only needs to do it if it&#8217;s being used inside an HTML attribute, but the filter callback does not receive any context to help it decide.<\/p>\n<p>So we create some context for it. Turn on output buffering at the top of the page (using an action hook). Then the filter can look at the output buffer to see whether it&#8217;s being used inside an attribute. The rest is simple.<\/p>\n<p>The beauty of this idea is that it&#8217;s completely automatic &#8212; just enable the plugin. No theme changes required.<\/p>\n<p>The ugliness of this idea is that it&#8217;s probably terribly inefficient and may break other plugins that mess around with output buffering. But I find the &#8220;sledgehammer vs. peanut&#8221; approach quite amusing.<\/p>\n<p>And it&#8217;s a great illustration of how flexible WordPress is.<\/p>\n<h2>Compatibility<\/h2>\n<p>Safe Titla was developed with WordPress 1.5, but is not robust due to problems with the WordPress hooks.<\/p>\n<h3>Installation<\/h3>\n<ol>\n<li>Download the safe-title.php file (see the <a href=\"#download\">end<\/a> of this article for download location)<\/li>\n<li>Copy safe-title.php into your WordPress plugins directory (wp-content\/plugins).<\/li>\n<li>Log in to WordPress Admin. Go to the Plugins page and click Activate for Safe Title<\/li>\n<li>That&#8217;s all<\/li>\n<\/ol>\n<p>Here&#8217;s the code from the plugin:<\/p>\n<pre class=\"code\"><code>\/\/ Turn on output buffering \r\nadd_action('wp_head', 'tguy_st_ob_start');\r\n\r\n\/\/ Strip the title if it's inside a tag\r\nadd_filter('the_title', 'tguy_st_strip_if_in_tag', 10, 3);\r\n\r\nfunction tguy_st_ob_start() {\r\n    ob_start();\r\n}\r\n\r\nfunction tguy_st_strip_if_in_tag($title_wrapped, $before, $after) {\r\n\/*\tStrip HTML tags from the title if it's already inside a tag.\r\n*\/\r\n    $title = substr($title_wrapped, strlen($before), strlen($title_wrapped) - strlen($before) - strlen($after));\r\n    $title_stripped = strip_tags($title);\r\n    if ($title != $title_stripped) {\r\n        \/\/ Title has html tags\r\n        if (preg_match('\/&lt;[^&gt;]*$\/', ob_get_contents())) {\r\n            \/\/ We're inside a tag. Return the stripped title\r\n            return $before . $title_stripped . $after;\r\n        }\r\n    }\r\n    return $title_wrapped;\r\n}<\/code><\/pre>\n<p>I&#8217;d love to hear any comments on this approach. The idea of peeking into the output buffer is overkill for this plugin, but it could be a useful way of solving more complex problems.<\/p>\n<h2><a id=\"download\"><\/a>Download<\/h2>\n<p>You can download <a href=\"http:\/\/semi-wp-plugins.svn.sourceforge.net\/viewvc\/*checkout*\/semi-wp-plugins\/misc\/branches\/current\/safe-title.php\">safe-title.php<\/a> or view the <a href=\"http:\/\/semi-wp-plugins.svn.sourceforge.net\/viewvc\/semi-wp-plugins\/misc\/branches\/current\/safe-title.php?view=markup\">source code<\/a>. Don&#8217;t forget to check out all the other plugins available here &#8212; there&#8217;s bound to be one that you will find useful.<\/p>\n<p>I write these WordPress plugins because I enjoy doing it, but it does take up a lot\r\nof my time. If you think this plugin is useful, please consider donating some appropriate\r\namount.<\/p>\r\n\r\n<div style=\"float: left; padding: 0.25em 1em 0.5em 0; margin: 1em 0 0 0;\">\r\n<form action=\"https:\/\/www.paypal.com\/cgi-bin\/webscr\" method=\"post\">\r\n<div>\r\n<input type=\"hidden\" name=\"cmd\" value=\"_s-xclick\" \/>\r\n<input type=\"image\" src=\"https:\/\/www.paypal.com\/en_US\/i\/btn\/x-click-but04.gif\" style=\"border:none\" name=\"submit\" alt=\"Make payments with PayPal - it's fast, free and secure!\" \/>\r\n<input type=\"hidden\" name=\"encrypted\" value=\"-----BEGIN PKCS7-----MIIHXwYJKoZIhvcNAQcEoIIHUDCCB0wCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYA7BglQn0K1FJvdqm+zAop0IFZb02mJnn56wpZYpbqWE6go360iySXAwUS8eMEMSxp2\/OUmWh6VQzm07kEP0buqLG0wwi4yOwawTYB2cahVUPadwYA+KyE78xQI4plMGO1LRchjNdVPkjFuD5s0K64SyYOwtCPYOo\/Xs1vZPbpH\/zELMAkGBSsOAwIaBQAwgdwGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIP5kNv+75+iKAgbhN2BQBAd0BiS1W5qaECVs\/v8Jqdoe\/SVb+bykh9HucP\/8+tYncHVffnDf0TAMxdjlQT65QdNc8T8FGDDhQZN8BwWx2kUwFgxKPBlPvL+KFWcu50jrBsyFsK9zLM260ZR6+aA9ZBdgtMKwCBk\/38bo6LmUtZ5PM+LSfJRh3HtFoUKgGndaDYl\/9N4vhK2clyt0DaQO3Mum8DTXwb57Aq8pjQPwsUzWl3OqZdZEI+YXJX4xxQIHkKAsSoIIDhzCCA4MwggLsoAMCAQICAQAwDQYJKoZIhvcNAQEFBQAwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMB4XDTA0MDIxMzEwMTMxNVoXDTM1MDIxMzEwMTMxNVowgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBR07d\/ETMS1ycjtkpkvjXZe9k+6CieLuLsPumsJ7QC1odNz3sJiCbs2wC0nLE0uLGaEtXynIgRqIddYCHx88pb5HTXv4SZeuv0Rqq4+axW9PLAAATU8w04qqjaSXgbGLP3NmohqM6bV9kZZwZLR\/klDaQGo1u9uDb9lr4Yn+rBQIDAQABo4HuMIHrMB0GA1UdDgQWBBSWn3y7xm8XvVk\/UtcKG+wQ1mSUazCBuwYDVR0jBIGzMIGwgBSWn3y7xm8XvVk\/UtcKG+wQ1mSUa6GBlKSBkTCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb22CAQAwDAYDVR0TBAUwAwEB\/zANBgkqhkiG9w0BAQUFAAOBgQCBXzpWmoBa5e9fo6ujionW1hUhPkOBakTr3YCDjbYfvJEiv\/2P+IobhOGJr85+XHhN0v4gUkEDI8r2\/rNk1m0GA8HKddvTjyGw\/XqXa+LSTlDYkqI8OwR8GEYj4efEtcRpRYBxV8KxAW93YDWzFGvruKnnLbDAF6VR5w\/cCMn5hzGCAZowggGWAgEBMIGUMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbQIBADAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMDYwMjA3MTEyOTQ5WjAjBgkqhkiG9w0BCQQxFgQUO31wm3aCiCMdh2XIXxIAeS8LfBIwDQYJKoZIhvcNAQEBBQAEgYB3CtAsDm+ZRBkd\/XLEhUx0IbaeyK9ymOT8R5EQfSZnoJ+QP05XWBc8zi21wSOiQ8nH9LtN2MtS4GRBAQFU1vbvGxw6bG2gJfggJ1pDPUOtkFgf1YA8At+m2I6G2E+YWx2\/QHdfMo3BpTJWQOUka52wjuTmIX9X6+CFMPokF91f0w==-----END PKCS7-----\r\n\" \/>\r\n<\/div>\r\n<\/form>\r\n<\/div>\r\n<p>Click here to donate using a credit card or PayPal.<\/p>\r\n\r\n<p style=\"clear:left\">\r\n<img decoding=\"async\" src=\"http:\/\/www.thunderguy.com\/semicolon\/wp\/wp-content\/uploads\/2011\/06\/BC_Rnd_32px.png\" style=\"float: left; padding: 0.25em 1em 0.5em 0; margin: 0;\" \/>\r\nSend <a href=\"http:\/\/bitcoin.org\/\">Bitcoins<\/a> to address<br \/>\r\n<tt>1542gqyprvQd7gwvtZZ4x25cPeGWVKg45x<\/tt><\/p>\r\n<h2>Full WordPress plugin list<\/h2>\n<ul class=\"plugin-list\">\n\r\n\t\r\n\t<!--\r\n\tchild_of=47&title_li=&sort_column=post_title\r\n\t-->\r\n\t\r\n\t<li class=\"page_item\"><a href=\"https:\/\/thunderguy.com\/semicolon\/wordpress\/code-markup-wordpress-plugin\/\" title=\"Code Markup: a WordPress plugin\">Code Markup<\/a> &#8212; Quickly paste code samples into your posts -- you can even include HTML markup in the code sample.<\/li>\r\n<li class=\"page_item\"><a href=\"https:\/\/thunderguy.com\/semicolon\/wordpress\/evermore-wordpress-plugin\/\" title=\"Evermore: a WordPress plugin\">Evermore<\/a> &#8212; Automatically display a short preview of your posts on the home page and other multiple-post pages, along with a link to the full post.<\/li>\r\n<li class=\"page_item\"><a href=\"https:\/\/thunderguy.com\/semicolon\/wordpress\/fixback-wordpress-plugin\/\" title=\"FixBack: a WordPress plugin\">FixBack<\/a> &#8212; Ensure trackbacks and pingbacks are sent with the correct link back to your blog.<\/li>\r\n<li class=\"page_item\"><a href=\"https:\/\/thunderguy.com\/semicolon\/wordpress\/less-wordpress-plugin\/\" title=\"Less: a WordPress plugin\">Less<\/a> &#8212; Less is no more. It has been renamed to Seemore and moved to its own <a href=\"http:\/\/www.thunderguy.com\/semicolon\/wordpress\/seemore-wordpress-plugin\/\">Seemore plugin page<\/a>.<\/li>\r\n<li class=\"page_item\"><a href=\"https:\/\/thunderguy.com\/semicolon\/wordpress\/plaintext-wordpress-plugin\/\" title=\"Plaintext: a WordPress plugin\">Plaintext<\/a> &#8212; Allow your readers to download source files (e.g. PHP, HTML, ASP) as plain text.<\/li>\r\n<li class=\"page_item current_page_item\"><a href=\"https:\/\/thunderguy.com\/semicolon\/wordpress\/safe-title-wordpress-plugin\/\" title=\"Safe Title: a WordPress plugin\">Safe Title<\/a> &#8212; Use HTML in post titles in the default WordPress theme (or any other theme).<\/li>\r\n<li class=\"page_item\"><a href=\"https:\/\/thunderguy.com\/semicolon\/wordpress\/search-meter-wordpress-plugin\/\" title=\"Search Meter: a WordPress plugin\">Search Meter<\/a> &#8212; Find out what people are searching for on your blog, so you can write what your visitors want to read.<\/li>\r\n<li class=\"page_item\"><a href=\"https:\/\/thunderguy.com\/semicolon\/wordpress\/seemore-wordpress-plugin\/\" title=\"Seemore: a WordPress plugin\">Seemore<\/a> &#8212; Change the (more...) link so it jumps to the full post, not just the part after the link.<\/li>\r\n<li class=\"page_item\"><a href=\"https:\/\/thunderguy.com\/semicolon\/wordpress\/top-cat-wordpress-plugin\/\" title=\"Top Cat: a WordPress plugin\">Top Cat<\/a> &#8212; Specify a main category for your posts, and use template tags to display posts differently according to their main category.<\/li>\r\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Latest version is 0.1. Safe Title is a WordPress plugin that allows you to use HTML in post titles in the default WordPress theme. Warning: You probably don&#8217;t need to use this plugin. It&#8217;s more an interesting technical experiment than a useful addition to the WordPress canon. Please read the notes below. When posting to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":47,"menu_order":0,"comment_status":"open","ping_status":"open","template":"page-wp-plugin.php","meta":{"footnotes":""},"class_list":["post-59","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/pages\/59","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/comments?post=59"}],"version-history":[{"count":0,"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/pages\/59\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/pages\/47"}],"wp:attachment":[{"href":"https:\/\/thunderguy.com\/semicolon\/wp-json\/wp\/v2\/media?parent=59"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}