Unique slugs that, if fits with slug-1, slug-2... slug-n - php

I am using only slug to identify a page on the website, like: example.tld/view/this-fancy-slug . This is generated from the title automatically with this function:
public static function Normalize($str)
{
$charset = "UTF-8";
$separator = "-";
$str = strtolower(htmlentities($str, ENT_COMPAT, $charset));
$str = preg_replace('/&(.)(acute|cedil|circ|lig|grave|ring|tilde|uml);/', "$1", $str);
$str = preg_replace('/([^a-z0-9]+)/', $separator, html_entity_decode($str, ENT_COMPAT, $charset));
$str = trim($str, $separator);
return $str;
}
This returns a perfect slug... but I need unique slugs. So I've to combine with mysql to check if exists a slug that fits with the created. No problem with that.
The problem is that I want to add a -1 at the final if there is ONE slug. But can be buggy if are added 3 equal slugs so... how can I manage this to go from slug, slug-1, slug-2, slug-3... slug-100, slug-n?
Thank you in advance!

Don't just check if that identical slug is present. Use a regular expression to count all the slugs that follow the pattern /(<base-regex-for-slug>)(-\d+)?/. Because you only allow alphanumerics your base regex above will be the slug itself.

Related

Using PHP preg_replace match result in a math operation?

I want to find a number in a string, add one to it, and replace it. These don't work:
$new_version =
preg_replace("/str\/(\d+)str/", "str/".("$1"+1)."str", $original);
$new_version =
preg_replace("/str\/(\d+)str/", "str/".(intval("$1")+1)."str", $original);
Where 'str' is a very identifiable string, each side of the number (and does not contain numbers).
I realise I can do this in more than one line of code quite easily but it seems like this should be possible.
Using a callback function allows you to cast a match to number and increment, e.g.:
preg_replace_callback(
"/str\/(\d+)str/",
function($matches) { return "str/" . ((int)$matches[1] + 1) . "str"; },
$original
);
Solely using str_replace you can get the number from the string, add one to it, and the replace the old number with the new one :
$str = 'In My Cart : 11 items';
$nb = preg_replace('/\D/', '', $str);
$nb += 1;
$str = str_replace($nb-1, $nb, $str);
echo $str;

Replacing multiple href values using a regular expression in PHP

I know this question has more of a WordPress background to it, but I'm hoping it's just my lack of PHP knowledge that is the problem here.
I have a regex that looks for <a> tags such as: Find Out More, which are generated from content inputted by the user. Once it finds this content a foreach loop runs over the matched text and uses a WordPress function $postId = url_to_postid( $url ); to convert the URL into a PostID.
This is an example output: Find Out More.
This works fine as long as there is one link in each piece of matched text. However if there are two or more links, it sets every link to have the same href which is incorrect.
I'm sure this is something to do with how I've got my loop running. The code I'm using is below:
<?php
$string = get_field('sample_text_box');
$pattern = "/(?<=href=(\"|'))[^\"']+(?=(\"|'))/";
preg_match_all($pattern, $string, $matches);
$urls = $matches[0];
foreach($urls as $key => $url) {
$postId[$key] = url_to_postid( $url );
}
$newstring = preg_replace($pattern , $postId[$key] , $string);
echo $newstring;
?>
The line get_field('sample_text_box'); is an Advanced Custom Field function which "returns the value of the specified field". You can read about it here if it helps: https://www.advancedcustomfields.com/resources/get_field/
Thanks!
The problem with your code is that you are indeed replacing the pattern with a single value of $postId[$key], where $key is the last value assigned in foreach.
You also can not pass $postId instead because preg_replace expects both pattern and replacement be of the same type - whether strings, or arrays.
However, the problem is easily solved with preg_replace_callback function:
$pattern = '/(?<=href\="|\')([^"\']+)(?="|\')/m';
$new_string = preg_replace_callback($pattern, function ($matches) {
return isset($matches[1]) ? url_to_postid($matches[1]) : $matches[0];
}, $string);

PHP match and replace whole word

