Limit WP excerpt to second sentence - php

I'm using this function to limit my WP excerpt to a sentence instead of just cutting it off after a number of words.
add_filter('get_the_excerpt', 'end_with_sentence');
function end_with_sentence($excerpt) {
$allowed_end = array('.', '!', '?', '...');
$exc = explode( ' ', $excerpt );
$found = false;
$last = '';
while ( ! $found && ! empty($exc) ) {
$last = array_pop($exc);
$end = strrev( $last );
$found = in_array( $end{0}, $allowed_end );
}
return (! empty($exc)) ? $excerpt : rtrim(implode(' ', $exc) . ' ' .$last);
}
Works like a charm, but I would like to limit this to two sentences. Anyone have an idea how to do this?

Your code didn't work for me for 1 sentence, but hey it's 2am here maybe I missed something. I wrote this from scratch:
add_filter('get_the_excerpt', 'end_with_sentence');
function end_with_sentence( $excerpt ) {
$allowed_ends = array('.', '!', '?', '...');
$number_sentences = 2;
$excerpt_chunk = $excerpt;
for($i = 0; $i < $number_sentences; $i++){
$lowest_sentence_end[$i] = 100000000000000000;
foreach( $allowed_ends as $allowed_end)
{
$sentence_end = strpos( $excerpt_chunk, $allowed_end);
if($sentence_end !== false && $sentence_end < $lowest_sentence_end[$i]){
$lowest_sentence_end[$i] = $sentence_end + strlen( $allowed_end );
}
$sentence_end = false;
}
$sentences[$i] = substr( $excerpt_chunk, 0, $lowest_sentence_end[$i]);
$excerpt_chunk = substr( $excerpt_chunk, $lowest_sentence_end[$i]);
}
return implode('', $sentences);
}

I see complexities in your sample code that make it (maybe) harder than it needs to be.
Regular expressions are awesome. If you want to modify this one, I'd recommend using this tool: https://regex101.com/
Here we're going to use preg_split()
function end_with_sentence( $excerpt, $number = 2 ) {
$sentences = preg_split( "/(\.|\!|\?|\...)/", $excerpt, NULL, PREG_SPLIT_DELIM_CAPTURE);
var_dump($sentences);
if (count($sentences) < $number) {
return $excerpt;
}
return implode('', array_slice($sentences, 0, ($number * 2)));
}
Usage
$excerpt = 'Sentence. Sentence! Sentence? Sentence';
echo end_with_sentence($excerpt); // "Sentence. Sentence!"
echo end_with_sentence($excerpt, 1); // "Sentence."
echo end_with_sentence($excerpt, 3); // "Sentence. Sentence! Sentence?"
echo end_with_sentence($excerpt, 4); // "Sentence. Sentence! Sentence? Sentence"
echo end_with_sentence($excerpt, 10); // "Sentence. Sentence! Sentence? Sentence"

Related

how to convert string to array character

