evanmcd Posted April 5, 2013 Share Posted April 5, 2013 Hi, I've been using PW as the back end for a number of contest sites in which users enter a short bit of text as an answer to a question. Each "entry" ends up as a PW Page. In this case, it's quite common for people to provide the same answer, which of course results in a duplicate page error (Exception: Duplicate entry). I'm wondering if there is a way to have PW automatically create a unique page name when it creates a new page that would have a duplicate name - like this-is-a-test becoming this-is-a-test-2. Any help is great appreciated! Thanks. Link to comment Share on other sites More sharing options...
WillyC Posted April 5, 2013 Share Posted April 5, 2013 $page=new Page(); $page->template='basic-page'; $page->parent='/mommy/'; $page->name=microtime(); // .or $page->name='gilderbergersbang' . $page->parent->numChildren; 5 Link to comment Share on other sites More sharing options...
evanmcd Posted April 5, 2013 Author Share Posted April 5, 2013 Great ideas @WillyC. I think I'll go with the numChildren. Brilliant! Thanks. Link to comment Share on other sites More sharing options...
diogo Posted April 5, 2013 Share Posted April 5, 2013 although numChildren is not bulletproof if you start deleting pages... but what are the odds? 1 Link to comment Share on other sites More sharing options...
Wanze Posted April 5, 2013 Share Posted April 5, 2013 I'm not 100 % sure right now, but I think if you don't set a name, Pw takes already care of this problem. Edit: Yep it does, found the code in Pages::___setupNew() protected function ___setupNew(Page $page) { if(!$page->name && $page->title) { $n = 0; $pageName = $this->fuel('sanitizer')->pageName($page->title, Sanitizer::translate); do { $name = $pageName . ($n ? "-$n" : ''); $child = $page->parent->child("name=$name"); // see if another page already has the same name $n++; } while($child->id); $page->name = $name; } //... So just set the title. If the same title appears multiple times, the API generates a name with -1,-2,-3... 6 Link to comment Share on other sites More sharing options...
Martijn Geerts Posted April 5, 2013 Share Posted April 5, 2013 @wanze: you're right. (Think pw ads _1 on the end when exist) I thought to save it without name & then re-save it with page id as name with some string adition. Then you're name is always unique & easy querying. (On mobile, not able to test) Link to comment Share on other sites More sharing options...
Martijn Geerts Posted April 5, 2013 Share Posted April 5, 2013 Oops to late. Damn wanze. 2 Link to comment Share on other sites More sharing options...
Wanze Posted April 5, 2013 Share Posted April 5, 2013 Oops to late. Damn wanze. Sorry Martijn, I used the "Answer-fast-and-edit-afterwards" trick But for my defence, I had to look up the code to be sure 1 Link to comment Share on other sites More sharing options...
diogo Posted April 5, 2013 Share Posted April 5, 2013 I guess it's even more brilliant to just let pw do it's work 1 Link to comment Share on other sites More sharing options...
kyle Posted July 14, 2013 Share Posted July 14, 2013 I tried to create a page via the API without a name and it displayed an error saying the name had to be set. This is my solution based off of the the code Wanze posted. /* * Clean URL */ function clean_string($string) { return trim(preg_replace('~[^0-9a-z]+~i', '-', html_entity_decode(preg_replace('~&([a-z]{1,2})(?:acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i', '$1', htmlentities($string, ENT_QUOTES, 'UTF-8')), ENT_QUOTES, 'UTF-8')), '-'); } /* * Check for duplicate name */ function check_name ($title, $path) { $parent_page = wire("pages")->get($path); $n = 0; $pageName = strtolower(clean_string($title)); do { $name = $pageName . ($n ? "-$n" : ''); $child = $parent_page->child("name=$name"); // see if another page already has the same name $n++; } while($child->id); return $name; } Link to comment Share on other sites More sharing options...
teppo Posted July 14, 2013 Share Posted July 14, 2013 @kyle: Just tried creating pages via API in PW 2.2.9 and 2.3.1 and in both setting template, title and parent was enough, name wasn't needed.. and like @Wanze and others pointed out above that way PW automagically creates unique names. Then again, I can't really remember how this stuff worked in earlier versions, so perhaps it hasn't always been quite as simple.. Anyway, even if setting name and making it unique yourself is necessary, I'd still suggest using built-in $sanitizer (in API context wire('sanitizer')) for sanitizing your page name instead of own custom code. This way you'll get page names that are 100% compatible with PW (and with less code.) 1 Link to comment Share on other sites More sharing options...
ryan Posted July 14, 2013 Share Posted July 14, 2013 Teppo is right that all recent versions of PW will take care of creating a name for you, so long as you've at least set a title. It will also number-increment the name (i.e. "page-name-2") if one already exists. But if you want to go with a different way of setting the name, perhaps some other format, then it's always fine to set it yourself too. Link to comment Share on other sites More sharing options...
MatthewSchenker Posted July 14, 2013 Share Posted July 14, 2013 Greetings, I am preparing another forum post about different ways to deal with duplicate titles in front-end forms. But in the meantime... What about appending the date/time onto the titles? That would ensure unique titles, and give you useful information right in the title. Of course, this would only be good in cases where you are not going to display the page to the public (which is the case here). Thanks, Matthew 1 Link to comment Share on other sites More sharing options...
ryan Posted July 16, 2013 Share Posted July 16, 2013 What about appending the date/time onto the titles? That would ensure unique titles, and give you useful information right in the title. Of course, this would only be good in cases where you are not going to display the page to the public (which is the case here). There are name collision possibilities with date/time (two being added at same exact time), but it's reasonably reliable other than that. ProcessWire actually uses microtime when creating pages internally that aren't named (or don't yet have a name), like the pages it creates for repeaters. I could see using the same method for unnamed pages anywhere. Link to comment Share on other sites More sharing options...
alan Posted March 10, 2016 Share Posted March 10, 2016 I was using Soma's lovely example of how to create a page via the API and began AOK then started getting Fatal error: Exception: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'mynewpage_url3-1075' for key 'name_parent_id' (in /wire/core/Pages.php line 2103) #0 /wire/core/Pages.php(2103): PDOStatement->execute() #1 /wire/core/Pages.php(1161): Pages->executeQuery(Object(PDOStatement)) #2 /wire/core/Pages.php(1055): Pages->savePageQuery(Object(Page), Array) #3 [internal function]: Pages->___save(Object(Page), Array) #4 /index.php on line 248 Then I found Wanze's super comment but I think if you don't set a name, Pw takes already care of this problem. Problem solved! Posted this just in case a Google search for that error helps someone else. 1 Link to comment Share on other sites More sharing options...
SteveB Posted March 10, 2016 Share Posted March 10, 2016 Another thing you can do is hook Pages::added (only called for new pages, not when re-saving existing ones) and in your hooked function set the page name to the page id, which is already part of the page at that point. 2 Link to comment Share on other sites More sharing options...
Ivan Gretsky Posted November 15, 2021 Share Posted November 15, 2021 On 7/14/2013 at 8:33 AM, teppo said: @kyle: Just tried creating pages via API in PW 2.2.9 and 2.3.1 and in both setting template, title and parent was enough, name wasn't needed.. and like @Wanze and others pointed out above that way PW automagically creates unique names. Then again, I can't really remember how this stuff worked in earlier versions, so perhaps it hasn't always been quite as simple.. Anyway, even if setting name and making it unique yourself is necessary, I'd still suggest using built-in $sanitizer (in API context wire('sanitizer')) for sanitizing your page name instead of own custom code. This way you'll get page names that are 100% compatible with PW (and with less code.) Sorry for resurrecting this topic. But I think my question is related yet (not exactly the same). If I clone a page, set new title and save it under the target parent, that already has a page with a same name as generated from that title, the name doesn't receive an increment. But it rather is set to the name of the default page, that was cloned, with an increment. Let me explain on example: I've got page with a name template under Templates parent page. Then I clone it, set it's name to an empty string, set some title (e.g. example) and save under another page Destination. The cloned page under Destination gets name example. Then I clone another page from template, set it the same title (example), and save it under Destination. I am hoping to see it receive a name example-2, but it is saved as template-2 instead. I guess that is happening because when I clone a page it runs that setupNew method before I assign a title to it. The question is: is there a way to use the same in-built logic for handling duplicate names when cloning pages? Link to comment Share on other sites More sharing options...
elabx Posted November 16, 2021 Share Posted November 16, 2021 On 11/15/2021 at 9:40 AM, Ivan Gretsky said: The question is: is there a way to use the same in-built logic for handling duplicate names when cloning pages? If I'm understanding the problem right, maybe the PagesNames class could be useful in this scenario?? https://processwire.com/api/ref/pages-names/unique-page-name/ 2 Link to comment Share on other sites More sharing options...
Zeka Posted November 17, 2021 Share Posted November 17, 2021 Several ways to do it: $page_to_clone = pages(1051); $destination_parent = pages(1016); $new_title = 'Example'; $pages->clone($page_to_clone, $destination_parent, false, [ 'set' => [ 'title' => $new_title, 'name' => '' ] ]); //////////////// wire()->addHookAfter('Pages::cloneReady', function ($event) { $pages = $event->object; $pagesNames = $pages->names(); $oldPage = $event->arguments(0); $newPage = $event->arguments(1); $sanitizer = $this->wire()->sanitizer; $newName = $sanitizer->pageNameTranslate($newPage->get('title')); $newPage->name = $pagesNames->uniquePageName($newName, $newPage->parent); }); //////////////// $page_to_clone = pages(1051); $destination_parent = pages(1016); $new_title = 'Example'; $pages->clone($page_to_clone, $destination_parent, false, [ 'set' => [ 'title' => $new_title, 'name' => $pages->names()->uniquePageName($sanitizer->pageNameTranslate($new_title), $destination_parent) ] ]); 2 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now