Updated Vpatch: Add Embeddable Codeblocks and Server-Side Select Mechanism

May 14th, 2020

UPDATE 2020/5/18: When I first published this patch I forgot to include the change to the root .htaccess file. This has been fixed and the links below now point to the updated patch.

UPDATE 2020/5/24: CSS change to force the hash in the meta line to wrap.

See below for the updated embeddable codeblocks patch. This is the third iteration after the first two discussions. This patch also now contains the server-side select mechanism, including the updates to xmlrpc.php. The functionality is included in what is now the MP-WP Content Processing plugin1 so it will work across all themes without modification.

You can grab the patch from the links below or from my code shelf.

mp-wp_add-embeddable-codeblocks-and-server-side-selection.vpatch
mp-wp_add-embeddable-codeblocks-and-server-side-selection.vpatch.billymg.sig

1 diff -uNr a/mp-wp/.htaccess b/mp-wp/.htaccess
2 --- a/mp-wp/.htaccess 23164212887a9fa35d330f33bce2c3b96604e7331b79f2a0de7f8b845556cc06bc5fbee0b01b16e026461aa92302f92d971fbd39ec267528a65c421684226688
3 +++ b/mp-wp/.htaccess 1794794b2197805ec99a93d1e3269d6095ef597bb19229a41d5859f615e84ecbd3f2afb414bcb3bfc217e835c6b744a2cbef04b2ea1f36f45330d093227417c3
4 @@ -20,7 +20,7 @@
5 RewriteBase /
6 RewriteCond %{REQUEST_FILENAME} !-f
7 RewriteCond %{REQUEST_FILENAME} !-d
8 -RewriteRule . /index.php [L]
9 +RewriteRule . /index.php [QSA,L]
10 </IfModule>
11
12 # END WordPress
13 diff -uNr a/mp-wp/manifest b/mp-wp/manifest
14 --- a/mp-wp/manifest 14d47d8eb66fd8266c00a6911255bbf873aa47dd418bf20975c6432f3190ec9914708760fe5d327c693a579b193b1c808698cbba3be3a2138d3b62257ad77f13
15 +++ b/mp-wp/manifest 00b581121b09f282560a29d90fbb53a6ad22a7799428554bb1d17584200fb45310a8022757daf326c1709b2032434fb9eb4c507743af87e517adda50e2974365
16 @@ -7,3 +7,4 @@
17 605926 mp-wp_comments_filtering diana_coman Recent comments widget should show only people's comments (no track/pingbacks); theme default changed to show trackbacks/pingbacks as last/at the bottom in an article's comments list.
18 629903 mp-wp_remove-textselectionjs-pop3-etc-r2 jfw Remove the unreliable JS-based selection (reground: including wrapper spans), posting by POP3 login, and a stray .php.orig file. Neutralize and comment the example pingback updater.
19 629903 mp-wp_svg-screenshots-and-errorreporting-r2 jfw Allow .svg extensions in theme screenshot search. Don't clobber the user's errorreporting level without WP_DEBUG. (Reground following antecedent.)
20 +631542 mp-wp_add-embeddable-codeblocks-and-server-side-selection billymg Add embeddable codeblocks and the server-side select mechanism to the "footnotes" plugin (now "mp-wp content processing")
21 diff -uNr a/mp-wp/wp-content/plugins/footnotes.php b/mp-wp/wp-content/plugins/footnotes.php
22 --- a/mp-wp/wp-content/plugins/footnotes.php 8e2449d4ac26ea05f080cec9d025ef8a8585221ee30da439b37ff1578d084e1c63cbe3f89e3d6868c19d0fa9f73a9af99b444251e7a854f6c87e316628d94859
23 +++ b/mp-wp/wp-content/plugins/footnotes.php 5f8bedbdaf66b24223d250d56acc0050ad7df6b7abade9d7834e835142ec46a5baff035c48fece400e10db78116d2af885d2ebfb8522f4ffcee876d58a0969a3
24 @@ -1,49 +1,29 @@
25 <?php
26 /*
27 -Plugin Name: WP-Footnotes
28 -Plugin URI: http://www.elvery.net/drzax/more-things/wordpress-footnotes-plugin/
29 -Version: 4.2
30 -Description: Allows a user to easily add footnotes to a post.
31 -Author: Simon Elvery
32 -Author URI: http://www.elvery.net/drzax/
33 +Plugin Name: MP-WP Content Processing
34 +Plugin URI: http://billymg.com/category/mp-wp/
35 +Description: Allows for the custom processing of article content. Currently supports footnotes and embedded vpatch snippets.
36 +Author: billymg
37 +Author URI: http://billymg.com
38 */
39
40 -/*
41 - * This file is part of WP-Footnotes a plugin for Word Press
42 - * Copyright (C) 2007 Simon Elvery
43 - *
44 - * This program is free software; you can redistribute it and/or
45 - * modify it under the terms of the GNU General Public License
46 - * as published by the Free Software Foundation; either version 2
47 - * of the License, or (at your option) any later version.
48 - *
49 - * This program is distributed in the hope that it will be useful,
50 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
51 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
52 - * GNU General Public License for more details.
53 - *
54 - * You should have received a copy of the GNU General Public License
55 - * along with this program; if not, write to the Free Software
56 - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
57 - */
58 -
59 -// Some important constants
60 -define('WP_FOOTNOTES_OPEN', " (("); //You can change this if you really have to, but I wouldn't recommend it.
61 -define('WP_FOOTNOTES_CLOSE', "))"); //Same with this one.
62 -define('WP_FOOTNOTES_VERSION', '4.2');
63 -
64 // Instantiate the class
65 -$swas_wp_footnotes = new swas_wp_footnotes();
66 +$mp_wp_content_processing = new mp_wp_content_processing();
67
68 // Encapsulate in a class
69 -class swas_wp_footnotes {
70 - var $current_options;
71 +class mp_wp_content_processing {
72 + const MP_WP_FOOTNOTES_OPEN = " ((";
73 + const MP_WP_FOOTNOTES_CLOSE = "))";
74 + const MP_WP_CODEBLOCKS_PRIORITY = 9; // highest value that comes before wpautop filter
75 + const MP_WP_FOOTNOTES_PRIORITY = 11;
76 +
77 + var $options;
78 var $default_options;
79
80 /**
81 * Constructor.
82 */
83 - function swas_wp_footnotes() {
84 + function mp_wp_content_processing() {
85 // Define the implemented option styles
86 $this->styles = array(
87 'decimal' => '1,2...10',
88 @@ -56,111 +36,168 @@
89 );
90
91 // Define default options
92 - $this->default_options = array('superscript'=>true,
93 - 'pre_backlink'=>' [',
94 - 'backlink'=>'&#8617;',
95 - 'post_backlink'=>']',
96 - 'pre_identifier'=>'',
97 - 'list_style_type'=>'decimal',
98 - 'list_style_symbol'=>'&dagger;',
99 - 'post_identifier'=>'',
100 - 'pre_footnotes'=>'',
101 - 'post_footnotes'=>'',
102 - 'style_rules'=>'ol.footnotes{font-size:0.8em; color:#666666;}',
103 - 'no_display_home'=>false,
104 - 'no_display_archive'=>false,
105 - 'no_display_date'=>false,
106 - 'no_display_category'=>false,
107 - 'no_display_search'=>false,
108 - 'no_display_feed'=>false,
109 - 'combine_identical_notes'=>false,
110 - 'priority'=>11,
111 - 'version'=>WP_FOOTNOTES_VERSION);
112 + $this->default_options = array(
113 + 'pre_backlink'=>' [',
114 + 'backlink'=>'&#8617;',
115 + 'post_backlink'=>']',
116 + 'pre_identifier'=>'',
117 + 'list_style_type'=>'decimal',
118 + 'list_style_symbol'=>'&dagger;',
119 + 'post_identifier'=>'',
120 + 'pre_footnotes'=>'',
121 + 'post_footnotes'=>''
122 + );
123
124 // Get the current settings or setup some defaults if needed
125 - if (!$this->current_options = get_option('swas_footnote_options')){
126 - $this->current_options = $this->default_options;
127 - update_option('swas_footnote_options', $this->current_options);
128 - } else {
129 + $this->options = get_option('mp_wp_cpp_options');
130 + if (!$this->options) {
131 + $this->options = $this->default_options;
132 + update_option('mp_wp_cpp_options', $this->options);
133 + } else {
134 // Set any unset options
135 - if ($this->current_options['version'] != WP_FOOTNOTES_VERSION) {
136 - foreach ($this->default_options as $key => $value) {
137 - if (!isset($this->current_options[$key])) {
138 - $this->current_options[$key] = $value;
139 - }
140 + $updated = false;
141 + foreach ($this->default_options as $key => $value) {
142 + if (!isset($this->options[$key])) {
143 + $this->options[$key] = $value;
144 + $updated = true;
145 }
146 - $this->current_options['version'] = WP_FOOTNOTES_VERSION;
147 - update_option('swas_footnote_options', $this->current_options);
148 + }
149 + if ($updated) {
150 + update_option('mp_wp_cpp_options', $this->options);
151 }
152 }
153
154 -/*
155 - if (!empty($_POST['save_options'])){
156 - $footnotes_options['superscript'] = (array_key_exists('superscript', $_POST)) ? true : false;
157 - $footnotes_options['pre_backlink'] = $_POST['pre_backlink'];
158 - $footnotes_options['backlink'] = $_POST['backlink'];
159 - $footnotes_options['post_backlink'] = $_POST['post_backlink'];
160 - $footnotes_options['pre_identifier'] = $_POST['pre_identifier'];
161 - $footnotes_options['list_style_type'] = $_POST['list_style_type'];
162 - $footnotes_options['post_identifier'] = $_POST['post_identifier'];
163 - $footnotes_options['list_style_symbol'] = $_POST['list_style_symbol'];
164 - $footnotes_options['pre_footnotes'] = stripslashes($_POST['pre_footnotes']);
165 - $footnotes_options['post_footnotes'] = stripslashes($_POST['post_footnotes']);
166 - $footnotes_options['style_rules'] = stripslashes($_POST['style_rules']);
167 - $footnotes_options['no_display_home'] = (array_key_exists('no_display_home', $_POST)) ? true : false;
168 - $footnotes_options['no_display_archive'] = (array_key_exists('no_display_archive', $_POST)) ? true : false;
169 - $footnotes_options['no_display_date'] = (array_key_exists('no_display_date', $_POST)) ? true : false;
170 - $footnotes_options['no_display_category'] = (array_key_exists('no_display_category', $_POST)) ? true : false;
171 - $footnotes_options['no_display_search'] = (array_key_exists('no_display_search', $_POST)) ? true : false;
172 - $footnotes_options['no_display_feed'] = (array_key_exists('no_display_feed', $_POST)) ? true : false;
173 - $footnotes_options['combine_identical_notes'] = (array_key_exists('combine_identical_notes', $_POST)) ? true : false;
174 - $footnotes_options['priority'] = $_POST['priority'];
175 - update_option('swas_footnote_options', $footnotes_options);
176 - }elseif(!empty($_POST['reset_options'])){
177 - update_option('swas_footnote_options', '');
178 - update_option('swas_footnote_options', $this->default_options);
179 - }
180 -*/
181 -
182 // Hook me up
183 - add_action('the_content', array($this, 'process'), $this->current_options['priority']);
184 - add_action('admin_menu', array($this, 'add_options_page')); // Insert the Admin panel.
185 + add_action('the_content', array($this, 'process_codeblocks'), self::MP_WP_CODEBLOCKS_PRIORITY);
186 + add_action('the_content', array($this, 'process_footnotes'), self::MP_WP_FOOTNOTES_PRIORITY);
187 + add_filter('the_content', array($this, 'server_side_selection'));
188 add_action('wp_head', array($this, 'insert_styles'));
189 }
190
191 +
192 + /**
193 + * Finds the selection from the query params.
194 + * @param $data string The content of the post.
195 + * @return string The new content with the highlighted selection.
196 + */
197 + function server_side_selection($data) {
198 + //bookend code goes here
199 + $b_code = '<span class="mp-wp-selection" id="select">';
200 + $b_code .= $_GET["b"];
201 + $e_code = $_GET["e"].'</span>';
202 +
203 + //change page ; last to first to preserve indexes.
204 + $b_pos = strpos($data,$_GET["b"]);
205 + $e_pos = strpos($data,$_GET["e"], $b_pos);
206 + if ($e_pos>0)
207 + $data = substr_replace($data, $e_code, $e_pos, strlen($_GET["e"]));
208 + if ($b_pos>0)
209 + $data = substr_replace($data, $b_code, $b_pos, strlen($_GET["b"]));
210 + return $data;
211 + }
212 +
213 + /**
214 + * Searches the text and apply markup to codeblocks.
215 + * Adds line number links and diff syntax highlighting.
216 + * @param $data string The content of the post.
217 + * @return string The new content with formatted codeblocks.
218 + */
219 + function process_codeblocks($data) {
220 + global $post;
221 +
222 + // Regex extraction of all codeblocks (or return if there are none)
223 + if ( !preg_match_all("/\[([a-z]+)\[(.*)(\]\])/Us", $data, $codeblocks, PREG_SET_ORDER) ) {
224 + return $data;
225 + }
226 +
227 + for ($i = 0; $i < count($codeblocks); $i++) {
228 + $codeblocks[$i]['snippet'] = $this->format_snippet($codeblocks[$i][2], $codeblocks[$i][1], $i+1);
229 + }
230 +
231 + foreach ($codeblocks as $key => $value) {
232 + $data = substr_replace($data, $value['snippet'], strpos($data,$value[0]),strlen($value[0]));
233 + }
234 +
235 + return $data;
236 + }
237 +
238 + function format_snippet($snippet, $syntax, $snippet_number) {
239 + $highlighting_functions = array(
240 + 'plaintext' => 'highlight_as_plain_text',
241 + 'diff' => 'highlight_as_diff'
242 + );
243 +
244 + if (is_null($highlighting_functions[$syntax])) {
245 + $syntax = 'plaintext';
246 + }
247 +
248 + $code_lines = explode("\r\n", $snippet);
249 +
250 + foreach ($code_lines as $idx => $line) {
251 + $line_number = sprintf('S%d-L%d', $snippet_number, $idx+1);
252 + $line_link = sprintf('<a href="#%s" name="%s">%d</a>', $line_number, $line_number, $idx+1);
253 + $line_open = sprintf('<tr><td class="line-number-column">%s</td><td class="content-column">', $line_link);
254 + $line_close = '</td></tr>';
255 +
256 + $code_lines[$idx] = $this->$highlighting_functions[$syntax]($line_open, $line, $line_close);
257 + }
258 +
259 + $formatted_snippet = implode("\n", $code_lines);
260 +
261 + $formatted_snippet = sprintf(
262 + '%s%s%s',
263 + '<div class="mp-wp-codeblock"><table cellpadding="0" cellspacing="0"><tbody>',
264 + $formatted_snippet,
265 + '</tbody></table></div>'
266 + );
267 +
268 + return $formatted_snippet;
269 + }
270 +
271 + function highlight_as_plain_text($line_open, $line, $line_close) {
272 + return sprintf('%s<span class="line-default">%s</span>%s', $line_open, $line, $line_close);
273 + }
274 +
275 + function highlight_as_diff($line_open, $line, $line_close) {
276 + if (substr($line, 0, 5) == 'diff ') {
277 + $highlighted_line = sprintf('%s<span class="line-filename">%s</span>%s', $line_open, $line, $line_close);
278 + } elseif (substr($line, 0, 4) == '--- ' || substr($line, 0, 4) == '+++ ' || substr($line, 0, 3) == '@@ ') {
279 + $highlighted_line = sprintf('%s<span class="line-meta">%s</span>%s', $line_open, $line, $line_close);
280 + } elseif (substr($line, 0, 1) == '-') {
281 + $highlighted_line = sprintf('%s<span class="line-removed">%s</span>%s', $line_open, $line, $line_close);
282 + } elseif (substr($line, 0, 1) == '+') {
283 + $highlighted_line = sprintf('%s<span class="line-added">%s</span>%s', $line_open, $line, $line_close);
284 + } else {
285 + $highlighted_line = sprintf('%s<span class="line-default">%s</span>%s', $line_open, $line, $line_close);
286 + }
287 +
288 + return $highlighted_line;
289 + }
290 +
291 /**
292 * Searches the text and extracts footnotes.
293 * Adds the identifier links and creats footnotes list.
294 * @param $data string The content of the post.
295 * @return string The new content with footnotes generated.
296 */
297 - function process($data) {
298 + function process_footnotes($data) {
299 global $post;
300
301 // Check for and setup the starting number
302 $start_number = (preg_match("|<!\-\-startnum=(\d+)\-\->|",$data,$start_number_array)==1) ? $start_number_array[1] : 1;
303
304 // Regex extraction of all footnotes (or return if there are none)
305 - if (!preg_match_all("/(".preg_quote(WP_FOOTNOTES_OPEN)."|<footnote>)(.*)(".preg_quote(WP_FOOTNOTES_CLOSE)."|<\/footnote>)/Us", $data, $identifiers, PREG_SET_ORDER)) {
306 + if (!preg_match_all("/(".preg_quote(self::MP_WP_FOOTNOTES_OPEN)."|<footnote>)(.*)(".preg_quote(self::MP_WP_FOOTNOTES_CLOSE)."|<\/footnote>)/Us", $data, $identifiers, PREG_SET_ORDER)) {
307 return $data;
308 }
309
310 - // Check whether we are displaying them or not
311 - $display = true;
312 - if ($this->current_options['no_display_home'] && is_home()) $display = false;
313 - if ($this->current_options['no_display_archive'] && is_archive()) $display = false;
314 - if ($this->current_options['no_display_date'] && is_date()) $display = false;
315 - if ($this->current_options['no_display_category'] && is_category()) $display = false;
316 - if ($this->current_options['no_display_search'] && is_search()) $display = false;
317 - if ($this->current_options['no_display_feed'] && is_feed()) $display = false;
318 -
319 $footnotes = array();
320
321 // Check if this post is using a different list style to the settings
322 if ( array_key_exists(get_post_meta($post->ID, 'footnote_style', true), $this->styles) ) {
323 $style = get_post_meta($post->ID, 'footnote_style', true);
324 } else {
325 - $style = $this->current_options['list_style_type'];
326 + $style = $this->options['list_style_type'];
327 }
328
329 // Create 'em
330 @@ -173,25 +210,11 @@
331 $identifiers[$i]['text'] = $identifiers[$i][2];
332 }
333
334 -
335 - // if we're combining identical notes check if we've already got one like this & record keys
336 - if ($this->current_options['combine_identical_notes']){
337 - for ($j=0; $j<count($footnotes); $j++){
338 - if ($footnotes[$j]['text'] == $identifiers[$i]['text']){
339 - $identifiers[$i]['use_footnote'] = $j;
340 - $footnotes[$j]['identifiers'][] = $i;
341 - break;
342 - }
343 - }
344 - }
345 -
346 - if (!isset($identifiers[$i]['use_footnote'])){
347 - // Add footnote and record the key
348 - $identifiers[$i]['use_footnote'] = count($footnotes);
349 - $footnotes[$identifiers[$i]['use_footnote']]['text'] = $identifiers[$i]['text'];
350 - $footnotes[$identifiers[$i]['use_footnote']]['symbol'] = $identifiers[$i]['symbol'];
351 - $footnotes[$identifiers[$i]['use_footnote']]['identifiers'][] = $i;
352 - }
353 + // Add footnote and record the key
354 + $identifiers[$i]['use_footnote'] = count($footnotes);
355 + $footnotes[$identifiers[$i]['use_footnote']]['text'] = $identifiers[$i]['text'];
356 + $footnotes[$identifiers[$i]['use_footnote']]['symbol'] = $identifiers[$i]['symbol'];
357 + $footnotes[$identifiers[$i]['use_footnote']]['identifiers'][] = $i;
358 }
359
360 // Footnotes and identifiers are stored in the array
361 @@ -206,86 +229,89 @@
362 $id_id = "identifier_".$key."_".$post->ID;
363 $id_num = ($style == 'decimal') ? $value['use_footnote']+$start_number : $this->convert_num($value['use_footnote']+$start_number, $style, count($footnotes));
364 $id_href = ( ($use_full_link) ? get_permalink($post->ID) : '' ) . "#footnote_".$value['use_footnote']."_".$post->ID;
365 -
366 -// $id_title = str_replace('"', "&quot;", htmlentities(strip_tags($value['text']), ENT_QUOTES, 'UTF-8'));
367 -
368 $id_title = str_replace('"', '`', strip_tags($value['text']));
369 - $id_replace = $this->current_options['pre_identifier'].'<a href="'.$id_href.'" id="'.$id_id.'" class="footnote-link footnote-identifier-link" title="'.$id_title.'">'.$id_num.'</a>'.$this->current_options['post_identifier'];
370 - if ($this->current_options['superscript']) $id_replace = '<sup>'.$id_replace.'</sup>';
371 - if ($display) $data = substr_replace($data, $id_replace, strpos($data,$value[0]),strlen($value[0]));
372 - else $data = substr_replace($data, '', strpos($data,$value[0]),strlen($value[0]));
373 + $id_replace = '<sup>'.$this->options['pre_identifier'].'<a href="'.$id_href.'" id="'.$id_id.'" class="footnote-link footnote-identifier-link" title="'.$id_title.'">'.$id_num.'</a>'.$this->options['post_identifier'].'</sup>';
374 + $data = substr_replace($data, $id_replace, strpos($data,$value[0]),strlen($value[0]));
375 }
376
377 // Display footnotes
378 - if ($display) {
379 - $start = ($start_number != 1) ? 'start="'.$start_number.'" ' : '';
380 - $data = $data.$this->current_options['pre_footnotes'];
381 -
382 - $data = $data . '<ol '.$start.'class="footnotes">';
383 - foreach ($footnotes as $key => $value) {
384 - $data = $data.'<li id="footnote_'.$key.'_'.$post->ID.'" class="footnote"';
385 - if ($style == 'symbol') {
386 - $data = $data . ' style="list-style-type:none;"';
387 - } elseif($style != $this->current_options['list_style_type']) {
388 - $data = $data . ' style="list-style-type:' . $style . ';"';
389 - }
390 - $data = $data . '>';
391 - if ($style == 'symbol') {
392 - $data = $data . '<span class="symbol">' . $this->convert_num($key+$start_number, $style, count($footnotes)) . '</span> ';
393 - }
394 - $data = $data.$value['text'];
395 - if (!is_feed()){
396 - foreach($value['identifiers'] as $identifier){
397 - $data = $data.$this->current_options['pre_backlink'].'<a href="'.( ($use_full_link) ? get_permalink($post->ID) : '' ).'#identifier_'.$identifier.'_'.$post->ID.'" class="footnote-link footnote-back-link">'.$this->current_options['backlink'].'</a>'.$this->current_options['post_backlink'];
398 - }
399 + $start = ($start_number != 1) ? 'start="'.$start_number.'" ' : '';
400 + $data = $data.$this->options['pre_footnotes'];
401 +
402 + $data = $data . '<ol '.$start.'class="footnotes">';
403 + foreach ($footnotes as $key => $value) {
404 + $data = $data.'<li id="footnote_'.$key.'_'.$post->ID.'" class="footnote"';
405 + if ($style == 'symbol') {
406 + $data = $data . ' style="list-style-type:none;"';
407 + } elseif($style != $this->options['list_style_type']) {
408 + $data = $data . ' style="list-style-type:' . $style . ';"';
409 + }
410 + $data = $data . '>';
411 + if ($style == 'symbol') {
412 + $data = $data . '<span class="symbol">' . $this->convert_num($key+$start_number, $style, count($footnotes)) . '</span> ';
413 + }
414 + $data = $data.$value['text'];
415 + if (!is_feed()){
416 + foreach($value['identifiers'] as $identifier){
417 + $data = $data.$this->options['pre_backlink'].'<a href="'.( ($use_full_link) ? get_permalink($post->ID) : '' ).'#identifier_'.$identifier.'_'.$post->ID.'" class="footnote-link footnote-back-link">'.$this->options['backlink'].'</a>'.$this->options['post_backlink'];
418 }
419 - $data = $data . '</li>';
420 }
421 - $data = $data . '</ol>' . $this->current_options['post_footnotes'];
422 + $data = $data . '</li>';
423 }
424 - return $data;
425 - }
426 -
427 - /**
428 - * Really insert the options page.
429 - */
430 - function footnotes_options_page() {
431 - $this->current_options = get_option('swas_footnote_options');
432 - foreach ($this->current_options as $key=>$setting) {
433 - $new_setting[$key] = htmlentities($setting);
434 - }
435 - $this->current_options = $new_setting;
436 - unset($new_setting);
437 - include (dirname(__FILE__) . '/options.php');
438 - }
439 + $data = $data . '</ol>' . $this->options['post_footnotes'];
440
441 - /**
442 - * Insert the options page into the admin area.
443 - */
444 - function add_options_page() {
445 - // Add a new menu under Options:
446 - add_options_page('Footnotes', 'Footnotes', 8, __FILE__, array($this, 'footnotes_options_page'));
447 - }
448 -
449 - function upgrade_post($data){
450 - $data = str_replace('<footnote>',WP_FOOTNOTES_OPEN,$data);
451 - $data = str_replace('</footnote>',WP_FOOTNOTES_CLOSE,$data);
452 return $data;
453 }
454
455 - function insert_styles(){
456 + function insert_styles() {
457 ?>
458 <style type="text/css">
459 - <?php if ($this->current_options['list_style_type'] != 'symbol'): ?>
460 - ol.footnotes li {list-style-type:<?php echo $this->current_options['list_style_type']; ?>;}
461 + ol.footnotes { font-size: 0.8em; color: #666; }
462 + a.footnote-link,
463 + td.line-number-column {
464 + -moz-user-select: none;
465 + -webkit-user-select: none;
466 + user-select: none;
467 + }
468 + div.mp-wp-codeblock {
469 + background: none;
470 + font-family: monospace;
471 + color: #333;
472 + border: 1px solid #ddd;
473 + padding: 0;
474 + overflow: auto;
475 + }
476 + td.line-number-column { background: #f5f6f7; text-align: right; vertical-align: top; }
477 + td.line-number-column a { color: #555; padding: 0 5px; }
478 + td.content-column {
479 + padding-left: 10px;
480 + white-space: pre-wrap;
481 + word-break: break-word;
482 + tab-size: 4;
483 + -moz-tab-size: 4;
484 + max-width: 100%; /* adjust, if necessary, to fit your blog's viewport */
485 + }
486 + span.line-filename { font-weight: bold; }
487 + span.line-meta {
488 + display: block;
489 + color: #999;
490 + word-wrap: break-word;
491 + word-break: break-all;
492 + }
493 + span.line-added { color: green; }
494 + span.line-removed { color:red; }
495 +
496 + <?php if ($this->options['list_style_type'] != 'symbol'): ?>
497 + ol.footnotes li { list-style-type: <?php echo $this->options['list_style_type']; ?>; }
498 <?php endif; ?>
499 - <?php echo $this->current_options['style_rules'];?>
500 +
501 + span.mp-wp-selection { background-color: #d3d3d3; }
502 </style>
503 <?php
504 }
505
506
507 - function convert_num ($num, $style, $total){
508 + function convert_num ($num, $style, $total) {
509 switch ($style) {
510 case 'decimal-leading-zero' :
511 $width = max(2, strlen($total));
512 @@ -301,7 +327,7 @@
513 case 'symbol' :
514 $sym = '';
515 for ($i = 0; $i<$num; $i++) {
516 - $sym .= $this->current_options['list_style_symbol'];
517 + $sym .= $this->options['list_style_symbol'];
518 }
519 return $sym;
520 }
521 @@ -318,7 +344,7 @@
522 * @param string $case Upper or lower case.
523 * @return string The roman numeral
524 */
525 - function roman($num, $case= 'upper'){
526 + function roman($num, $case= 'upper') {
527 $num = (int) $num;
528 $conversion = array('M'=>1000, 'CM'=>900, 'D'=>500, 'CD'=>400, 'C'=>100, 'XC'=>90, 'L'=>50, 'XL'=>40, 'X'=>10, 'IX'=>9, 'V'=>5, 'IV'=>4, 'I'=>1);
529 $roman = '';
530 @@ -331,7 +357,7 @@
531 return ($case == 'lower') ? strtolower($roman) : $roman;
532 }
533
534 - function alpha($num, $case='upper'){
535 + function alpha($num, $case='upper') {
536 $j = 1;
537 for ($i = 'A'; $i <= 'ZZ'; $i++){
538 if ($j == $num){
539 diff -uNr a/mp-wp/xmlrpc.php b/mp-wp/xmlrpc.php
540 --- a/mp-wp/xmlrpc.php 4f496f538195a62e0f48c2d27dd787923795583c1ae1419c1135d132ca848efe79b148f31de66d9414829b034981427920b317952be6fe23a097447815b14000
541 +++ b/mp-wp/xmlrpc.php d26b211e8c163bae44b267a173ba2724e8475a6ee44ea0fd0caed998d85de6de1589efae5a82efe598ed884b0e0db2c9b8b5b6d644fef1142546d9fb1df16849
542 @@ -3326,7 +3326,8 @@
543 $comment_post_ID = (int) $post_ID;
544 $comment_author = $title;
545 $this->escape($comment_author);
546 - $comment_author_url = $pagelinkedfrom;
547 + $select_tail = "?b=".substr(rawurlencode(strip_tags($excerpt)),0,12)."&e=".substr(rawurlencode(strip_tags($excerpt)),0,-4)."#select";
548 + $comment_author_url = $pagelinkedfrom.$select_tail;
549 $comment_content = $context;
550 $this->escape($comment_content);
551 $comment_type = 'pingback';
552
  1. Previously just the footnotes plugin before embeddable codeblocks and server-side selection were added in this patch. []
« Guanacaste, San Jose, and Arenal: Two Months in Costa Rica
The MP-WP Weightloss Program: Removing JavaScript »

8 Comments

  1. Your code displayer runs offscreen ; I tried to get you some shots to show it but look at this sad shit -- 5 failed, 41 expired out of 46, browsershots.org is dead by now too, joining a lengthy pile of needful infrastructure nobody's left to salvage.

    So what can we do, sit here like savages, "your thing runs offscreen".

  2. billymg says:

    @Mircea Popescu Thanks for taking a look. Do you mean that there is horizontal scrolling inside the code "pane"? Or that the code pane itself is running off the browser's viewport? The former is intentional but is only set with CSS and so can be adjusted at the theme level by adding td.content-column { word-break: break-all; }.

  3. Oh is that what it was, a horiz scroller ? It doesn't show on this machine ; most people regard these very dimly fwis.

  4. billymg says:

    @Mircea Popescu Can you check again to see if it's fixed now? There should be no horizontal scrolling.

    There was a fix I made earlier on my live version that breaks the long file hash in a vdiff but for the rest of the code only wraps at the word level. I forgot to carry this fix over when updating the patch.

    A wider layout for displaying code will help readability as well (just so that less wrapping is required in the first place). I'm working on an update to my theme that will improve this.

  5. Jacob Welsh says:

    Since I now have a definite need to get selection working for a hosted blog customer, and would prefer to do it the proper / standard / upstream way if such a way in fact exists, I tried to give this patch a closer look, but was put off enough by first impressions that I'm not sure I can bring myself to push through it as is.

    You've got mixed tab and space indents (server_side_selection); inconsistent spacing style in new code; inconsistent spacing style even within a space-only change (roman); a bulk reindent mixed with content change making the latter harder to follow (default_options); poor factoring (that sprintf paste table in highlight_as_diff, not to mention assigning a variable just in order to return it).

    Then there's the angle that since it's 406 lines of patching on what was a 346 line file it might as well be a total rewrite, from which view it's a missed opportunity to fix the overall structure. Such as dropping the "plugin" baggage wherein this (and only this) file is considered "content", on a level with themes and uploads, despite in actual usage being part of the core text formatting, on a level with the insertion of br and p tags; and wherein the "how to deploy a new blog" process that nobody's published except in bits and pieces needs to include "don't forget to activate the footnotes plugin!" in its lengthy list of ridiculous GUI-based post-install tasks. Or the "Encapsulate in a class [for no discernible reason and requiring more code to instantiate it into a throwaway global variable]".

    so it will work across all themes without modification

    Except that existing users already put selection code in their own themes per the original recipe so... won't the two implementations interfere unless the old one is manually reverted in full or in part?

  6. [...] http://billymg.com/2020/05/updated-vpatch-add-embeddable-codeblocks-and-the-server-side-select-mecha... << billymg -- Updated vpatch: Add embeddable codeblocks and the server-side select mechanism [...]

  7. [...] diana_coman: yeah, i would recommend just keeping the directory of your current custom theme as is. the included themes can be safely nuked for sure (server-side selection is handled in the footnotes.php as of this patch) [...]

  8. [...] was trimmed3, a feature was added, patches were produced, and in 2020 TMSR was closed. I had also at this time just moved [...]

Leave a Reply

*
*

You can use the following HTML tags in your comment: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>