-
Notifications
You must be signed in to change notification settings - Fork 2k
/
rule-create-better-excerpt.js
126 lines (104 loc) · 3.29 KB
/
rule-create-better-excerpt.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/**
* External dependencies
*/
import striptags from 'striptags';
import { trim, toArray, forEach } from 'lodash';
/**
* Internal Dependencies
*/
import { domForHtml } from './utils';
/**
* Removes an HTML element from the DOM
*
* @param {Node} element DOM element to remove
*/
function removeElement( element ) {
element.parentNode && element.parentNode.removeChild( element );
}
/**
* Trims any empty starting `br` tags. Recurses into non-empty tags.
* will remove all of the leading `br`s it can find.
*
* @param {Node} dom DOM element to remove br tags from.
*/
function stripLeadingBreaklines( dom ) {
if ( ! dom ) {
return;
}
// first element is breakline actually returns the node in case of success
while ( firstElementIsBreakline( dom ) ) {
removeElement( firstElementIsBreakline( dom ) );
}
}
/**
* Returns the node if first element ( checking nested ) is a `br`
* else returns falsy
*
* @param {Node} dom DOM element to check
*/
function firstElementIsBreakline( dom ) {
if ( dom.childNodes.length === 0 ) {
return dom.nodeName === 'BR' && dom;
}
return firstElementIsBreakline( dom.firstChild );
}
function buildStrippedDom( content ) {
// Spin up a new DOM for the linebreak markup
const dom = domForHtml( content );
// Ditch any photo captions, styles, scripts
const stripSelectors =
'.wp-caption, style, script, blockquote[class^="instagram-"], figure, .tiled-gallery';
forEach( dom.querySelectorAll( stripSelectors ), removeElement );
return dom.innerHTML;
}
export function formatExcerpt( content ) {
if ( ! content ) {
return '';
}
const dom = domForHtml( striptags( content, [ 'p', 'br', 'sup', 'sub' ] ) );
dom.id = '__better_excerpt__';
// strip any p's that are empty
toArray( dom.querySelectorAll( 'p' ) )
.filter( ( element ) => trim( element.textContent ).length === 0 )
.forEach( removeElement );
// remove styles for all p's that remain
toArray( dom.querySelectorAll( 'p' ) ).forEach( ( element ) => {
element.removeAttribute( 'style' );
element.removeAttribute( 'align' );
} );
stripLeadingBreaklines( dom );
// now limit it to the first three elements
forEach(
dom.querySelectorAll( '#__better_excerpt__ > p, #__better_excerpt__ > br' ),
function ( element, index ) {
if ( index >= 3 ) {
element.parentNode && element.parentNode.removeChild( element );
}
}
);
// trim and replace entities
const betterExcerpt = trim( dom.innerHTML.replace( / /g, ' ' ) );
dom.innerHTML = '';
return betterExcerpt;
}
export default function createBetterExcerpt( post ) {
if ( ! post || ! post.content ) {
return post;
}
const strippedDom = buildStrippedDom( post.content );
post.content_no_html = trim( striptags( strippedDom ) );
post.better_excerpt = formatExcerpt( strippedDom );
post.better_excerpt_no_html = trim( striptags( post.better_excerpt ) );
// also make a shorter excerpt...
if ( post.better_excerpt_no_html ) {
// replace any trailing [...] with an actual ellipsis
let shorterExcerpt = post.better_excerpt_no_html.replace( /\[...\]\w*$/, '…' );
// limit to 160 characters
if ( shorterExcerpt.length > 160 ) {
const lastSpace = shorterExcerpt.lastIndexOf( ' ', 160 );
shorterExcerpt = shorterExcerpt.substring( 0, lastSpace ) + '…';
}
post.short_excerpt = shorterExcerpt;
}
return post;
}