← All changes
|
features/content-restriction/content-restriction-filtering.php
+238
-2
3.15.9
→
4.0.3
View file →
| @@ -240,8 +240,242 @@ | ||
| 240 | 240 | } |
| 241 | 241 | add_filter( 'wppb_content_restriction_message_logged_in', 'wppb_content_restriction_message_wpautop', 30, 1 ); |
| 242 | 242 | add_filter( 'wppb_content_restriction_message_logged_out', 'wppb_content_restriction_message_wpautop', 30, 1 ); |
| 243 | 243 | |
| 244 | +function wppb_content_restriction_get_post_preview_allowed_html() { | |
| 245 | + $allowed_post_html = wp_kses_allowed_html( 'post' ); | |
| 246 | + $allowed_tags = array( | |
| 247 | + 'a', | |
| 248 | + 'abbr', | |
| 249 | + 'acronym', | |
| 250 | + 'b', | |
| 251 | + 'blockquote', | |
| 252 | + 'br', | |
| 253 | + 'cite', | |
| 254 | + 'code', | |
| 255 | + 'dd', | |
| 256 | + 'del', | |
| 257 | + 'details', | |
| 258 | + 'div', | |
| 259 | + 'dl', | |
| 260 | + 'dt', | |
| 261 | + 'em', | |
| 262 | + 'h1', | |
| 263 | + 'h2', | |
| 264 | + 'h3', | |
| 265 | + 'h4', | |
| 266 | + 'h5', | |
| 267 | + 'h6', | |
| 268 | + 'hr', | |
| 269 | + 'i', | |
| 270 | + 'ins', | |
| 271 | + 'kbd', | |
| 272 | + 'li', | |
| 273 | + 'mark', | |
| 274 | + 'ol', | |
| 275 | + 'p', | |
| 276 | + 'pre', | |
| 277 | + 'q', | |
| 278 | + 's', | |
| 279 | + 'samp', | |
| 280 | + 'small', | |
| 281 | + 'span', | |
| 282 | + 'strike', | |
| 283 | + 'strong', | |
| 284 | + 'sub', | |
| 285 | + 'summary', | |
| 286 | + 'sup', | |
| 287 | + 'table', | |
| 288 | + 'tbody', | |
| 289 | + 'td', | |
| 290 | + 'tfoot', | |
| 291 | + 'th', | |
| 292 | + 'thead', | |
| 293 | + 'tr', | |
| 294 | + 'u', | |
| 295 | + 'ul', | |
| 296 | + 'var', | |
| 297 | + ); | |
| 298 | + $allowed_html = array(); | |
| 299 | + | |
| 300 | + foreach( $allowed_tags as $tag ) { | |
| 301 | + if( isset( $allowed_post_html[ $tag ] ) ) { | |
| 302 | + $allowed_html[ $tag ] = $allowed_post_html[ $tag ]; | |
| 303 | + } | |
| 304 | + } | |
| 305 | + | |
| 306 | + return apply_filters( 'wppb_content_restriction_post_preview_allowed_html', $allowed_html ); | |
| 307 | +} | |
| 308 | + | |
| 309 | +function wppb_content_restriction_sanitize_post_preview_html( $html ) { | |
| 310 | + $html = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $html ); | |
| 311 | + | |
| 312 | + return wp_kses( $html, wppb_content_restriction_get_post_preview_allowed_html() ); | |
| 313 | +} | |
| 314 | + | |
| 315 | +function wppb_content_restriction_get_text_count_units( $text, $offsets = false ) { | |
| 316 | + if( str_starts_with( wp_get_word_count_type(), 'characters' ) && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ) ) { | |
| 317 | + $pattern = ( wp_get_word_count_type() === 'characters_excluding_spaces' ) ? '/[^\n\r\t ]/u' : '/./u'; | |
| 318 | + } else { | |
| 319 | + $pattern = '/[^\n\r\t ]+/u'; | |
| 320 | + } | |
| 321 | + | |
| 322 | + preg_match_all( $pattern, $text, $units, ( $offsets ? PREG_OFFSET_CAPTURE : 0 ) ); | |
| 323 | + | |
| 324 | + return $units[0]; | |
| 325 | +} | |
| 326 | + | |
| 327 | +function wppb_content_restriction_count_dom_node_words( $node ) { | |
| 328 | + $count = 0; | |
| 329 | + | |
| 330 | + if( ! $node->hasChildNodes() ) { | |
| 331 | + return $count; | |
| 332 | + } | |
| 333 | + | |
| 334 | + foreach( $node->childNodes as $child ) { | |
| 335 | + if( $child->nodeType === XML_TEXT_NODE || $child->nodeType === XML_CDATA_SECTION_NODE ) { | |
| 336 | + $count += count( wppb_content_restriction_get_text_count_units( $child->nodeValue ) ); | |
| 337 | + } else { | |
| 338 | + $count += wppb_content_restriction_count_dom_node_words( $child ); | |
| 339 | + } | |
| 340 | + } | |
| 341 | + | |
| 342 | + return $count; | |
| 343 | +} | |
| 344 | + | |
| 345 | +function wppb_content_restriction_trim_text_node_words( $text, &$remaining_words, $more, &$trimmed, &$last_text_node ) { | |
| 346 | + $words = wppb_content_restriction_get_text_count_units( $text, true ); | |
| 347 | + | |
| 348 | + if( empty( $words ) ) { | |
| 349 | + return $text; | |
| 350 | + } | |
| 351 | + | |
| 352 | + if( $remaining_words <= 0 ) { | |
| 353 | + if( ! empty( $last_text_node ) ) { | |
| 354 | + $last_text_node->nodeValue = rtrim( $last_text_node->nodeValue ) . $more; | |
| 355 | + } | |
| 356 | + | |
| 357 | + $trimmed = true; | |
| 358 | + | |
| 359 | + return ''; | |
| 360 | + } | |
| 361 | + | |
| 362 | + $word_count = count( $words ); | |
| 363 | + | |
| 364 | + if( $word_count < $remaining_words ) { | |
| 365 | + $remaining_words -= $word_count; | |
| 366 | + | |
| 367 | + return $text; | |
| 368 | + } | |
| 369 | + | |
| 370 | + $last_text_node = null; | |
| 371 | + | |
| 372 | + if( $word_count === $remaining_words ) { | |
| 373 | + $remaining_words = 0; | |
| 374 | + | |
| 375 | + return $text; | |
| 376 | + } | |
| 377 | + | |
| 378 | + $last_word = $words[ $remaining_words - 1 ]; | |
| 379 | + $cut_position = $last_word[1] + strlen( $last_word[0] ); | |
| 380 | + $remaining_words = 0; | |
| 381 | + $trimmed = true; | |
| 382 | + | |
| 383 | + return rtrim( substr( $text, 0, $cut_position ) ) . $more; | |
| 384 | +} | |
| 385 | + | |
| 386 | +function wppb_content_restriction_trim_dom_node_words( $node, &$remaining_words, $more, &$trimmed, &$last_text_node ) { | |
| 387 | + if( ! $node->hasChildNodes() ) { | |
| 388 | + return; | |
| 389 | + } | |
| 390 | + | |
| 391 | + $children = array(); | |
| 392 | + foreach( $node->childNodes as $child ) { | |
| 393 | + $children[] = $child; | |
| 394 | + } | |
| 395 | + | |
| 396 | + foreach( $children as $child ) { | |
| 397 | + if( $trimmed ) { | |
| 398 | + $node->removeChild( $child ); | |
| 399 | + continue; | |
| 400 | + } | |
| 401 | + | |
| 402 | + if( $child->nodeType === XML_TEXT_NODE || $child->nodeType === XML_CDATA_SECTION_NODE ) { | |
| 403 | + $child->nodeValue = wppb_content_restriction_trim_text_node_words( $child->nodeValue, $remaining_words, $more, $trimmed, $last_text_node ); | |
| 404 | + | |
| 405 | + if( ! $trimmed && ! empty( wppb_content_restriction_get_text_count_units( $child->nodeValue ) ) ) { | |
| 406 | + $last_text_node = $child; | |
| 407 | + } | |
| 408 | + | |
| 409 | + if( $trimmed && $child->nodeValue === '' ) { | |
| 410 | + $node->removeChild( $child ); | |
| 411 | + } | |
| 412 | + } else { | |
| 413 | + wppb_content_restriction_trim_dom_node_words( $child, $remaining_words, $more, $trimmed, $last_text_node ); | |
| 414 | + | |
| 415 | + if( $trimmed && ! $child->hasChildNodes() ) { | |
| 416 | + $node->removeChild( $child ); | |
| 417 | + } | |
| 418 | + } | |
| 419 | + } | |
| 420 | +} | |
| 421 | + | |
| 422 | +function wppb_content_restriction_trim_html_words( $html, $num_words, $more = null ) { | |
| 423 | + if( $more === null ) { | |
| 424 | + $more = __( '…', 'profile-builder' ); | |
| 425 | + } | |
| 426 | + | |
| 427 | + $num_words = (int) $num_words; | |
| 428 | + | |
| 429 | + if( $num_words <= 0 || $html === '' ) { | |
| 430 | + return ''; | |
| 431 | + } | |
| 432 | + | |
| 433 | + $html = wppb_content_restriction_sanitize_post_preview_html( $html ); | |
| 434 | + | |
| 435 | + if( ! class_exists( 'DOMDocument' ) ) { | |
| 436 | + return wpautop( wp_trim_words( $html, $num_words, $more ) ); | |
| 437 | + } | |
| 438 | + | |
| 439 | + $dom_flags = 0; | |
| 440 | + if( defined( 'LIBXML_HTML_NOIMPLIED' ) ) { | |
| 441 | + $dom_flags |= LIBXML_HTML_NOIMPLIED; | |
| 442 | + } | |
| 443 | + if( defined( 'LIBXML_HTML_NODEFDTD' ) ) { | |
| 444 | + $dom_flags |= LIBXML_HTML_NODEFDTD; | |
| 445 | + } | |
| 446 | + | |
| 447 | + $document = new DOMDocument(); | |
| 448 | + $previous_errors = libxml_use_internal_errors( true ); | |
| 449 | + $document->loadHTML( '<?xml encoding="UTF-8"><div id="wppb-content-restriction-preview-wrapper">' . $html . '</div>', $dom_flags ); | |
| 450 | + libxml_clear_errors(); | |
| 451 | + libxml_use_internal_errors( $previous_errors ); | |
| 452 | + | |
| 453 | + $wrapper = $document->getElementById( 'wppb-content-restriction-preview-wrapper' ); | |
| 454 | + | |
| 455 | + if( empty( $wrapper ) ) { | |
| 456 | + return wpautop( wp_trim_words( $html, $num_words, $more ) ); | |
| 457 | + } | |
| 458 | + | |
| 459 | + $remaining_words = $num_words; | |
| 460 | + $trimmed = false; | |
| 461 | + $last_text_node = null; | |
| 462 | + $more_text = html_entity_decode( $more, ENT_QUOTES | ENT_HTML5, get_option( 'blog_charset' ) ); | |
| 463 | + | |
| 464 | + if( wppb_content_restriction_count_dom_node_words( $wrapper ) <= $num_words ) { | |
| 465 | + return $html; | |
| 466 | + } | |
| 467 | + | |
| 468 | + wppb_content_restriction_trim_dom_node_words( $wrapper, $remaining_words, $more_text, $trimmed, $last_text_node ); | |
| 469 | + | |
| 470 | + $preview = ''; | |
| 471 | + foreach( $wrapper->childNodes as $child ) { | |
| 472 | + $preview .= $document->saveHTML( $child ); | |
| 473 | + } | |
| 474 | + | |
| 475 | + return $preview; | |
| 476 | +} | |
| 477 | + | |
| 244 | 478 | /* Adds a preview of the restricted post before the default restriction messages */ |
| 245 | 479 | function wppb_content_restriction_add_post_preview( $message, $content, $post, $user_ID ) { |
| 246 | 480 | |
| 247 | 481 | $preview = ''; |
| @@ -261,11 +495,13 @@ | ||
| 261 | 495 | if( $length !== 0 ) { |
| 262 | 496 | // Do shortcodes on the content |
| 263 | 497 | $post_content = do_shortcode( $post_content ); |
| 264 | 498 | |
| 265 | - // Trim the preview | |
| 266 | - $preview = wp_trim_words( $post_content, $length, apply_filters( 'wppb_content_restriction_post_preview_more', __( '…', 'profile-builder' ) ) ); | |
| 499 | + // Trim the preview while preserving the post's HTML structure. | |
| 500 | + $preview = wppb_content_restriction_trim_html_words( $post_content, $length, apply_filters( 'wppb_content_restriction_post_preview_more', __( '…', 'profile-builder' ) ) ); | |
| 267 | 501 | } |
| 502 | + | |
| 503 | + return $preview . $message; | |
| 268 | 504 | } |
| 269 | 505 | |
| 270 | 506 | // More tag |
| 271 | 507 | if( $preview_option == 'more-tag' ) { |