1

I want to create a php variable which will use the the_title function:

So if the title of the post is "Style" the variable will name will be $style and if the post title is "Dog" the variable name will be $Dog.

Is it possible?

I tried ${the_title()};

But it echoes the title.

My goal is to use at as a dynamic variable inside a each loop and increase it's number every time it gets the same title. 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...

3
  • 2
    "are you sure you want to do this?" wouldn't it be better to expand the title into an array to use that eg. $titlewords = explode(" ", get_the_title());
    – majick
    Jun 25, 2017 at 10:03
  • What are you trying to achieve? Aren't you afraid that your new variable will overwrite some other crucial variables like for instance post or what will happen if the title will include characters like space or an quote?
    – Picard
    Jun 25, 2017 at 11:12
  • I can add a prefix like "wefij_the_title" and i can handle the spaces.
    – Nori
    Jun 25, 2017 at 13:44

2 Answers 2

0

Indeed, the the_title function echoes the title, unless you set the third parameter to false (default true). So you start with this;

$title = the_title ('','',false);

Now, $title may contain all kinds of characters that cannot be used in PHP variable names, so we need some sanitization:

$title = preg_replace('/[^A-Za-z0-9\_]/', '', $title); // Removes special chars except underscore.

Then you use PHP variable variables to turn the content of $title into a variable name:

$$title = 'something';

So, if the_title gives the value "hello world", the $title variable after sanitizing has the value "helloworld" and $helloworld has the value "something".

3
  • why is it that if i just set $title = the_title('','',false); and the echo $$title; it echoes the the title? isn't it suppose to be empty until is set it to something? my goal is to set it to increasing number with each loop, so i don't need to set it to '0' which will reset it... and still be different for every post... I have updated the question to explain it.
    – Nori
    Jun 25, 2017 at 14:02
  • You would need to echo ${$title}
    – cjbj
    Jun 25, 2017 at 14:22
  • For your purpose this approach is quite complicated. You could just store every title in an array and then use array_keys to see how often it has been used before. Check this: stackoverflow.com/questions/26235186/…
    – cjbj
    Jun 25, 2017 at 14:26
0

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 &amp Colors ', 'My Style&#039s 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 &amp Colors
My Style's Colors  = My Style&#039s 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.