The first line of code is converted to the second code. I can use the padding methods, but I want to get the solution from the shortest path and convert it quickly. I will use the code field in the sql select section
$it = "(a(am,bam),b(dam,cam))";
$to = "a.am, a.bam, b.dam, b.cam";
Try following code:
$it = "(a(am,bam),b(dam,cam))";
function iDelimiter( $str ) {
$count = 0;
$str = str_split( $str );
foreach( $str as &$value ) {
if( $value == "(" ) {
$count++;
} elseif( $value == ")" ) {
$count--;
}
if( $value == "," && ! $count ) {
$value = "|";
}
}
return explode( "|", implode( $str ) );
}
function iParser( $str, $_prefix = "" ) {
preg_match( "/^((?!(\(|\))).)*\((.*)\)$/", $str, $m );
if( count( $m ) < 4 ) {
return ( strlen( $_prefix ) ? $_prefix . "." : '' ) . $str;
}
$prefix = ( strlen( $_prefix ) ? $_prefix . "." : '' ) . $m[1];
$str = $m[3];
if( strpos( $str, "(" ) === false ) {
$return = explode( ",", $str );
$pad = preg_filter( '/^/', strlen( $prefix ) ? $prefix . '.' : '', $return );
return implode( $pad, "," );
} else {
$str = iDelimiter( $str );
$return = array_map( 'iParser', $str, array_pad( array(), count( $str ), $prefix ) );
return implode( $return, ", " );
}
}
print_r( iParser( $it ) );
It parse every depth of parentheses. Just pass your string to iParser function.
Try this:
<?php
function str2Arr( $s, $r, $str) {
$str = trim( str_replace( $s, $r, $str ));
return explode(" ", $str);
}
$it = "(a(am,bam),b(dam,cam))";
//$to = "a.am, a.bam, b.dam, b.cam";
$search = ['),', '(', ')', ',', 'a a', 'b d', 'ba', 'c'];
$replace =[' ', ' ', ' ', ' ', 'a.a','b.d', 'a.ba', 'b.c'];
var_dump( implode(", ",( str2Arr( $search, $replace, $it) ) ) );
See demo
Without using a regex one may achieve the specified conversion by using str_replace() which uses an array of characters to be replaced by another array of characters when found in the subject string. The non-alphabetical characters are each replaced with blank space and the substrings are replaced so that each starts with an "a" or "b" as appropriate followed by a period and the rest of the substring.
Kill me now. There's got to be a better way, but my eyes are bleeding.
It probably would have worked much better had I started with a regex, but my regex skills are rusty.
I kept pounding your data with a hammer until the square peg went through the round hole.
<?php
$it = "(a(am,bam),b(dam,cam))";
$it = substr($it, 1, -1);
//$to = "a.am, a.bam, b.dam, b.cam";
$final = [];
$test = explode("),", $it);
foreach($test as $section) {
$letter = substr($section, 0, 1);
$remainder = substr($section, 2);
if(strpos($remainder, ")")) {
$remainder = substr($remainder, 0, strpos($remainder, ")"));
}
echo $letter . " ".$remainder."\n";
foreach(explode(",", $remainder) as $fragment) {
array_push($final, $letter.".".$fragment);
}
}
var_dump($final);
var_dump(implode($final, ", "));
Yields
a am,bam
b dam,cam
array(4) {
[0]=>
string(4) "a.am"
[1]=>
string(5) "a.bam"
[2]=>
string(5) "b.dam"
[3]=>
string(5) "b.cam"
}
string(22) "a.am, a.bam, b.dam, b.cam"

PHP: How can I cut the word and add "..."

How can I cut the words and add "..." after reaching 4 or 5 words?
The code below states I did the character-based word cuttingb but I need it now to be by word.
Currently I have this kind of code:
if(strlen($post->post_title) > 35 )
{
$titlep = substr($post->post_title, 0, 35).'...';
}
else
{
$titlep = $post->post_title;
}
and this is the output of title:
if ( $params['show_title'] === 'true' ) {
$title = '<h3 class="wp-posts-carousel-title">';
$title.= '' . $titlep . '';
$title.= '</h3>';
}
Typically, I'll explode the body and pull out the first x characters.
$split = explode(' ', $string);
$new = array_slice ( $split, 0 ,5);
$newstring = implode( ' ', $new) . '...';
Just know, this method is slow.
Variant #1
function crop_str_word($text, $max_words = 50, $sep = ' ')
{
$words = split($sep, $text);
if ( count($words) > $max_words )
{
$text = join($sep, array_slice($words, 0, $max_words));
$text .=' ...';
}
return $text;
}
Variant #2
function crop_str_word($text, $max_words, $append = ' …')
{
$max_words = $max_words+1;
$words = explode(' ', $text, $max_words);
array_pop($words);
$text = implode(' ', $words) . $append;
return $text;
}
Variant #3
function crop_str_word($text, $max_words)
{
$words = explode(' ',$text);
if(count($words) > $max_words && $max_words > 0)
{
$text = implode(' ',array_slice($words, 0, $max_words)).'...';
}
return $text;
}
via
You should use str_replace function of PHP.
str_replace('your word', '...', $variable);
read that article: http://php.net/manual/en/function.str-replace.php
In WordPress this functionality is done by wp_trim_words() function.
<?php
if(strlen($post->post_title) > 35 )
{
$titlep = wp_trim_words( $post->post_title, 35, '...' );
}
else
{
$titlep = $post->post_title;
}
?>
If you do this functionality using PHP then write code as below:
<?php
$titlep = strlen($post->post_title) > 35 ? substr($post->post_title, 0, 35).'...' : $post->post_title;
?>

read more script cuts at html tags