Hi I am replacing certain names with different value . Here is values I am replacing "#size-name" and "#size" .But the problem is my code replacing only size first and note name for example
#size = "replaceword"
#size-name = "replaceword2"
But its replacing
#size ="replaceword"
#size-name = "replaceword2-name"
How can I replace whole word not part of it here is my code
$tempOutQuery = preg_replace("/(\b($key)\b)/i" , $value , $tempOutQuery);
$tempOutQuery= str_replace("#".$key ,$value ,$tempOutQuery);
both codes are not working
My Full Code
$val= "Hi I want #size dress which is #size-name";
$tempOutQuery = preg_replace("/(\b(size)\b)/i" ,"replaceword", $tempOutQuery);
$tempOutQuery = preg_replace("/(\b(size-name)\b)/i" ,"replaceword2", $tempOutQuery);
If you could make replace without using regulat expressions, then I would suggest using standart str_replace() with arrays:
$val= "Hi i want #size dress which is #size-name";
$search = array('size-name', 'size');
$replace = array('replaceword2', 'replaceword');
$result = str_replace($search, $replace, $val);
The order of search and replace Strings is important!
You should take care that you replace long search-strings first, and the short strings later.
Here's another option for you, using preg_replace_callback. It's actually very similar to Gennadiy's method. The only real difference is that it's using the preg aspect of PHP (and it's a lot more work). But it's another way to skin the proverbial cat.
<?php
// SET OUR DEFAULT STRING
$string = 'Hi I want #size suit which is #size-name';
// LOOK FOR EITHER size-name OR size AND IF YOU FIND IT ...
// RUN THE FUNCTION 'replace_sizes'
$string = preg_replace_callback('~#(size-name|size)~', 'replace_sizes', $string);
// PRINT OUT OUR MODIFIED STRING
print $string;
// THIS IS THE FUNCTION THAT WILL BE RUN EVERY TIME A MATCH IS FOUND
// EITHER 'size' OR 'size-name' WILL BE STORED IN $m[1]
function replace_sizes($m) {
// SET UP AN ARRAY THAT HAS OUR POTENTIAL MATCHES AS KEYS
// AND THE TEXT WE WANT TO REPLACE WITH AS THE VALUE
$size_text_array = array('size-name' => 'replaceword2', 'size' => 'replaceword');
// RETURN WHATEVER THE VALUE IS BASED ON THE KEY
return $size_text_array[$m[1]];
}
This will print out:
Hi I want replaceword suit which is replaceword2
Here is a working demo:
http://ideone.com/njNTbB
You can try pre_replace() to replace whole word from an item of an array in PHP a shown below.
<?PHP
function removePrepositions($text){
$propositions=array('/\bfor\b/i','/\band\b/i');
if( count($propositions) > 0 ) {
foreach($propositions as $exceptionPhrase) {
$text = preg_replace($exceptionPhrase, '', trim($text));
}
$retval = trim($text);
}
return $retval;
}
?>
See the entire post here

How to make a Slug from the Title

I' am creating a slug on the fly. When I review the database my slug row looks like this
laal-salaam---2002
What actually I don't want is duplicate hyphen between the words.
$crawl_slug = preg_replace('/[^A-Za-z0-9-]+/', '-', $crawl_name);
$crawl_slug = strtolower($crawl_slug);
Thats the PHP code that handles in making the slug from the name on the fly.
The end result should be
laal-salaam-2002
Is there any other way I can achieve this issue. Thanks!
This is a Simple Function I use for years.
<?php
function to_slug($string)
{
$string = trim($string);
$string1 = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $string)));
return preg_replace("/\-+/i", "-", $string1);
}
$slug = to_slug("laal-salaam---2002");
echo $slug
?>

URL Friendly Username in PHP?

On my PHP site, currently users login with an email address and a password. I would like to add a username as well, this username they g\set will be unique and they cannot change it. I am wondering how I can make this name have no spaces in it and work in a URL so I can use there username to link to there profiles and other stuff. If there is a space in there username then it should add an underscore jason_davis. I am not sure the best way to do this?
function Slug($string)
{
// convert to entities
$string = htmlentities( $string, ENT_QUOTES, 'UTF-8' );
// regex to convert accented chars into their closest a-z ASCII equivelent
$string = preg_replace( '~&([a-z]{1,2})(?:acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i', '$1', $string );
// convert back from entities
$string = html_entity_decode( $string, ENT_QUOTES, 'UTF-8' );
// any straggling caracters that are not strict alphanumeric are replaced with a dash
$string = preg_replace( '~[^0-9a-z]+~i', '-', $string );
// trim / cleanup / all lowercase
$string = trim( $string, '-' );
$string = strtolower( $string );
return $string;
}
$user = 'Alix Axel';
echo Slug($user); // alix-axel
$user = 'Álix Ãxel';
echo Slug($user); // alix-axel
$user = 'Álix----_Ãxel!?!?';
echo Slug($user); // alix-axel
In other words... you need to create a username slug. Doctrine (ORM for PHP) has a nice function to do it. Doctrine_Inflector::urlize()
EDIT: You should also keep username slug in database, as a Unique Key column. Then every search operation should be done based on that column, not original username.

Categories