blob: 0840bfa8b4f22c01b8a2d0e31def0145c78ee375 [file] [log] [blame]
<?php
// Declare theme features
add_theme_support( 'post-thumbnails' );
add_action( 'init', function () {
register_nav_menu('site-nav', __( 'Site Navigation' ));
register_nav_menu('footer-nav', __( 'Footer Navigation' ));
register_nav_menu('sitemap', __( 'Site Map Page' ));
register_nav_menu('feature-subnav', __( 'Feature Page Buttons' ));
} );
// Disable WP-emoji polyfill
add_action('init', function() {
remove_action('wp_head', 'print_emoji_detection_script', 7);
remove_action('admin_print_scripts', 'print_emoji_detection_script');
remove_action('admin_print_styles', 'print_emoji_styles');
remove_action('wp_print_styles', 'print_emoji_styles');
remove_filter('the_content_feed', 'wp_staticize_emoji');
remove_filter('comment_text_rss', 'wp_staticize_emoji');
remove_filter('wp_mail', 'wp_staticize_emoji_for_email');
// Remove DNS prefetch
add_filter('emoji_svg_url', '__return_false');
});
add_action( 'wp_dashboard_setup', function () {
$SurveyWidget = new WebKit_Nightly_Survey();
$SurveyWidget->add_widget();
});
function modify_contact_methods($profile_fields) {
// Add new fields
$profile_fields['twitter'] = 'Twitter Handle';
unset($profile_fields['aim']);
unset($profile_fields['yim']);
unset($profile_fields['jabber']);
return $profile_fields;
}
function get_nightly_build ($type = 'builds') {
if (!class_exists('SyncWebKitNightlyBuilds'))
return false;
$WebKitBuilds = SyncWebKitNightlyBuilds::object();
$build = $WebKitBuilds->latest($type);
return $build;
}
function get_nightly_source () {
return get_nightly_build('source');
}
function get_nightly_archives ($limit) {
if (!class_exists('SyncWebKitNightlyBuilds'))
return array();
$WebKitBuilds = SyncWebKitNightlyBuilds::object();
$builds = $WebKitBuilds->records('builds', $limit);
return (array)$builds;
}
function get_nightly_builds_json () {
if (!class_exists('SyncWebKitNightlyBuilds'))
return '';
$WebKitBuilds = SyncWebKitNightlyBuilds::object();
$records = $WebKitBuilds->records('builds', 100000);
$builds = array();
foreach ( $records as $build ) {
$builds[] = $build[0];
}
$json = json_encode($builds);
return empty($json) ? "''" : $json;
}
add_filter('user_contactmethods', function ($fields) {
// Add Twitter field to user profiles
$fields['twitter'] = 'Twitter Handle';
// Remove unused social networks
unset($fields['aim']);
unset($fields['yim']);
unset($fields['jabber']);
return $fields;
});
add_action('init', function () {
register_sidebar(array(
'name'=> 'Home Tiles',
'id' => 'tiles',
'before_widget' => '',
'after_widget' => '',
'before_title' => '',
'after_title' => '',
));
} );
// Start Page internal rewrite handling
add_action('after_setup_theme', function () {
add_rewrite_rule(
'nightly/start/([^/]+)/([0-9]+)/?$',
'index.php?pagename=nightly/start&nightly_branch=$matches[1]&nightly_build=$matches[2]',
'top'
);
});
add_filter('query_vars', function( $query_vars ) {
$query_vars[] = 'nightly_build';
$query_vars[] = 'nightly_branch';
return $query_vars;
});
add_filter('the_title', function( $title ) {
if ( is_admin() ) return $title;
if ( is_feed() ) return $title;
$title = str_replace(": ", ": <br>", $title);
$nowrap_strings = array();
if ($nowrap_setting = get_option("webkit_org_nowrap_strings")) {
$nowrap_strings = explode("\n", $nowrap_setting);
} else add_option("webkit_org_nowrap_strings", "\n");
foreach ($nowrap_strings as $token) {
$nobreak = str_replace(" ", " ", trim($token));
$title = str_replace(trim($token), $nobreak, $title);
}
return $title;
});
// For RSS feeds, convert relative URIs to absolute
add_filter('the_content', function($content) {
if (!is_feed()) return $content;
$base = trailingslashit(get_site_url());
$content = preg_replace('/<a([^>]*) href="\/([^"]*)"/', '<a$1 href="' . $base . '$2"', $content);
$content = preg_replace('/<img([^>]*) src="\/([^"]*)"/', '<img$1 src="' . $base . '$2"', $content);
return $content;
});
// Add Web Inspector Reference notice to Web Inspector blog posts
add_filter('the_content', function($content) {
if (!has_term('web-inspector', 'category', get_post()))
return $content;
$note = '<div class="note">Note: Learn more about Web Inspector from the <a href="/web-inspector/">Web Inspector Reference</a> documentation.</div>';
$position = get_post_meta(get_the_ID(), 'web-inspector-reference-note', true);
if ($position === 'before')
$content = $note . $content;
else
$content .= $note;
return $content;
});
add_action('wp_head', function () {
if (!is_single()) return;
$style = get_post_meta(get_the_ID(), 'style', true);
if (!empty($style))
echo '<style type="text/css">' . $style . '</style>';
$script = get_post_meta(get_the_ID(), 'script', true);
if (!empty($script))
echo '<script type="text/javascript">' . $script . '</script>';
});
add_action('the_post', function($post) {
global $pages;
if (!(is_single() || is_page())) return;
$content = $post->post_content;
if (strpos($content, 'abovetitle') === false) return;
if (strpos($content, '<img') !== 0) return;
$post->post_title_img = substr($content, 0, strpos($content, ">\n") + 3);
$post->post_content = str_replace($post->post_title_img, '', $content);
$pages = array($post->post_content);
});
add_action('the_post', function($post) {
global $pages;
if (!(is_single() || is_page())) return;
$foreword = get_post_meta(get_the_ID(), 'foreword', true);
if ( ! $foreword ) return;
$content = $post->post_content;
// Transform Markdown
$Markdown = WPCom_Markdown::get_instance();
$foreword = wp_unslash( $Markdown->transform($foreword) );
$post->post_content = '<div class="foreword">' . $foreword . '</div>' . $content;
$pages = array($post->post_content);
});
add_filter('the_author', function($display_name) {
$post = get_post();
if (!(is_single() || is_page())) return;
$byline = get_post_meta(get_the_ID(), 'byline', true);
return empty($byline) ? $display_name : $byline;
});
function before_the_title() {
$post = get_post();
if ( isset($post->post_title_img) )
echo wp_make_content_images_responsive($post->post_title_img);
}
// Hide category 41: Legacy from archives
add_filter('pre_get_posts', function ($query) {
if ( $query->is_home() )
$query->set('cat', '-41');
return $query;
});
add_filter( 'get_the_excerpt', function( $excerpt ) {
$sentences = preg_split( '/(\.|!|\?)\s/', $excerpt, 2, PREG_SPLIT_DELIM_CAPTURE );
// if ( empty($sentences[1]) )
// $sentences[1] = '&hellip;';
return $sentences[0] . $sentences[1];
});
function show_404_page() {
status_header(404);
return include( get_query_template( '404' ) );
}
include('widgets/post.php');
include('widgets/icon.php');
include('widgets/twitter.php');
include('widgets/page.php');
function table_of_contents() {
if ( class_exists('WebKitTableOfContents') )
WebKitTableOfContents::markup();
}
function has_table_of_contents() {
if ( class_exists('WebKitTableOfContents') )
return WebKitTableOfContents::hasIndex();
}
function table_of_contents_index( $content, $post_id ) {
if ( ! class_exists('WebKitTableOfContents') )
return $content;
$content = WebKitTableOfContents::parse($content);
WebKitTableOfContents::wp_insert_post($post_id);
return $content;
}
function is_super_cache_enabled() {
global $super_cache_enabled;
return (isset($super_cache_enabled) && true === $super_cache_enabled);
}
function include_post_icons() {
echo WebKit_Post_Icons::parse_icons();
}
function include_invert_lightness_filter() {
include('images/invert-lightness.svg');
}
function get_post_icon() {
$categories = get_the_category();
if (isset($categories[0]))
$slug = $categories[0]->slug;
if ('web-inspector' == $slug) {
$tags = get_the_tags();
if (isset($tags[0]))
$slug = $tags[0]->slug;
}
if (!WebKit_Post_Icons::has_icon($slug))
return 'default';
return $slug;
}
function tag_post_image_luminance($post_id) {
$threshold = 128;
$tags = array();
// Get the image data
$image_src = wp_get_attachment_image_src( get_post_thumbnail_id($post_id), 'small' );
$image_url = $image_src[0];
if ( empty($image_url) ) return $post_id;
// detect luminence value
$luminance = calculate_image_luminance($image_url);
$tags = wp_get_post_tags($post_id, array('fields' => 'names'));
if ( $luminance < $threshold )
$tags[] = 'dark';
elseif ( false !== ( $key = array_search('dark', $messages) ) )
unset($tags[ $key ]);
// Set a tag class
if ( ! empty($tags) )
wp_set_post_tags( $post_id, $tags, true );
return $post_id;
}
function calculate_image_luminance($image_url) {
if (!function_exists('ImageCreateFromString'))
return 1;
// Get original image dimensions
$size = getimagesize($image_url);
// Create image resource from source image
$image = ImageCreateFromString(file_get_contents($image_url));
// Allocate image resource
$sample = ImageCreateTrueColor(1, 1);
// Flood fill with a white background (to properly calculate luminance of PNGs with alpha)
ImageFill($sample , 0, 0, ImageColorAllocate($sample, 255, 255, 255));
// Downsample to 1x1 image
ImageCopyResampled($sample, $image, 0, 0, 0, 0, 1, 1, $size[0], $size[1]);
// Get the RGB value of the pixel
$rgb = ImageColorAt($sample, 0, 0);
$red = ($rgb >> 16) & 0xFF;
$green = ($rgb >> 8) & 0xFF;
$blue = $rgb & 0xFF;
// Calculate relative luminance value (https://en.wikipedia.org/wiki/Relative_luminance)
return ( 0.2126 * $red + 0.7152 * $green + 0.0722 * $blue);
}
function html_select_options(array $list, $selected = null, $values = false, $append = false) {
if ( ! is_array($list) ) return '';
$_ = '';
// Append the options if the selected value doesn't exist
if ( ( ! in_array($selected, $list) && ! isset($list[ $selected ])) && $append )
$_ .= '<option value="' . esc_attr($selected) . '">' .esc_html($selected) . '</option>';
foreach ( $list as $value => $text ) {
$value_attr = $selected_attr = '';
if ( $values ) $value_attr = ' value="' . esc_attr($value) . '"';
if ( ( $values && (string)$value === (string)$selected)
|| ( ! $values && (string)$text === (string)$selected ) )
$selected_attr = ' selected="selected"';
if ( is_array($text) ) {
$label = $value;
$_ .= '<optgroup label="' . esc_attr($label) . '">';
$_ .= html_select_options($text, $selected, $values);
$_ .= '</optgroup>';
continue;
} else $_ .= "<option$value_attr$selected_attr>$text</option>";
}
return $_;
}
add_filter('save_post', 'tag_post_image_luminance');
add_filter('next_post_link', function ( $format ) {
return str_replace('href=', 'class="page-numbers next-post" href=', $format);
});
add_filter('previous_post_link', function ( $format ) {
return str_replace('href=', 'class="page-numbers prev-post" href=', $format);
});
// Queue global scripts
add_action( 'wp_enqueue_scripts', function () {
wp_register_script(
'theme-global',
get_stylesheet_directory_uri() . '/scripts/global.js',
false,
'1.0',
true
);
wp_enqueue_script( 'theme-global' );
} );
class Responsive_Toggle_Walker_Nav_Menu extends Walker_Nav_Menu {
private $toggleid = null;
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$output .= "\n" . str_repeat("\t", $depth);
$classes = array("sub-menu");
if ( 0 == $depth ) {
$classes[] = "sub-menu-layer";
}
$id = ( 0 == $depth ) ? " id=\"sub-menu-for-{$this->toggleid}\"" : '';
$class_names = esc_attr(join( ' ', $classes ));
$output .= "<ul class=\"$class_names\" role=\"menu\"$id>\n";
}
public function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "$indent</ul>\n";
}
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$before = $args->link_before;
$after = $args->link_after;
if ( in_array('menu-item-has-children', $item->classes) && 0 == $depth ) {
$this->toggleid = $item->ID;
$args->before .= "<input type=\"checkbox\" id=\"toggle-{$item->ID}\" class=\"menu-toggle\" />";
$args->link_before = "<label for=\"toggle-{$item->ID}\" class=\"label-toggle\">" . $args->link_before;
$args->link_after .= "</label>";
$item->url = '#nav-sub-menu';
} elseif ( in_array('menu-item-has-children', $item->classes) && 1 == $depth ) {
// $item->role = "presentation";
} else $toggleid = null;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args, $depth );
$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
$output .= $indent . '<li' . $id . $class_names . '>';
$atts = array();
$atts['title'] = ! empty( $item->attr_title ) ? $item->attr_title : '';
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
$atts['role'] = ! empty( $item->role ) ? $item->role : 'menuitem';
if ( in_array('menu-item-has-children', $item->classes) && 0 == $depth ) {
$atts['aria-haspopup'] = "true";
$atts['aria-owns'] = 'sub-menu-for-' . $item->ID;
$atts['aria-controls'] = 'sub-menu-for-' . $item->ID;
$atts['aria-expanded'] = 'true';
}
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
$args->link_before = $before;
$args->link_after = $after;
}
}
class WebKit_Post_Icons {
private static $registry = array();
public static function parse_icons() {
if (!empty(self::$registry))
return '';
$svg_string = file_get_contents(get_stylesheet_directory() . '/images/icons.svg');
$svg = new SimpleXMLElement( $svg_string );
$svg->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg');
$matches = $svg->xpath('//svg:symbol/@id');
foreach ($matches as $symbol)
self::$registry[(string)$symbol['id']] = true;
return $svg_string;
}
public static function has_icon($id) {
return isset(self::$registry[$id]);
}
}
class Front_Page_Posts {
private static $object; // Singleton instance
private static $wp_query; // WP_Query instance
public static function &object () {
if ( ! self::$object instanceof self )
self::$object = new self;
if ( empty(self::$wp_query) )
self::$wp_query = new WP_Query(array('post_type' => 'post', 'posts_per_page' => 16));
return self::$object;
}
public static function WP_Query() {
return self::$wp_query;
}
}
class WebKit_Nightly_Survey {
const COOKIE_PREFIX = 'webkitnightlysurvey_';
const DATA_SETTING_NAME = 'webkit_nightly_survey_data';
const SURVEY_FILENAME = 'survey.json';
public function add_widget() {
wp_add_dashboard_widget(
'webkit_nightly_survey_results', // Widget slug
'WebKit Nightly Survey Results', // Title
array($this, 'display_widget') // Display function
);
if (isset($_GET['wksurvey']) && $_GET['wksurvey'] == 'download')
$this->download() && exit;
}
public function display_widget() {
$data = get_option(self::DATA_SETTING_NAME);
$styles = "
<style>
.survey_table .question {
text-align: left;
}
.survey_table .score {
font-size: 15px;
min-width: 30px;
text-align: right;
vertical-align: top;
padding-right: 10px;
}
.survey_table .others {
font-style: italic;
}
</style>
";
$response_limit = 10;
$table = '';
foreach ($data as $question => $responses) {
$question_row = '<tr><th colspan="2" class="question">' . $question . '</th></tr>';
$response_rows = '';
arsort($responses);
$response_count = 0;
$total_responses = count($responses);
foreach ($responses as $response => $votes) {
$response_rows .= '<tr><td class="score">' . intval($votes) . '</td><td class="response">' . stripslashes($response) . '</td></tr>';
if ( ++$response_count >= $response_limit && $response_count < $total_responses) {
$response_rows .= '<tr><td class="score others">' . intval($total_responses - $response_limit) . '</td><td class="response others">more "other" responses</td></tr>';
break;
}
}
$table .= $question_row . $response_rows;
}
echo $styles;
echo '<table class="survey_table">' . $table . '</table>';
echo '<p class="textright"><a class="button button-primary" href="' . add_query_arg('wksurvey','download',admin_url()) . '">Download Results as CSV</a></p>';
}
private function download() {
$data = get_option(self::DATA_SETTING_NAME);
$table = '';
header('Content-type: text/csv; charset=UTF-8');
header('Content-Disposition: attachment; filename="webkit_nightly_survey.csv"');
header('Content-Description: Delivered by webkit.org');
header('Cache-Control: maxage=1');
header('Pragma: public');
foreach ($data as $question => $responses) {
$question_row = 'Score,' . $question . "\n";
$response_rows = '';
arsort($responses);
foreach ($responses as $response => $votes) {
$response_rows .= intval($votes) . ',' . stripslashes($response) . "\n";
}
$table .= $question_row . $response_rows . "\n";
}
echo $table;
exit;
}
public function process() {
if ( empty($_POST) ) return;
if ( ! wp_verify_nonce($_POST['_nonce'], self::SURVEY_FILENAME) )
wp_die('Invalid WebKit Nightly Survey submission.');
$score = $data = get_option(self::DATA_SETTING_NAME);
$Survey = self::survey();
foreach ($Survey as $id => $SurveyQuestion) {
if ( ! isset($score[ $SurveyQuestion->question ]) )
$score[ $SurveyQuestion->question ] = array();
$response = $_POST['questions'][ $id ];
$answer = empty($SurveyQuestion->responses[ $response ]) ? $response : $SurveyQuestion->responses[ $response ];
if ($answer == 'Other:')
$answer = $_POST['other'][ $id ];
$score[ $SurveyQuestion->question ][ $answer ]++;
}
if ( $data === false ) {
$deprecated = null;
$autoload = 'no';
add_option(self::DATA_SETTING_NAME, $score, $deprecated, $autoload);
} else {
update_option(self::DATA_SETTING_NAME, $score);
}
$httponly = false;
$secure = false;
setcookie(self::cookie_name(), 1, time() + YEAR_IN_SECONDS, '/', WP_HOST, $secure, $httponly );
$_COOKIE[ self::cookie_name() ] = 1;
}
public static function responded() {
return isset($_COOKIE[ self::cookie_name() ]);
}
private static function cookie_name() {
return self::COOKIE_PREFIX . COOKIEHASH;
}
public static function survey_file() {
return dirname(__FILE__) . '/' . self::SURVEY_FILENAME;
}
public static function form_nonce() {
return '<input type="hidden" name="_nonce" value="' . wp_create_nonce( self::SURVEY_FILENAME ) . '">';
}
public static function survey () {
$survey_json = file_get_contents(self::survey_file());
$Decoded = json_decode($survey_json);
return isset($Decoded->survey) ? $Decoded->survey : array();
}
}
/** Workaround to support <dialog> tags by customizing the built-in wpautop() function **/
remove_filter('the_content', 'wpautop');
add_filter('the_content', function ($pee, $br = true) {
/**
* Replaces double line breaks with paragraph elements.
*
* A group of regex replaces used to identify text formatted with newlines and
* replace double line breaks with HTML paragraph tags. The remaining line breaks
* after conversion become <<br />> tags, unless $br is set to '0' or 'false'.
*
* @since 0.71
*
* @param string $pee The text which has to be formatted.
* @param bool $br Optional. If set, this will convert all remaining line breaks
* after paragraphing. Line breaks within `<script>`, `<style>`,
* and `<svg>` tags are not affected. Default true.
* @return string Text which has been converted into correct paragraph tags.
*/
$pre_tags = array();
if ( trim( $pee ) === '' ) {
return '';
}
// Just to make things a little easier, pad the end.
$pee = $pee . "\n";
/*
* Pre tags shouldn't be touched by autop.
* Replace pre tags with placeholders and bring them back after autop.
*/
if ( strpos( $pee, '<pre' ) !== false ) {
$pee_parts = explode( '</pre>', $pee );
$last_pee = array_pop( $pee_parts );
$pee = '';
$i = 0;
foreach ( $pee_parts as $pee_part ) {
$start = strpos( $pee_part, '<pre' );
// Malformed HTML?
if ( false === $start ) {
$pee .= $pee_part;
continue;
}
$name = "<pre wp-pre-tag-$i></pre>";
$pre_tags[ $name ] = substr( $pee_part, $start ) . '</pre>';
$pee .= substr( $pee_part, 0, $start ) . $name;
$i++;
}
$pee .= $last_pee;
}
// Change multiple <br>'s into two line breaks, which will turn into paragraphs.
$pee = preg_replace( '|<br\s*/?>\s*<br\s*/?>|', "\n\n", $pee );
$allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary|dialog)';
// Add a double line break above block-level opening tags.
$pee = preg_replace( '!(<' . $allblocks . '[\s/>])!', "\n\n$1", $pee );
// Add a double line break below block-level closing tags.
$pee = preg_replace( '!(</' . $allblocks . '>)!', "$1\n\n", $pee );
// Add a double line break after hr tags, which are self closing.
$pee = preg_replace( '!(<hr\s*?/?>)!', "$1\n\n", $pee );
// Standardize newline characters to "\n".
$pee = str_replace( array( "\r\n", "\r" ), "\n", $pee );
// Find newlines in all elements and add placeholders.
$pee = wp_replace_in_html_tags( $pee, array( "\n" => ' <!-- wpnl --> ' ) );
// Collapse line breaks before and after <option> elements so they don't get autop'd.
if ( strpos( $pee, '<option' ) !== false ) {
$pee = preg_replace( '|\s*<option|', '<option', $pee );
$pee = preg_replace( '|</option>\s*|', '</option>', $pee );
}
/*
* Collapse line breaks inside <object> elements, before <param> and <embed> elements
* so they don't get autop'd.
*/
if ( strpos( $pee, '</object>' ) !== false ) {
$pee = preg_replace( '|(<object[^>]*>)\s*|', '$1', $pee );
$pee = preg_replace( '|\s*</object>|', '</object>', $pee );
$pee = preg_replace( '%\s*(</?(?:param|embed)[^>]*>)\s*%', '$1', $pee );
}
/*
* Collapse line breaks inside <audio> and <video> elements,
* before and after <source> and <track> elements.
*/
if ( strpos( $pee, '<source' ) !== false || strpos( $pee, '<track' ) !== false ) {
$pee = preg_replace( '%([<\[](?:audio|video)[^>\]]*[>\]])\s*%', '$1', $pee );
$pee = preg_replace( '%\s*([<\[]/(?:audio|video)[>\]])%', '$1', $pee );
$pee = preg_replace( '%\s*(<(?:source|track)[^>]*>)\s*%', '$1', $pee );
}
// Collapse line breaks before and after <figcaption> elements.
if ( strpos( $pee, '<figcaption' ) !== false ) {
$pee = preg_replace( '|\s*(<figcaption[^>]*>)|', '$1', $pee );
$pee = preg_replace( '|</figcaption>\s*|', '</figcaption>', $pee );
}
// Remove more than two contiguous line breaks.
$pee = preg_replace( "/\n\n+/", "\n\n", $pee );
// Split up the contents into an array of strings, separated by double line breaks.
$pees = preg_split( '/\n\s*\n/', $pee, -1, PREG_SPLIT_NO_EMPTY );
// Reset $pee prior to rebuilding.
$pee = '';
// Rebuild the content as a string, wrapping every bit with a <p>.
foreach ( $pees as $tinkle ) {
$pee .= '<p>' . trim( $tinkle, "\n" ) . "</p>\n";
}
// Under certain strange conditions it could create a P of entirely whitespace.
$pee = preg_replace( '|<p>\s*</p>|', '', $pee );
// Add a closing <p> inside <div>, <address>, or <form> tag if missing.
$pee = preg_replace( '!<p>([^<]+)</(div|address|form)>!', '<p>$1</p></$2>', $pee );
// If an opening or closing block element tag is wrapped in a <p>, unwrap it.
$pee = preg_replace( '!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', '$1', $pee );
// In some cases <li> may get wrapped in <p>, fix them.
$pee = preg_replace( '|<p>(<li.+?)</p>|', '$1', $pee );
// If a <blockquote> is wrapped with a <p>, move it inside the <blockquote>.
$pee = preg_replace( '|<p><blockquote([^>]*)>|i', '<blockquote$1><p>', $pee );
$pee = str_replace( '</blockquote></p>', '</p></blockquote>', $pee );
// If an opening or closing block element tag is preceded by an opening <p> tag, remove it.
$pee = preg_replace( '!<p>\s*(</?' . $allblocks . '[^>]*>)!', '$1', $pee );
// If an opening or closing block element tag is followed by a closing <p> tag, remove it.
$pee = preg_replace( '!(</?' . $allblocks . '[^>]*>)\s*</p>!', '$1', $pee );
// Optionally insert line breaks.
if ( $br ) {
// Replace newlines that shouldn't be touched with a placeholder.
$pee = preg_replace_callback( '/<(script|style|svg).*?<\/\\1>/s', '_autop_newline_preservation_helper', $pee );
// Normalize <br>
$pee = str_replace( array( '<br>', '<br/>' ), '<br />', $pee );
// Replace any new line characters that aren't preceded by a <br /> with a <br />.
$pee = preg_replace( '|(?<!<br />)\s*\n|', "<br />\n", $pee );
// Replace newline placeholders with newlines.
$pee = str_replace( '<WPPreserveNewline />', "\n", $pee );
}
// If a <br /> tag is after an opening or closing block tag, remove it.
$pee = preg_replace( '!(</?' . $allblocks . '[^>]*>)\s*<br />!', '$1', $pee );
// If a <br /> tag is before a subset of opening or closing block tags, remove it.
$pee = preg_replace( '!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee );
$pee = preg_replace( "|\n</p>$|", '</p>', $pee );
// Replace placeholder <pre> tags with their original content.
if ( ! empty( $pre_tags ) ) {
$pee = str_replace( array_keys( $pre_tags ), array_values( $pre_tags ), $pee );
}
// Restore newlines in all elements.
if ( false !== strpos( $pee, '<!-- wpnl -->' ) ) {
$pee = str_replace( array( ' <!-- wpnl --> ', '<!-- wpnl -->' ), "\n", $pee );
}
return $pee;
});