I have a php code that chops the string and places a read more button. This all worked well until I saw it chops trough some html tags in the text. Witch ruins the functionality. This is my code:
$self = $_SERVER['PHP_SELF'];
function chopstring( $string, $id, $maxlength = 480, $append = '...' ){
$strlen = strlen( $string );
if( $strlen <= (int) $maxlength ){
return $string;
}
else{
$chopped = substr( $string, 0, (int) $maxlength );
$chopped_on_space = substr( $chopped, 0, strrpos( $chopped, ' ' ) );
return ( $chopped_on_space ) . $append . " <a class='btn-orange right' href='".$self."?id=".$id."'>Lees verder</a>";
}
}
how can i make sure this doesn't chop trough br img and url tags anymore
this helped:
function chopstring( $string, $id, $maxlength = 480 ){
$strlen = strlen( $string );
if( $strlen <= (int) $maxlength ){
return $string;
}
else{
$chopped = substr( $string, 0, (int) $maxlength );
$chopped_on_space = substr( $chopped, 0, strrpos( $chopped, ' ' ) );
$output = new tidy;
$output->parseString($chopped_on_space, array('show-body-only'=>true, 'indent'=>true), 'UTF8');
$output->repairString();
$output = preg_replace('#(( ){0,}<br( {0,})(/{0,1})>){1,}$#i', '', $output);
return ( $output ) . "... <a class='btn-orange right' href='".$self."?id=".$id."'>Lees verder</a>";
}
}
the $output grabs the $chopped_on_space and gets a repair and the preg_replace makes sure there will be no <br> at the end of the string.

Automatically split WordPress post content in to 3 columns?

I'm currently using the following code from this tutorial to automatically split the WordPress post content in to 2 columns. However, how would I change this code to output 3 columns instead of only 2?
functions.php code:
function content_split($text, $separator = '<hr/>', $start = false ) {
if ( $start === false) {
$start = strlen($text) / 2;
}
$lastSpace = false;
$split = substr($text, 0, $start - 1);
// if the text is split at a good breaking point already.
if (in_array(substr($text, $start - 1, 1), array(' ', '.', '!', '?'))) {
$split .= substr($text, $start, 1);
// Calculate when we should start the split
$trueStart = strlen($split);
// find a good point to break the text.
} else {
$split = substr($split, 0, $start - strlen($separator));
$lastSpace = strrpos($split, ' ');
if ($lastSpace !== false) {
$split = substr($split, 0, $lastSpace);
}
if (in_array(substr($split, -1, 1), array(','))) {
$split = substr($split, 0, -1);
}
// Calculate when we should start the split
$trueStart = strlen($split);
}
//now we know when to split the text
return substr_replace($text, $separator, $trueStart, 0);
}
index.php code:
<div class="first-column my-column">
<?php $text = get_the_content(); $separator = '</div><div class="second-column my-column">'; echo apply_filters('the_content', content_split($text,$separator)); ?>
</div>
function content_split($text, $separator = '<hr/>') {
$string = '';
$start = ceil(strlen($text) / 3);
$string.= substr($text,0,$start);
$string.= $separator;
$string.= substr($text,$start,$start);
$string.= $separator;
$string.= substr($text,($start*2),$start);
return $string;
}

Does PHP have a feature like Python's template strings?

