WordPress: Excerpt after text but before images - php

I am wondering how to do the following:
I want to do an excerpt after 45 words, but if the text of the post is less than 45 words and images are included in the post, then the more tag should be included right after the text.
1st: I would be happy with this solution.
2nd: Great might be to have in such a case an alternative sentence, e.g. "Click to see pictures.".
Hope this makes sense to anybody reading this.
Currently I have the following:
/*-----------------------------------------------------------------------------------*/
/* Sets the post excerpt length to 15 characters.
/*-----------------------------------------------------------------------------------*/
function moka_excerpt_length( $length ) {
return 45;
}
add_filter( 'excerpt_length', 'moka_excerpt_length' );
/*-----------------------------------------------------------------------------------*/
/* Returns a "Continue Reading" link for excerpts
/*-----------------------------------------------------------------------------------*/
function moka_excerpt_more( $more ) {
return '… <a class="read-more" href="'. get_permalink( get_the_ID() ) . '">' . __( 'Read more', 'moka' ) . '</a>';
}
add_filter( 'excerpt_more', 'moka_excerpt_more' );
Any help is much appreciated.
Many thanks and kind regards.

I think, You can write the code yourself.
You can add filter to the_content() or an alternative way:
Refer to this: http://wordpress.org/support/topic/executing-a-function-only-if-a-post-contains-an-image, you can check if the_content() has img or no?!
And for counting words in the_content() this answer is useful:
Counting words on a html web page using php

