so for example for each post with unique title it will be set to '1' but if a title repeats a second time it will be set to '2' and so on...
Use array_count_values()
after casting titles in an array. Use the_title_attribute()
with a false
argument to get an esc_attr()
& tag-stripped title. Be mindful of regex used with preg_replace
or you can end up with false matches. After setting array_count_values()
, a foreach loop using as $key => $value
can use complex syntax to create variable names based on $key
(aka post_title
): ${'_'. $key} = $value
.
Once you have all post objects, loop through them.
Getting title
You can use the_title_attribute()
, since it runs title through esc_attr();
$title_cleaned = the_title_attribute( array( 'echo' => false, );
//OR: $post->post_title for raw from object
Side Note: Alternatively, from the object you can get the raw title from $post->post_title
foreach ($posts as $post) {
$title_cleaned = esc_attr( $post->post_title )
}
Trim, sanitize, preg_replace
remove any leading or ending extra spaces and force type to string
$title_cleaned = (string) trim( $post );
remove any non-alphanumeric space, leaving spaces
$title_cleaned = preg_replace( '/[^a-zA-Z0-9 ]*/', '', $title_cleaned );
change spaces to underscores
$title_cleaned = preg_replace( '/\s+/', '_', $title_cleaned );
cast value to array
$array_of_titles[] = $title_cleaned;
// loop end
Get count
Use array_count_values()
to cast key => values
of post_title => count
$counted_array = array_count_values( $array_of_titles );
The value of $counted_array
will be something like:
Array (
[ Style ] => 3
[ Dog ] => 1
)
Setting ${'_'. $key} = $value
Set keys to variable names, adding an underscore to avoid numbers starting variable name
foreach( $counted_array as $key => $value ) {
${'_'. $key} = (int) $value;
}
Example of all the above together:
foreach ($posts as $post ) {
$title_cleaned = the_title_attribute( array( 'echo' => false, );
$title_cleaned = (string) trim( $title_cleaned );
$title_cleaned = preg_replace( '/[^a-zA-Z0-9 ]*/', '', $title_cleaned );
$title_cleaned = preg_replace( '/\s+/', '_', $title_cleaned );
$array_of_titles[] = $title_cleaned;
}
$counted_array = array_count_values( $array_of_titles );
foreach( $counted_array as $key => $value ) {
${'_'. $key} = (int) $value;
}
Example mockup
This php file can be used outside WP to see what I mean regarding the title to regex stuff.
<?php
//using array below as a mock response of titles after passing through esc_attr
$faux_the_title_attribute = array( ' My Styles & Colors ', 'My Style's Colors', 'My Styles: Colors', 'My Styles: Colors', 'My Styles: Colors' );
foreach ($faux_the_title_attribute as $pt ) {
//$title_cleaned = the_title_attribute( array( 'echo' => false, );
$title_cleaned = (string) trim( $pt );
$title_cleaned = preg_replace( '/[^a-zA-Z0-9 ]*/', '', $title_cleaned );
$title_cleaned = preg_replace( '/\s+/', '_', $title_cleaned );
//My Styles & Colors = My_Styles_amp_Colors
$array_of_titles[] = $title_cleaned;
}
$counted_array = array_count_values( $array_of_titles );
foreach( $counted_array as $key => $value ) {
// ${'_'. $key} = $key . '_' . $value;
//becomes $_My_Styles_amp_Colors = _My_Styles_amp_Colors_3;
${'_'. $key} = (int) $value;
//becomes $_My_Styles_Colors = 3;
}
printf( $_My_Styles_amp_Colors );
?>
A note on regex, post title strings to ${$title}
, and potential issues
You would need to prepend these in the event of a post_title
beginning with a numerical, since php variables must begin with a letter or underscore.
Depending on how you are getting the titles, get_title()
as called by the_title()
, or the object from get_post
may not have filters applied.
While a regex like [^a-zA-Z0-9]*
will remove all non alphanumeric, without esc_attr()
to htmlencode
them first (i.e. with a get_post()
using default raw
filter), the returned strings "My Styles & Colors", "My Style's Colors", or "My Styles: Colors" would all be MyStylesColors
after the preg_replace
.
However after esc_attr()
:
My Styles & Colors = My Styles & Colors
My Style's Colors = My Style's Colors
My Styles: Colors = My Styles: Colors
After esc_attr()
and regex preg_replace
:
My Styles & Colors = MyStylesampColors
My Style's Colors = MyStyle039sColors
My Styles: Colors = MyStylesColors
However, removing the whitespace in the expression (by not including it, i.e. [^a-zA-Z0-9 ]*
), causes the following possible issues:
My Styles & le Colors = MyStylesampleColors
My Style sample Colors = MyStylesampleColors
Adding whitespace to approved regex, and using second preg_replace('/\s+/', '_', $string);
to swap whitespace to underscores:
$title_cleaned = (string) the_title_attribute( array( 'echo' => false );
$title_cleaned = preg_replace( '/[^a-zA-Z0-9]/', '', $title_cleaned );
$title_cleaned = preg_replace( '/\s+/', '_', $title_cleaned );
//My Styles & Colors = My_Styles_amp_Colors
But that will convert opening or closing whitespaces to underscores, so php's trim()
can handle those before any preg_replace
.
None of this enforces the start of the variable name be a letter or underscore (numbers being invalid to start php variables).
So a post title:
3 Best Styles = 3BestStyles = $3BestStyles
You could validate against ^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$
, or prefix everything with an underscore.
So continuing from above $title_cleaned
example:
$title_cleaned = the_title_attribute( array( 'echo' => false, );
$title_cleaned = (string) trim( $title_cleaned );
$title_cleaned = preg_replace( '/[^a-zA-Z0-9 ]*/', '', $title_cleaned );
$title_cleaned = preg_replace( '/\s+/', '_', $title_cleaned );
$array_of_titles[] = $title_cleaned;
There could be other issues not taken into consideration here, too.
Personally, if just needing to know those counts and be able to compare, order, etc., I would stop at the step with $counted_array = array_count_values( $array_of_titles );
and forgo the dynamic variable bit. IMO, of course.
$titlewords = explode(" ", get_the_title());
post
or what will happen if the title will include characters like space or an quote?