/** * LaTeX support. * * Backward compatibility requires support for both "[latex][/latex]", and * "$latex $" shortcodes. * * $latex e^{\i \pi} + 1 = 0$ -> [latex]e^{\i \pi} + 1 = 0[/latex] * $latex [a, b]$ -> [latex][a, b][/latex] */ function latex_markup($content) { $textarr = wp_html_split($content); $regex = '% \\$latex(?:=\\s*|\\s+) ((?: [^$]+ # Not a dollar | (?<=(?<!\\\\)\\\\)\\$ # Dollar preceded by exactly one slash )+) (?<!\\\\)\\$ # Dollar preceded by zero slashes %ix'; foreach ($textarr as &$element) { if ('' == $element || '<' === $element[0]) { continue; } if (false === stripos($element, '$latex')) { continue; } $element = preg_replace_callback($regex, 'latex_src', $element); } return implode('', $textarr); }
/** * Search only inside HTML elements for shortcodes and process them. * * Any [ or ] characters remaining inside elements will be HTML encoded * to prevent interference with shortcodes that are outside the elements. * Assumes $content processed by KSES already. Users with unfiltered_html * capability may get unexpected output if angle braces are nested in tags. * * @since 4.2.3 * * @param string $content Content to search for shortcodes * @param bool $ignore_html When true, all square braces inside elements will be encoded. * @return string Content with shortcodes filtered out. */ function do_shortcodes_in_html_tags($content, $ignore_html) { // Normalize entities in unfiltered HTML before adding placeholders. $trans = array('[' => '[', ']' => ']'); $content = strtr($content, $trans); $trans = array('[' => '[', ']' => ']'); $pattern = get_shortcode_regex(); $textarr = wp_html_split($content); foreach ($textarr as &$element) { if ('' == $element || '<' !== $element[0]) { continue; } $noopen = false === strpos($element, '['); $noclose = false === strpos($element, ']'); if ($noopen || $noclose) { // This element does not contain shortcodes. if ($noopen xor $noclose) { // Need to encode stray [ or ] chars. $element = strtr($element, $trans); } continue; } if ($ignore_html || '<!--' === substr($element, 0, 4) || '<![CDATA[' === substr($element, 0, 9)) { // Encode all [ and ] chars. $element = strtr($element, $trans); continue; } $attributes = wp_kses_attr_parse($element); if (false === $attributes) { // Some plugins are doing things like [name] <[email]>. if (1 === preg_match('%^<\\s*\\[\\[?[^\\[\\]]+\\]%', $element)) { $element = preg_replace_callback("/{$pattern}/s", 'do_shortcode_tag', $element); } // Looks like we found some crazy unfiltered HTML. Skipping it for sanity. $element = strtr($element, $trans); continue; } // Get element name $front = array_shift($attributes); $back = array_pop($attributes); $matches = array(); preg_match('%[a-zA-Z0-9]+%', $front, $matches); $elname = $matches[0]; // Look for shortcodes in each attribute separately. foreach ($attributes as &$attr) { $open = strpos($attr, '['); $close = strpos($attr, ']'); if (false === $open || false === $close) { continue; // Go to next attribute. Square braces will be escaped at end of loop. } $double = strpos($attr, '"'); $single = strpos($attr, "'"); if ((false === $single || $open < $single) && (false === $double || $open < $double)) { // $attr like '[shortcode]' or 'name = [shortcode]' implies unfiltered_html. // In this specific situation we assume KSES did not run because the input // was written by an administrator, so we should avoid changing the output // and we do not need to run KSES here. $attr = preg_replace_callback("/{$pattern}/s", 'do_shortcode_tag', $attr); } else { // $attr like 'name = "[shortcode]"' or "name = '[shortcode]'" // We do not know if $content was unfiltered. Assume KSES ran before shortcodes. $count = 0; $new_attr = preg_replace_callback("/{$pattern}/s", 'do_shortcode_tag', $attr, -1, $count); if ($count > 0) { // Sanitize the shortcode output using KSES. $new_attr = wp_kses_one_attr($new_attr, $elname); if ('' !== trim($new_attr)) { // The shortcode is safe to use now. $attr = $new_attr; } } } } $element = $front . implode('', $attributes) . $back; // Now encode any remaining [ or ] chars. $element = strtr($element, $trans); } $content = implode('', $textarr); return $content; }
/** * Replace characters or phrases within HTML elements only. * * @since 4.2.3 * * @param string $haystack The text which has to be formatted. * @param array $replace_pairs In the form array('from' => 'to', ...). * @return string The formatted text. */ function wp_replace_in_html_tags($haystack, $replace_pairs) { // Find all elements. $textarr = wp_html_split($haystack); $changed = false; // Optimize when searching for one item. if (1 === count($replace_pairs)) { // Extract $needle and $replace. foreach ($replace_pairs as $needle => $replace) { } // Loop through delimiters (elements) only. for ($i = 1, $c = count($textarr); $i < $c; $i += 2) { if (false !== strpos($textarr[$i], $needle)) { $textarr[$i] = str_replace($needle, $replace, $textarr[$i]); $changed = true; } } } else { // Extract all $needles. $needles = array_keys($replace_pairs); // Loop through delimiters (elements) only. for ($i = 1, $c = count($textarr); $i < $c; $i += 2) { foreach ($needles as $needle) { if (false !== strpos($textarr[$i], $needle)) { $textarr[$i] = strtr($textarr[$i], $replace_pairs); $changed = true; // After one strtr() break out of the foreach loop and look at next element. break; } } } } if ($changed) { $haystack = implode($textarr); } return $haystack; }
/** * Extract shortcodes from a text string * * First we break the string down into chunks of HTML * then we process the shortcodes within the HTML * or the shortcodes in plain text * Ignoring sections where we don't expect to see shortcodes * * * @param string $text a text field * @return array of shortcodes, may be an empty array */ function schunt_codes_from_text($text) { $codes = array(); if ($this->schunt($text)) { $text_array = wp_html_split($text); //print_r( $text_array ); foreach ($text_array as $text) { if ($this->skip($text)) { continue; } if ($this->schunt($text)) { $bits = explode("[", $text); //print_r( $bits ); array_shift($bits); foreach ($bits as $bit) { if ($this->skip($bit)) { continue; } if (strlen($bit) > 0) { $bit = strtr($bit, "/]", " "); $bit = rtrim($bit); $sc = explode(" ", $bit); $code = $sc[0]; //echo "Code: $code" . PHP_EOL; $invalid = preg_match('@[<>&/\\[\\]\\x00-\\x20=]@', $code); if ($invalid) { echo "Invalid shortcode detected? {$code}" . PHP_EOL; echo $bit . PHP_EOL; echo PHP_EOL; echo $text . PHP_EOL; //gobang(); docontinue(); //oikb_get_response(); } else { //echo "Code: $code looks like a good un" . PHP_EOL; $codes[$code] = $code; $this->found_codes[$code] = $code; $this->check_code_skip($code); } } } } } } //print_r( $codes ); //gobang(); return $codes; }
/** * Runs preg_replace_callback so that replacements don't happen within open tags. * Parameters are the same as preg_replace, with an added optional search param for improved performance * * @param String $pattern * @param String $replacement * @param String $content * @param String $search * @return String $content */ function jetpack_preg_replace_callback_outside_tags($pattern, $callback, $content, $search = null) { if (!function_exists('wp_html_split')) { return $content; } if ($search && false === strpos($content, $search)) { return $content; } $textarr = wp_html_split($content); unset($content); foreach ($textarr as &$element) { if ('' === $element || '<' === $element[0]) { continue; } $element = preg_replace_callback($pattern, $callback, $element); } return join($textarr); }
/** * Basic functionality goes here. * * @dataProvider data_basic_features */ function test_basic_features($input, $output) { return $this->assertEquals($output, wp_html_split($input)); }