Welcome Guest, Not a member yet? Register   Sign In
Create unique slugs for post titles etc.
#1

[eluser]Johan André[/eluser]
Code:
public function create_unique_slug($string, $table)
{
    $slug = url_title($string);
    $slug = strtolower($slug);
    $i = 0;
    $params = array ();
    $params['slug'] = $slug;
    if ($this->input->post('id')) {
        $params['id !='] = $this->input->post('id');
    }
    
    while ($this->db->where($params)->get($table)->num_rows()) {
        if (!preg_match ('/-{1}[0-9]+$/', $slug )) {
            $slug .= '-' . ++$i;
        } else {
            $slug = preg_replace ('/[0-9]+$/', ++$i, $slug );
        }
        $params ['slug'] = $slug;
        }
    return $slug;
}

I use this in my models to create unique slugs. It takes the the following arguments: $string - the string to convert, $table - the table to check for dupes.

The function checks if the post array contains an id (when updating posts). If it does the function excludes the actual post in the check (since it is allowed to be named the same).

Hope someone finds this useful. I basically converted the CakePHP-alike to CI. It's PHP5 only since it uses method chaining in the while-loop....
#2

[eluser]Unknown[/eluser]
Worked like a charm, thank you Smile Bra gjort!
#3

[eluser]Dam1an[/eluser]
Damn, how did I miss this? I'm currently in the process of auto generating several millions of unique slugs. My scenario is a little more specific then this, but thought I'd share what I have here anyway, in the hope it's of use to someone as well
(Explaination after the code)

Code:
<?php
// Code to populate the cities table here (too boring and irrelevant to show)

// And now we can take care of creating unique slugs
$table = 'cities';

// First of all, go through all the cities, and make a default slug
$query = $this->db->get($table);
$results = $query->result();

foreach($results as $result) {
    $slug = strtolower($result->name);
    $slug = url_title($slug);
    
    $data = array('slug'=>$slug);
    $this->db->where('id', $result->id);
    $this->db->update($table, $data);
}

// Now everything has a slug, find any duplicates
$query = $this->db->query("SELECT `slug`, COUNT(`slug`) AS count FROM `$table` GROUP BY `slug` HAVING count > 1 ORDER BY count");
$results = $query->result();

// For each duplicate, get all rows matching that slug
// We will then append the country name to the end
foreach ($results as $result) {
    $this->db->select("$table.*, countries.name as country_name");
    $this->db->where("$table.slug", $result->slug);
    $this->db->join('countries', "$table.country_code = countries.country_code");
    $query = $this->db->get($table);
    $dupes = $query->result();
    
    foreach($dupes as $dupe) {
        $data = array('slug'=>$dupe->slug.'-'.url_title(strtolower($dupe->country_name)));
        $this->db->where('id',$dupe->id);
        $this->db->update($table, $data);
    }
}

// Now everything has a slug, find any duplicates
$query = $this->db->query("SELECT `slug`, COUNT(`slug`) AS count FROM `$table` GROUP BY `slug` HAVING count > 1 ORDER BY count");
$results = $query->result();

// For each duplicate, get all rows matching that slug
// We will then append the country name to the end
foreach ($results as $result) {
    $this->db->select("$table.*, countries.name as country_name");
    $this->db->where("$table.slug", $result->slug);
    $this->db->join('countries', "$table.country_code = countries.country_code");
    $query = $this->db->get($table);
    $dupes = $query->result();
    
    foreach($dupes as $dupe) {
        $data = array('slug'=>$dupe->slug.'-'.url_title(strtolower($dupe->country_name)));
        $this->db->where('id',$dupe->id);
        $this->db->update($table, $data);
    }
}

// Just for good measure, make sure we have elimitaed all duplicates
$query = $this->db->query("SELECT `slug`, COUNT(`slug`) AS count FROM `$table` GROUP BY `slug` HAVING count > 1 ORDER BY count");
$results = $query->result();