I did some deeper research and came up with the following. I know that it won't work, but some parts work as standalone, but I am not able to bring everything together. Maybe somebody can help to point me into the right direction?
function individual_excerpt_more( $more ) {
if {
function word_count() {
$content = get_post_field( 'post_content', $post->ID );
$word_count = str_word_count( strip_tags( $content ) );
return $word_count; <45 // (less than 45 words)
}
&& $content = $post->post_content;
if( has_shortcode( $content, 'gallery', 'video' ) ) {
// The content has a [gallery] & [video] short code, so this check returned true.
}
return '… <ins><a class="read-more" href="'. get_permalink( get_the_ID() ) . '">Read more</a></ins>';
}
else {
function theme_excerpt_length( $length ) {
return 45;
}
add_filter( 'excerpt_length', ’theme_excerpt_length' );
}
add_filter( 'excerpt_more', 'individual_excerpt_more' );

Related

How to add HTML markup and CSS style in PHP

I'm not versed in PHP. I've been trying to add css to the following php snippet but to no avail.
add_filter( 'gettext', 'change_related_products_title', 10, 3 );
function change_related_products_title( $translated, $text, $domain ) {
if( $text === 'Related products' && $domain === 'woocommerce' ){
$translated = esc_html__( 'These go well with', $domain ) . ' ' . esc_html( get_the_title() );
}
return $translated;
}
As far as I understand, echo works but it returns errors with the snippet. printf is closer to the result I want to achieve but it adds a random number which I have no idea what it represents.
Below is what I have attempted:
add_filter( 'gettext', 'change_related_products_title', 10, 3 );
function change_related_products_title( $translated, $text, $domain ) {
if( $text === 'Related products' && $domain === 'woocommerce' ){
$css = '<h1>Some Text</h1>';
$translated = printf($css , $domain ) . ' ' . esc_html( get_the_title() );
}
return $translated;
}
The above snippet returns: Some Text random number title.
The actual result I am trying to achieve is to have the output wrapped with css tag for styling purpose. For e.g. Like this:
Some Text title
That was not the random number, it is the count of the characters in $css.
The printf requires % identifier. Please refer to documentation
The html h1 is a block level element which will not display inline block with your title as your expected result. So you need to write your custom css to display it in-line block.
Hope below code will get you the required output
$css = '<div class="wrapping-class"><div class="custom-class">Some Text</div>%s</div>';
printf($css, esc_html( get_the_title() ));
Generated HTML Tags

Strip automatic P tags around images, videos, iframes in WordPress 4.9

THE ISSUE
I'm trying to size my YouTube video that I'm inserting and I got some working CSS to style it correctly, but the fact that WordPress keeps adding <P> tags around my video, image, and iframe tags is breaking my code. I'm only trying to remove paragraph tag wraps from elements (video/img/iframe) in blog content sections (not sidebars, widgets, footers, etc.)
CLIENT WEBSITE:
This website is for a client so the code needs to be as unobtrusive as possible. For instance, a good solution would be a custom shortcode, or something that allows me to target the videos with CSS styling rules.
Here is a blog post on the website in question:
http://ehepperle.com/in-progress/feelheal/11/how-to-create-125-px-ad-banner-gimp/
MY SYSTEM
WordPress: 4.9.6
Theme: Storefront
Website: http://ehepperle.com/in-progress/feelheal/11/how-to-create-125-px-ad-banner-gimp/
MY CODE
Since this is specific to WordPress filters rather than general coding concepts, I haven't found a way to make a good demonstration example, but here are code snippets showing what I've tried:
functions.php - ver. 1
// Remove P Tags Around Images
// From: http://justlearnwp.com/remove-p-tag-around-wordpress-images/
function filter_ptags_on_images($content){
return preg_replace('/<p>\s*(<a .*>)?\s*(<img .* \/>)\s*(<\/a>)?\s*<\/p>/iU', '\1\2\3', $content);
}
add_filter('the_content', 'filter_ptags_on_images');
functions.php - ver. 2
// https://stackoverflow.com/questions/44539888/remove-automatic-p-tag-in-wordpress#answer-44540531
function reformat_auto_p_tags($content) {
$new_content = '';
$pattern_full = '{(\[raw\].*?\[/raw\])}is';
$pattern_contents = '{\[raw\](.*?)\[/raw\]}is';
$pieces = preg_split($pattern_full, $content, -1, PREG_SPLIT_DELIM_CAPTURE);
foreach ($pieces as $piece) {
if (preg_match($pattern_contents, $piece, $matches)) {
$new_content .= $matches[1];
} else {
$new_content .= wptexturize(wpautop($piece));
}
}
return $new_content;
}
remove_filter('the_content', 'wpautop');
remove_filter('the_content', 'wptexturize');
add_filter('the_content', 'reformat_auto_p_tags', 99);
add_filter('widget_text', 'reformat_auto_p_tags', 99);
LINKS I REVIEWED BEFORE POSTING
I've tried solutions pieced together from these different possible solutions, all to no avail.
From: Remove automatic p tag in WordPress
http://justlearnwp.com/remove-p-tag-around-wordpress-images/
How to Remove P Tags Around Images in WordPress Posts From Source Code
https://www.daddydesign.com/wordpress/how-to-remove-the-paragraph-tag-from-images-inside-the-wordpress-post-content/
https://ahmadawais.com/remove-the-p-paragraph-tags-from-author-description-in-wordpress/
https://firstsiteguide.com/stop-adding-paragraphs-automatically/#comment-424246
https://codex.wordpress.org/Function_Reference/wpautop
http://micahjon.com/2016/removing-wrapping-p-paragraph-tags-around-images-wordpress/
How to remove p tag from wordpress
MY QUESTIONS
The following questions are actually multiple aspects of the same main question to gather the most complete understanding from various perspectives.
How can I remove <p> tags from iframes, video, and image tags in WordPress? The methods I've located from the past 2 years (and earlier) don't seem to work.
What is wrong with my code? Why are removing wpautop filters not working in my functions.php?
Did something change with WP version 4.8-4.9 that is making these filter hacks not work any more?
UPDATE: 2018-09-05
I'm adding my complete functions.php file in case anyone can help identify something that is causing a conflict. I don't see any, but maybe you will see something I missed.
functions.php (complete)
<?php
add_action( 'wp_enqueue_scripts', function() {
//* Parent CSS
wp_enqueue_style( 'storefront',
get_template_directory_uri() . '/style.css' );
//* Child CSS
wp_enqueue_style( 'storefront-ehw-1',
get_stylesheet_directory_uri() . '/style.css', [ 'storefront' ] );
} );
/* Adds search box to top nav menu
add_filter( 'wp_nav_menu_items','add_search_box', 10, 2 );
function add_search_box( $items, $args ) {
$items .= '<li class="widget widget_search">' . get_search_form( false ) . '</li>';
return $items;
}
*/
/* Hide categories from WordPress category widget
NOTE: 59 is the id of .Test-Posts category. This hides that from users.*/
function exclude_widget_categories($args){
$exclude = "59";
$args["exclude"] = $exclude;
return $args;
}
add_filter("widget_categories_args","exclude_widget_categories");
/* Add Google fonts */
function wpb_add_google_fonts() {
wp_enqueue_style( 'wpb-google-fonts', 'http://fonts.googleapis.com/css?family=Aguafina Script|Neucha|The Girl Next Door|Quintessential|Open Sans|Raleway', false );
}
add_action( 'wp_enqueue_scripts', 'wpb_add_google_fonts' );
/**
* Display the theme credit
*
* #since 1.0.0
* #return void
*/
function storefront_credit() {
?>
<div class="site-info">
<?php echo esc_html( apply_filters( 'storefront_copyright_text', $content = 'Copyright © ' . date( 'Y' ) . ' ' . get_bloginfo( 'name' ) ) ); ?>
<?php if ( apply_filters( 'storefront_credit_link', true ) ) { ?>
<br />
<?php echo '' . esc_html__( 'Designed by: Eric Hepperle Designs', 'storefront-ehw-1' ) . '' ?>
<?php } ?>
</div><!-- .site-info -->/*<?php
}
/* **** VARIOUS ATTEMPTS TO REMOVE P-TAGS FROM YOUTUBE VIDEO THUMBNAILS ****
// Remove P Tags Around Images
// From: http://justlearnwp.com/remove-p-tag-around-wordpress-images/
function filter_ptags_on_images($content){
return preg_replace('/<p>\s*(<a .*>)?\s*(<img .* \/>)\s*(<\/a>)?\s*<\/p>/iU', '\1\2\3', $content);
}
add_filter('the_content', 'filter_ptags_on_images');
// Remove P Tags Around videos
function filter_ptags_on_vids($content){
return preg_replace('/<video>\s*(<a .*>)?\s*(<img .* \/>)\s*(<\/a>)?\s*<\/video>/iU', '\1\2\3', $content);
}
add_filter('the_content', 'filter_ptags_on_vids');
// https://stackoverflow.com/questions/44539888/remove-automatic-p-tag-in-wordpress#answer-44540531
function reformat_auto_p_tags($content) {
$new_content = '';
$pattern_full = '{(\[raw\].*?\[/raw\])}is';
$pattern_contents = '{\[raw\](.*?)\[/raw\]}is';
$pieces = preg_split($pattern_full, $content, -1, PREG_SPLIT_DELIM_CAPTURE);
foreach ($pieces as $piece) {
if (preg_match($pattern_contents, $piece, $matches)) {
$new_content .= $matches[1];
} else {
$new_content .= wptexturize(wpautop($piece));
}
}
return $new_content;
}
remove_filter('the_content', 'wpautop');
remove_filter('the_content', 'wptexturize');
add_filter('the_content', 'reformat_auto_p_tags', 99);
add_filter('widget_text', 'reformat_auto_p_tags', 99);
// ------------ FROM STACK OVERFLOW ------------------------
//
// Remove p tags from images, scripts, and iframes.
function remove_some_ptags( $content ) {
$content = preg_replace('/<p>\s*(<a .*>)?\s*(<img .* \/>)\s*(<\/a>)?\s*<\/p>/iU', '\1\2\3', $content);
$content = preg_replace('/<p>\s*(<script.*>*.<\/script>)\s*<\/p>/iU', '\1', $content);
$content = preg_replace('/<p>\s*(<iframe.*>*.<\/iframe>)\s*<\/p>/iU', '\1', $content);
return $content;
}
add_filter( 'the_content', 'remove_some_ptags' );
*/
// Add the filter to manage the p tags
add_filter( 'the_content', 'jb_remove_autop_for_image', 0 );
function jb_remove_autop_for_image( $content )
{
global $post;
// Here you can write condition as per your requirement.
// i have added example for your idea
if ( is_single() && $post->post_type == 'image' )
remove_filter('the_content', 'wpautop');
return $content;
}
Please try below code.
// Add the filter to manage the p tags
add_filter( 'the_content', 'jb_remove_autop_for_image', 0 );
function jb_remove_autop_for_image( $content )
{
global $post;
// Here you can write condition as per your requirement.
// i have added example for your idea
if ( is_single() && $post->post_type == 'image' )
remove_filter('the_content', 'wpautop');
return $content;
}
You can wrap embedded iframes, images, videos etc. in your own wrapper. WP then wouldn't add <p> tags. Use 'oembed_dataparse' filter.
// Wrap iframe for embedded video in <div> with custom class.
// Add class-modifier if aspect ratio is 4/3.
function wrap_oembed_dataparse($return, $data, $url) {
$mod = '';
if ( ( $data->type == 'video' ) &&
( isset($data->width) ) && ( isset($data->height) ) &&
( round($data->height/$data->width, 2) == round( 3/4, 2) )
)
{
$mod = 'embed-responsive--4-3';
}
return '<div class="embed-responsive ' . $mod . '">' . $return . '</div>';
}
add_filter( 'oembed_dataparse', 'wrap_oembed_dataparse', 99, 4 );
This Vanilla-JS-function searches for all iframes, and moves them outside of their parents:
moveIframesOutOfPtags() {
let iframes = document.querySelectorAll( 'iframe' );
let before = "<div class="iframe-container">";
let after = "</div>";
Object.entries( iframes ).forEach( entry => {
let value = entry[1];
if( value.parentNode.nodeName === 'P' || value.parentNode.nodeName === 'p' ){
value.parentNode.outerHTML = before + value.parentNode.innerHTML + after;
}
});
}
Tested and works.
I'm using it in a Vue-app, so I've put it in the mounted section. If you're not using vue, then you would have to put the function inside a <script and run it inside some window.onload(() => { ... });
Depending on how you control the scripts on your page, then you should put it there, enqueued in your functions-file (good) or just straight up in the footer (bad).
Bonus info
I've also added a container-div (.iframe-container) to put the iframe into. By using this method then you can add these styles and then scale the iframe to fill 100% width, an keeping a set aspect ratio%.
Here I am sending the code for removing p tag From Images scripts and iframes.
// Remove p tags from images, scripts, and iframes.
function remove_some_ptags( $content ) {
$content = preg_replace('/<p>\s*(<a .*>)?\s*(<img .* \/>)\s*(<\/a>)?\s*<\/p>/iU', '\1\2\3', $content);
$content = preg_replace('/<p>\s*(<script.*>*.<\/script>)\s*<\/p>/iU', '\1', $content);
$content = preg_replace('/<p>\s*(<iframe.*>*.<\/iframe>)\s*<\/p>/iU', '\1', $content);
return $content;
}
add_filter( 'the_content', 'remove_some_ptags' );
Kindly check.

Wordpress | Apply function/filter to specific template (featured image function filter)

I have the following code in my tweaks plugin.
add_filter( 'the_content', 'sqhse_news_featimgmove', 20 );
function sqhse_news_featimgmove( $content ) {
$content = preg_replace( "/<\/p>/", "</p>" . get_the_post_thumbnail($post->ID,'post-single', array( 'class' => "img-fluid img-rounded w-100")) . "<div class='clearfix' style='margin-bottom:10px;'></div>", $content, 1 );
return $content;
}
What it does:
It adds the featured image after the first paragraph which is great and exactly what I need.
The problem: The code applies itself to single.php (great that's where I need it) but it also applies itself to single-training_courses.php (a template for a custom post type).
The help required: Apply the code to single.php and not any sub single templates such as single-training_courses.php
Is this achievable? and if so how may I achieve this?
You can use get_post_type() WordPress function and wrap your code inside an if statement as follow:
add_filter( 'the_content', 'sqhse_news_featimgmove', 20 );
function sqhse_news_featimgmove( $content ) {
if( get_post_type() == 'post' ) {
$content = preg_replace( "/<\/p>/", "</p>" . get_the_post_thumbnail($post->ID,'post-single', array( 'class' => "img-fluid img-rounded w-100")) . "<div class='clearfix' style='margin-bottom:10px;'></div>", $content, 1 );
return $content;
}
return $content;
}
The filter you're using, the_content, as you've discovered will apply to all content areas. You need to add a conditional to check the post type you're on and adjust accordingly. My suggestion would be to use is_singular().
add_filter( 'the_content', 'sqhse_news_featimgmove', 20 );
function sqhse_news_featimgmove( $content ) {
if ( is_singular( 'post' ) ) {
$content = preg_replace( "/<\/p>/", "</p>" . get_the_post_thumbnail($post->ID,'post-single', array( 'class' => "img-fluid img-rounded w-100")) . "<div class='clearfix' style='margin-bottom:10px;'></div>", $content, 1 );
}
return $content;
}
When dealing with filters make sure you always return a value. If you have a conditional for example keep the return statement outside of it.
https://codex.wordpress.org/Function_Reference/is_singular

Change Excerpt Length for Specific Page ID

I am working with a theme that uses the following function to set the post excerpt length on all pages:
//excerpt length
if ( !function_exists('custom_excerpt_length')):
function custom_excerpt_length( $length ) {
return 90;
}
add_filter( 'excerpt_length', 'custom_excerpt_length', 999 );
function new_excerpt_more( $more ) {
return '...';
}
add_filter('excerpt_more', 'new_excerpt_more');
endif;
I added new function:
add_filter( 'get_the_excerpt', 'so20668477_get_the_excerpt', 10, 1 );
function so20668477_get_the_excerpt( $excerpt )
{
if( is_page( 39370 ) )
$excerpt = apply_filters( 'the_content', get_the_content() );
return $excerpt;
}
But, it is not working, still showing post excerpt on page 39370. I am needing to display full length posts on Page ID = 39370 only. Not sure how to add the condition. Any help is much appreciated.
First you should be strongly encouraged to always use curly braces even in situations where they are technically optional.
Don't do:
if ( condition )
return false;
Instead do:
if ( condition ) {
return false;
}
About your question :
This function apply_filters( 'the_content', get_the_content() ); get the echo of the content not the content, so your condition is correct.
Try this code :
if( is_page( 39370 ) ){
$content = get_the_content();
$content = apply_filters('the_content', $content);
$excerpt = explode("[newpage]", $content);
}
return $excerpt;
Or there is another aproach :
if( is_page( 39370 ) ){
ob_start();
the_content();
$content = ob_get_clean();
}
return $excerpt;
I hope this solution will help you.

Excerpt "Read More..." Embedded In Text

On my Wordpress blog I use excerpts a lot. On my homepage I want a "read more..." on the same line as the text(without CSS), however I do not want it on my news page like that. I found this code which does exactly what I want but it applies it to all the excerpts. How do I have it just do this on the Homepage?
function new_excerpt_more( $more ) {
return ' <a class="read-more" href="'
. get_permalink( get_the_ID() )
. '">Read More...</a>';
}
add_filter( 'excerpt_more', 'new_excerpt_more' );
This should work:
function new_excerpt_more($more) {
if(is_home())
$more = ' <a class="read-more" href="'. get_permalink( get_the_ID() ) . '">Read More...</a>';
return $more;
}
add_filter( 'excerpt_more', 'new_excerpt_more' );
EDIT: In your theme, before the loop, you should add a variable (a flag) to see if it's the page that you want:
$my_flag = is_page( array( id, id, id, id, 'page-name', 'page-slug' );
if( have_posts() ) :
while( have_posts() ) :
// Your code
endwhile;
endif;
And in your function (new_excerpt_more), you must check it like this:
function new_excerpt_more($more) {
global $my_flag;
if(is_home() || $my_flag)
$more = ' <a class="read-more" href="'. get_permalink( get_the_ID() ) . '">Read More...</a>';
return $more;
}
add_filter( 'excerpt_more', 'new_excerpt_more' );
I haven't tested it, but it should work. However, isn't supposed that pages display single content? It would never display only the excerpt (of course, it will depend on your theme :P)
Documentation:
is_home()

Categories