Python has a feature called template strings.
>>> from string import Template
>>> s = Template('$who likes $what')
>>> s.substitute(who='tim', what='kung pao')
'tim likes kung pao'
I know that PHP allows you to write:
"Hello $person"
and have $person substituted, but the templates can be reused in various sections of the code?
You can use template strings like this:
$name = "Maria";
$info["last_name"] = "Warner";
echo "Hello {$name} {$info["last_name"]}";
This will echo Hello Maria Warner.
You could also use strtr:
$template = '$who likes $what';
$vars = array(
'$who' => 'tim',
'$what' => 'kung pao',
);
echo strtr($template, $vars);
Outputs:
tim likes kung pao
I think there are a bunch of ways to do this... but this comes to mind.
$search = array('%who%', '%what_id%');
$replace = array('tim', 'kung pao');
$conference_target = str_replace(
$search,
$replace,
"%who% likes %what%"
);
Ha, we even had one in our framework using vsprintf:
class Helper_StringFormat {
public static function sprintf($format, array $args = array()) {
$arg_nums = array_slice(array_flip(array_keys(array(0 => 0) + $args)), 1);
for ($pos = 0; preg_match('/(?<=%)\(([a-zA-Z_]\w*)\)/', $format, $match, PREG_OFFSET_CAPTURE, $pos);) {
$arg_pos = $match[0][2];
$arg_len = strlen($match[0][0]);
$arg_key = $match[1][0];
if (! array_key_exists($arg_key, $arg_nums)) {
user_error("sprintfn(): Missing argument '${arg_key}'", E_USER_WARNING);
return false;
}
$format = substr_replace($format, $replace = $arg_nums[$arg_key] . '$', $arg_pos, $arg_len);
$pos = $arg_pos + strlen($replace);
}
return vsprintf($format, array_values($args));
}
}
Which looks like it came from the sprintf page
This allows for calls like:
sprintfn('second: %(second)s ; first: %(first)s', array(
'first' => '1st',
'second'=> '2nd'
));
UPDATE
Here is an update to do what you want... not fully tested though
class Helper_StringFormat {
public static function sprintf($format, array $args = array()) {
$arg_nums = array_slice(array_flip(array_keys(array(0 => 0) + $args)), 1);
for ($pos = 0; preg_match('/(?<=%)\(([a-zA-Z_][\w\s]*)\)/', $format, $match, PREG_OFFSET_CAPTURE, $pos);) {
$arg_pos = $match[0][1];
$arg_len = strlen($match[0][0]);
$arg_key = $match[1][0];
if (! array_key_exists($arg_key, $arg_nums)) {
user_error("sprintfn(): Missing argument '${arg_key}'", E_USER_WARNING);
return false;
}
$format = substr_replace($format, $replace = $arg_nums[$arg_key] . '$', $arg_pos, $arg_len);
$pos = $arg_pos + strlen($replace); // skip to end of replacement for next iteration
}
return vsprintf($format, array_values($args));
}
}
$str = "%(my var)s now work with a slight %(my var2)s";
$repl = array("my var" => "Spaces", "my var2" => "modification.");
echo Helper_StringFormat::sprintf($str, $repl);
OUTPUT
Spaces now work with a slight modification.
Another more simple approach would be this:
$s = function ($vars) {
extract($vars);
return "$who likes $what";
};
echo $s(['who' => 'Tim', 'what' => 'King Pao']); // Tim likes King Pao
And yes, PHPStorm will complain...
I personally most like sprintf (or vsprintf, for an array of arguments). It places them in the intended order, coerces types as needed, and has a lot more advanced features available.
Example:
$var = sprintf("%s costs %.2f dollars", "Cookies", 1.1);
This will result in the value Cookies cost 1.10 dollars.
There's an entire family of printf functions for different use cases, all listed under "See Also".
Very versatile: same methods for providing variables, array components, function results, etc.
I made a function to do what you want. i made it "quck-and-dirty" because i have not much time to refactorize it, maybe i upload it to my github.
EDIT: a bug correction...
Use it like
formattemplatter(
'$who likes $what'
, array(
'who' => 'Tim'
, 'what' => 'Kung Pao'
)
);
Variables can be [a-zA-Z0-9_] only.
function formattemplater($string, $params) {
// Determine largest string
$largest = 0;
foreach(array_keys($params) as $k) {
if(($l=strlen($k)) > $largest) $largest=$l;
}
$buff = '';
$cp = false; // Conditional parenthesis
$ip = false; // Inside parameter
$isp = false; // Is set parameter
$bl = 1; // buffer length
$param = ''; // current parameter
$out = ''; // output string
$string .= '!';
for($sc=0,$c=$oc='';isset($string{$sc});++$sc,++$bl) {
$c = $string{$sc};
if($ip) {
$a = ord($c);
if(!($a == 95 || ( // underscore
($a >= 48 && $a <= 57) // 0-9
|| ($a >= 65 && $a <= 90) // A-Z
|| ($a >= 97 && $a <= 122) // a-z
)
)) {
$isp = isset($params[$buff]);
if(!$cp && !$isp) {
trigger_error(
sprintf(
__FUNCTION__.': the parameter "%s" is not defined'
, $buff
)
, E_USER_ERROR
);
} elseif(!$cp || $isp) {
$out .= $params[$buff];
}
$isp = $isp && !empty($params[$buff]);
$oc = $buff = '';
$bl = 0;
$ip = false;
}
}
if($cp && $c === ')') {
$out .= $buff;
$cp = $isp = false;
$c = $buff = '';
$bl = 0;
}
if(($cp && $isp) || $ip)
$buff .= $c;
if($c === '$' && $oc !== '\\') {
if($oc === '(') $cp = true;
else $out .= $oc;
$ip = true;
$buff = $c = $oc = '';
$bl = 0;
}
if(!$cp && $bl > $largest) {
$buff = substr($buff, - $largest);
$bl = $largest;
}
if(!$ip && ( !$cp || ($cp && $isp))) {
$out .= $oc;
if(!$cp) $oc = $c;
}
}
return $out;
}
Just for the sake of completeness: there is also Heredoc.
$template = fn( $who, $what ) => <<<EOT
$who likes $what
EOT;
echo( $template( 'tim', 'kung pao' ) );
Outputs:
tim likes kung pao
Sidenotes:
You get highlighting in your favourite language (if properly configured). Just substitute EOT (from the sample above) with whatever you like (e.c. HTML, SQL, PHP, ...).
Escape arrays with curly braces {$data['who']}. Accessing objekts like $data->who works without braces.
Arrow functions like fn($a)=>$a are available since PHP 7.4. You can write function($a){return $a;} if you are using PHP<7.4.

Categories