diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php
index a0438e9c53..7b0d9a89bc 100644
--- a/src/wp-includes/formatting.php
+++ b/src/wp-includes/formatting.php
@@ -609,6 +609,145 @@ function wpautop( $pee, $br = true ) {
 	return $pee;
 }

+/**
+ * Replaces <p> tags with two line breaks. "Opposite" of autop().
+ *
+ * Replaces <p> tags with two line breaks except where the <p> has attributes.
+ * Unifies whitespace. Indents <li>, <dt> and <dd> for better readability.
+ *
+ * @param  String html The content from the editor.
+ * @return String      The content with stripped paragraph tags.
+ */
+function wpremovep( $html ) {
+    $blocklist = 'blockquote|ul|ol|li|dl|dt|dd|table|thead|tbody|tfoot|tr|th|td|h[1-6]|fieldset|figure';
+    $blocklist1 = $blocklist . '|div|p';
+    $blocklist2 = $blocklist . '|pre';
+
+    $preserve = [];
+    $preserveLinebreaks = false;
+    $preserveBr = false;
+
+	if ( !$html ) {
+        return '';
+    }
+
+    // Protect script and style tags.
+    if ( strpos($html, "<script") !== false || strpos($html, "<style") !== false) {
+        $html = preg_replace_callback( '/<(script|style)[^>]*>[\s\S]*?<\/\1>/', function( $match ) use (&$preserve) {
+            array_push($preserve, $match[0]);
+            return '<wp-preserve>';
+        }, $html );
+	}
+
+    // Protect pre tags.
+    if ( strpos($html, "<pre") !== false ) {
+        $preserveLinebreaks = true;
+        $html = preg_replace_callback( '/<pre[^>]*>[\s\S]+?<\/pre>/', function( $matches ) {
+            $match = $matches[0];
+            $match = preg_replace( '/<b'.'r ?\/?>(\r\n|\n)?/', '<wp-line-break>', $match );
+            $match = preg_replace( '/<\/?p( [^>]*)?>(\r\n|\n)?/', '<wp-line-break>', $match );
+            $match = preg_replace( '/\r?\n/', '<wp-line-break>', $match );
+
+            return $match;
+        }, $html );
+    }
+
+    // Remove line breaks but keep <br> tags inside image captions.
+    if ( strpos($html, "[caption") !== false ) {
+        $preserveBr = true;
+        $html = preg_replace_callback( '/\[caption[\s\S]+?\[\/caption\]/', function( $matches ) {
+            $match = $matches[0];
+            $match = preg_replace( '/<br([^>]*)>/', "<wp-temp-br$1>", $match );
+            $match = preg_replace( '/[\r\n\t]+/', '', $match );
+
+            return $match;
+        }, $html );
+    }
+
+    // Normalize white space characters before and after block tags.
+    $html = preg_replace( '/\s*<\/(' . $blocklist1 . ')>\s*/' , "</$1>\n", $html );
+    $html = preg_replace( '/\s*<((?:' . $blocklist1 . ')(?: [^>]*)?)>/', "\n<$1>", $html );
+
+    // Mark </p> if it has any attributes.
+    // weird '<"."p' thing to avois IDE bugs trying to parse html
+    $html = preg_replace( "/(<"."p [^>]+>.*?)<\/p>/", '$1</p#>', $html );
+
+    // Preserve the first <p> inside a <div>.
+    $html = preg_replace( '/<div( [^>]*)?>\s*<p>/i', "<div$1>\n\n", $html );
+
+    // Remove paragraph tags.
+    $html = preg_replace( '/\s*<p>/i', '', $html);
+    $html = preg_replace( '/\s*<\/p>\s*/i', "\n\n", $html);
+
+    // Normalize white space chars and remove multiple line breaks.
+    $html = preg_replace( '/\n[\s\n]+\n/', "\n\n", $html);
+
+    // Replace <br> tags with line breaks.
+    $html = preg_replace_callback( '/(\s*)<br\s?\/?>\s*/i', function( $match ) {
+        return ( strpos($match[1], "\n") !== false ) ? "\n\n" : "\n";
+    }, $html);
+
+    // Fix line breaks around <div>.
+    $html = preg_replace( '/\s*<div/', "\n<div", $html );
+    $html = preg_replace( '/<\/div>\s*/', "</div>\n", $html );
+
+    // Fix line breaks around caption shortcodes.
+    $html = preg_replace( '/\s*\[caption([^\[]+)\[\/caption\]\s*/i', "\n\n[caption$1[/caption]\n\n", $html );
+    $html = preg_replace( '/caption\]\n\n+\[caption/', "caption]\n\n[caption", $html );
+
+    // Pad block elements tags with a line break.
+    $html = preg_replace( '/\s*<((?:' . $blocklist2 . ')(?: [^>]*)?)\s*>/', "\n<$1>", $html );
+    $html = preg_replace( '/\s*<\/(' . $blocklist2 . ')>\s*/', "</$1>\n", $html );
+
+    // Indent <li>, <dt> and <dd> tags.
+    $html = preg_replace( '/<((li|dt|dd)[^>]*)>/', " \t<$1>" , $html);
+
+    // Fix line breaks around <select> and <option>.
+    if ( strpos($html, "<option") !== false ) {
+        $html = preg_replace( '/\s*<option/', "\n \t<option", $html );
+        $html = preg_replace( '/\s*<\/select>/', "\n</select>\n", $html );
+    }
+
+    // Pad <hr> with two line breaks.
+    if ( strpos($html, "<hr") !== false ) {
+        $html = preg_replace( '/\s*<hr( [^>]*)?>\s*/', "\n\n<hr$1>\n\n", $html );
+    }
+
+    // Remove line breaks in <object> tags.
+    if ( strpos($html, "<object") !== false ) {
+        $html = preg_replace_callback( '/<object[\s\S]+?<\/object>/', function( $a ) {
+            return preg_replace( "/[\r\n]+/", '', $a[0] );
+        }, $html );
+    }
+
+    // Unmark special paragraph closing tags.
+    $html = preg_replace( '/<\/p#>/', "</p>\n", $html );
+
+    // Pad remaining <p> tags whit a line break.
+    $html = preg_replace( '/\s*(<'.'p [^>]+>[\s\S]*?<\/p>)/', "\n$1", $html );
+
+    // Trim.
+    $html = preg_replace( "/^\s+/", '' , $html);
+    $html = preg_replace( "/[\s\n]+$/", '' , $html);
+
+    if ( $preserveLinebreaks ) {
+        $html = preg_replace( '/<wp-line-break>/', "\n", $html );
+    }
+
+    if ( $preserveBr ) {
+        $html = preg_replace( '/<wp-temp-br([^>]*)>/', "<br$1>", $html );
+    }
+
+    // Restore preserved tags.
+    if ( count($preserve) > 0 ) {
+        $html = preg_replace_callback( '/<wp-preserve>/', function() use (&$preserve) {
+            return array_shift($preserve);
+        }, $html );
+    }
+
+    return $html;
+}
+
 /**
  * Separate HTML elements and comments from the text.
  *
diff --git a/tests/phpunit/tests/formatting/Removep.php b/tests/phpunit/tests/formatting/Removep.php
new file mode 100644
index 0000000000..18a446bdbe
--- /dev/null
+++ b/tests/phpunit/tests/formatting/Removep.php
@@ -0,0 +1,351 @@
+<?php
+
+/**
+ * @group formatting
+ * @ticket 45435
+ */
+class Tests_Formatting_Removep extends WP_UnitTestCase {
+    public function test_remove_p() {
+        $test_data  = '<p>Welcome to WordPress!  This post contains important information.  After you read it, you can make it private to hide it from visitors but still have the information handy for future reference.</p>
+<p></p>
+<p>First things first:</p>
+';
+        $expected = 'Welcome to WordPress!  This post contains important information.  After you read it, you can make it private to hide it from visitors but still have the information handy for future reference.
+
+First things first:';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+
+    public function test_remove_br() {
+        $test_data  = '<p>Welcome to WordPress!<br />This post contains important information.<br>After you read it, you can make it private to hide it from visitors but still have the information handy for future reference.</p>
+<p>Test<br />   <br >   <br>Test</p>
+<p>First things first:</p>
+';
+        $expected = 'Welcome to WordPress!
+This post contains important information.
+After you read it, you can make it private to hide it from visitors but still have the information handy for future reference.
+
+Test
+
+
+Test
+
+First things first:';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+
+    public function test_line_break_around_div() {
+        $test_data  = '<p>Hello</p><div>World</div><p>!!</p>';
+        $expected = 'Hello
+<div>World</div>
+!!';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+
+    public function test_line_break_around_caption() {
+        $test_data  = '<p>Hello</p>[caption id="1"]whatever 1[/caption]<p>!!</p>[caption id="2"]whatever 2[/caption][caption id="3"]whatever 3[/caption]';
+        $expected = 'Hello
+
+[caption id="1"]whatever 1[/caption]
+
+!!
+
+[caption id="2"]whatever 2[/caption]
+
+[caption id="3"]whatever 3[/caption]';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+
+    public function test_line_break_around_block_elements() {
+
+        //const blocklist = 'blockquote|ul|ol|li|dl|dt|dd|table|thead|tbody|tfoot|tr|th|td|h[1-6]|fieldset|figure';
+        //const blocklist1 = blocklist + '|div|p';
+        //const blocklist2 = blocklist + '|pre';
+
+        $test_data  = '<p>Hello</p>
+
+<blockquote cite="https://www.huxley.net/bnw/four.html">
+    <p>Words can be like X-rays, if you use them properly – they\'ll go through anything. You read and you\'re pierced.</p>
+</blockquote>
+<h1>This is an UL</h1><ul>
+    <li>Milk</li><li>Cheese
+        <ul><li>Blue cheese</li><li>Feta</li>    </ul>
+    </li>
+</ul><h2>This is an OL</h2>
+<ol> <li>Mix flour, baking powder, sugar, and salt.</li><li>In another bowl, mix eggs, milk, and oil.</li>
+  <li>Stir both mixtures together.</li>
+  <li>Fill muffin tray 3/4 full.</li><li>Bake for 20 minutes.</li>
+</ol>
+
+<p>Cryptids of Cornwall:</p>
+<h3>This is an DL</h3>
+<dl>
+    <dt>Beast of Bodmin</dt><dd>A large feline inhabiting Bodmin Moor.</dd>
+    <dt>Morgawr</dt><dd>A sea serpent.</dd>
+    <dt>Owlman</dt><dd>A giant owl-like creature.</dd>
+</dl>
+<h4>This is an TABLE</h4><table>
+    <thead>
+        <tr>
+            <th colspan="2">The table header</th>
+        </tr>
+    </thead>
+    <tbody>
+        <tr>
+            <td>The table body</td>
+            <td>with two columns</td>
+        </tr>
+    </tbody>
+</table><pre>
+  L          TE
+    A       A
+      C    V
+       R A
+       DOU
+       LOU
+      REUSE
+      QUE TU
+      PORTES
+    ET QUI T\'
+    ORNE O CI
+     VILISÉ
+    OTE-  TU VEUX
+     LA    BIEN
+    SI      RESPI
+            RER       - Apollinaire
+</pre>
+
+';
+        $expected = 'Hello
+<blockquote cite="https://www.huxley.net/bnw/four.html">Words can be like X-rays, if you use them properly – they\'ll go through anything. You read and you\'re pierced.</blockquote>
+<h1>This is an UL</h1>
+<ul>
+ 	<li>Milk</li>
+ 	<li>Cheese
+<ul>
+ 	<li>Blue cheese</li>
+ 	<li>Feta</li>
+</ul>
+</li>
+</ul>
+<h2>This is an OL</h2>
+<ol>
+ 	<li>Mix flour, baking powder, sugar, and salt.</li>
+ 	<li>In another bowl, mix eggs, milk, and oil.</li>
+ 	<li>Stir both mixtures together.</li>
+ 	<li>Fill muffin tray 3/4 full.</li>
+ 	<li>Bake for 20 minutes.</li>
+</ol>
+Cryptids of Cornwall:
+<h3>This is an DL</h3>
+<dl>
+ 	<dt>Beast of Bodmin</dt>
+ 	<dd>A large feline inhabiting Bodmin Moor.</dd>
+ 	<dt>Morgawr</dt>
+ 	<dd>A sea serpent.</dd>
+ 	<dt>Owlman</dt>
+ 	<dd>A giant owl-like creature.</dd>
+</dl>
+<h4>This is an TABLE</h4>
+<table>
+<thead>
+<tr>
+<th colspan="2">The table header</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>The table body</td>
+<td>with two columns</td>
+</tr>
+</tbody>
+</table>
+<pre>
+  L          TE
+    A       A
+      C    V
+       R A
+       DOU
+       LOU
+      REUSE
+      QUE TU
+      PORTES
+    ET QUI T\'
+    ORNE O CI
+     VILISÉ
+    OTE-  TU VEUX
+     LA    BIEN
+    SI      RESPI
+            RER       - Apollinaire
+</pre>';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+
+    public function test_line_break_around_select() {
+        $test_data  = '<p>Hello</p><select><option value="1">Value 1</option>
+<option value="2">Value 2</option></select><p>World</p>';
+
+        $expected = 'Hello
+
+<select>
+ 	<option value="1">Value 1</option>
+ 	<option value="2">Value 2</option>
+</select>
+World';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+
+    public function test_line_break_around_hr() {
+        $test_data  = '<p>Hello</p><hr /><p>World</p>';
+
+        $expected = 'Hello
+
+<hr />
+
+World';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+
+    public function test_first_p_in_div() {
+        $test_data  = '<p>Hello</p><div><p>World</p></div>';
+
+        $expected = 'Hello
+<div>
+
+World
+
+</div>';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+
+    public function test_remove_break_in_object() {
+        $test_data  = '<p>Hello</p><object><p>World</p></object>';
+
+        $expected = 'Hello
+
+<object>World</object>';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+
+    public function test_mark_p_with_attributes() {
+        $test_data  = '<p>Welcome to WordPress!  This post contains important information.  After you read it, you can make it private to hide it from visitors but still have the information handy for future reference.</p><p>New P here</p>
+<p></p><p style="color:red">First things first</p><p style="color:blue">Last things last</p>
+';
+        $expected = 'Welcome to WordPress!  This post contains important information.  After you read it, you can make it private to hide it from visitors but still have the information handy for future reference.
+
+New P here
+<p style="color:red">First things first</p>
+<p style="color:blue">Last things last</p>';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+
+    public function test_preserve_scripts_and_styles() {
+        $test_data  = '<p>Welcome to WordPress!</p><p>We test here</p>
+<script>
+    const html = "<p>Preserve script</p>"
+</script>
+<style type="text/css">p.preserve {
+    content: "<p>Preserve style</p>"
+}</style><p>End of test</p>
+';
+        $expected = 'Welcome to WordPress!
+
+We test here
+
+<script>
+    const html = "<p>Preserve script</p>"
+</script>
+<style type="text/css">p.preserve {
+    content: "<p>Preserve style</p>"
+}</style>End of test';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+
+    public function test_protect_pre() {
+
+        $test_data  = '<p>Hello</p>
+<pre>
+<p>Protect me</p>
+<br />
+<p>Please</p><br />
+<p>Thank you.</p>
+</pre>
+
+';
+        $expected = 'Hello
+<pre>
+
+Protect me
+
+
+Please
+
+
+Thank you.
+</pre>';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+
+    public function test_protect_caption_br() {
+
+        $test_data  = 'Hello<br />[caption]this<br>is<br />a caption[/caption]World';
+        $expected = 'Hello
+
+[caption]this<br>is<br />a caption[/caption]
+
+World';
+
+        // On windows environments, the EOL-style is \r\n
+        $test_data = str_replace( "\r\n", "\n", $test_data );
+
+        $this->assertEquals( $expected, wpremovep( $test_data ) );
+    }
+}