echo '<pre>', print_r($results), '</pre>';

Whats going on
This version is for creating slugs for 20,000 cities

1) For every row in the table, create a base slug, which is a lower case url_title of the city name
2) Once this is done, find any duplicates
3) For each duplicate, append the lower case url_title of the country that city is in
4) Once again, check for any duplicates (apparently it's possible to have the same city more then once in a country)
5) For each duplicate, append -number in descending order, so the largest city has no suffix, and the smallest city has the largest number for it's suffix (size is determined by number of hotels in this case)
6) Relax in the satisfaction you now have unique slugs
#4

[eluser]Johan André[/eluser]
[quote author="thall" date="1250474077"]Worked like a charm, thank you Smile Bra gjort![/quote]

Tackar! Smile
#5

[eluser]omar-303[/eluser]
The CMS System i am building supports any language other than English so i had to translate the title first so i am able to add it in the url

in generate_slug()
Code:
//Translating the phrase to english
        $translated_phrase = $this->google_translate->translate($phrase, '', 'en');
        if ($translated_phrase !== false)
            $phrase=$translated_phrase;

the google_translate library
Code:
&lt;?php
class Google_translate {

/**
* Translate a piece of text with the Google Translate API
* @return String
* @param $text String
* @param $from String[optional] Original language of $text. An empty String will let google decide the language of origin
* @param $to String[optional] Language to translate $text to
*/
    function translate($text, $from = '', $to = 'en') {
        $url = 'http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q='.rawurlencode($text).'&langpair;='.rawurlencode($from.'|'.$to);
        $response = file_get_contents(
            $url,
            null,
            stream_context_create(
            array(
            'http'=>array(
            'method'=>"GET",
            'header'=>"Referer: http://".$_SERVER['HTTP_HOST']."/\r\n"
            )
            )
            )
        );
        
        if (preg_match("/{\"translatedText\":\"([^\"]+)\"/i", $response, $matches)) {
            return self::_unescapeUTF8EscapeSeq($matches[1]);
        }
        return false;
    }
    /**
     * Convert UTF-8 Escape sequences in a string to UTF-8 Bytes. Old version.
     * @return UTF-8 String
     * @param $str String
     */
    function __unescapeUTF8EscapeSeq($str) {
        return preg_replace_callback("/\\\u([0-9a-f]{4})/i", create_function('$matches', 'return html_entity_decode(\'&#x\'.$matches[1].\';\', ENT_NOQUOTES, \'UTF-8\');'), $str);
    }
    /**
     * Convert UTF-8 Escape sequences in a string to UTF-8 Bytes
     * @return UTF-8 String
     * @param $str String
     */
    function _unescapeUTF8EscapeSeq($str) {
        return preg_replace_callback("/\\\u([0-9a-f]{4})/i", create_function('$matches', 'return Google_Translate_API::_bin2utf8(hexdec($matches[1]));'), $str);
    }
    /**
     * Convert binary character code to UTF-8 byte sequence
     * @return String
     * @param $bin Mixed Interger or Hex code of character
     */
    function _bin2utf8($bin) {
        if ($bin <= 0x7F) {
            return chr($bin);
        }
        else if ($bin >= 0x80 && $bin <= 0x7FF){
            return pack("C*", 0xC0 | $bin >> 6, 0x80 | $bin & 0x3F);
        }
        else if ($bin >= 0x800 && $bin <= 0xFFF) {
            return pack("C*", 11100000 | $bin >> 11, 0x80 | $bin >> 6 & 0x3F, 0x80 | $bin & 0x3F);
        }
        else if ($bin >= 0x10000 && $bin <= 0x10FFFF) {
            return pack("C*", 11100000 | $bin >> 17, 0x80 | $bin >> 12 & 0x3F, 0x80 | $bin >> 6& 0x3F, 0x80 | $bin & 0x3F);
        }
    }
}

I hope some one finds this useful




Theme © iAndrew 2016 - Forum software by © MyBB