Can Posted February 25, 2016 Share Posted February 25, 2016 Hey friends I gotta little side project, I'm building a little bookmark management tool. For this I made a little bookmarklet, which will add the currently opened page. The opening popup lets me adjust name, url and add tags. I thought it might be nice to be able to enter not only "plain" tags, but build a structure on the fly. So when I'm entering (let's say none of them exists at that moment) Processwire>Docs>Security the script creates tag called Processwire, add Docs as child and Security as child of Docs. This part works great. The only problem I'm having, is that I already got a tag called "Docs" but it's a root tag and I want to have a new one as child of Processwire So I want the following in the end. /tags/Docs/ /tags/Processwire/ /tags/Processwire/Docs/ /tags/Processwire/Docs/Security/ but I'm getting /tags/Docs/Security/ instead, because Processwire and Docs already exist.. so this is the code where I'm stuck function processTags($tags, $tagParent = 'tags') { $vars = array('sanitizer', 'pages'); foreach ($vars as $var) ${$var} = wire("$var"); // create new PageArray to hold all tags $tagPages = new PageArray(); // sanitizer array will handle delimited (',', '|') string input for us $tagsArray = $sanitizer->array($tags); foreach ($tagsArray as $tag) { // if closing bracket found than split if (strpos($tag, '>') !== false) { $thePapas = explode('>', $tag); // for ($i=0; $i<count($thePapas); $i++) { foreach ($thePapas as $tp) { // determine parent either /tags/ or the previous tag $parentTag = ($tagPages->count()) ? $tagPages->last() : 'tags'; // and thru this same function $tagPages->add(processTags($tp, $parentTag)); } // we stop here and return to prevent duplicates // we add only the last because the others are in a parent relationship already return $tagPages->last(); } else { $tagParent = ($tagParent instanceof Page) ? $tagParent->path : "/$tagParent/"; // no parent>tag pair so look if tag exists, otherwise create $t = $pages->getByPath("{$tagParent}{$tag}/"); if (!$t->id) { $t = new Page(); $t->parent = "$tagParent"; $t->template = 'tag'; $t->title = $tag; $t->save(); } // add to PageArray $tagPages->add($t); } } return $tagPages; } I'm calling it like processTags('ProcessWire>Docs>Security') And even though I'm searching for existing tags with getByPath it's not working.. :/ For the record, this project is on PW 3.0.8 devns Hope I could explain my problem/question sufficiently? Ah, to clarify. When using all new tag names it's working great.. Saluditos Can Link to comment Share on other sites More sharing options...
horst Posted February 25, 2016 Share Posted February 25, 2016 (edited) Hi Can, a short code example how I would go with it. It is written in the browser, not tested, and it is the bare core of my idea, you need to add the rest by yourself, if it works: // $tags is a string like: "Processwire>Docs>Security" function doTags($tags, $tagParent = 'tags') { $vars = array('sanitizer', 'pages'); foreach ($vars as $var) ${$var} = wire("$var"); $parts = explode('>', $tags); // parts now holds the hirarchical ordered parent list, without the rootParent named in $tagParent $parent = $pages->get("name=$tagParent"); foreach($parts as $part) { // try to get a childpage with name $part and parent = $parent $p = $pages->get("parent=$parent, name=" . $sanitizer->pageName($part)); if(0 == $p->id) { // if it do not exist, create it now $p = new Page(); $p->parent = $parent; $p->template = 'tag'; $p->title = $part; $p->save(); } // switch parent to the next level: $parent = $p; } } Edited February 25, 2016 by horst 1 Link to comment Share on other sites More sharing options...
Can Posted February 26, 2016 Author Share Posted February 26, 2016 (edited) Thank you horst! Anyway your code is awesome, so much cleaner! Even though I added a second loop to handle multiple comma (or dash) separated tag groups and added comments your version is still shorter! function processTags($tags, $tagParent = 'tags') { $vars = array('sanitizer', 'pages'); foreach ($vars as $var) ${$var} = wire("$var"); // added this loop to split CSV strings // now we can enter multiple seperate tags with children // like "Tag1,Tag2>Child Tag,Tag3" $tagsArray = $sanitizer->array($tags); $return = new PageArray(); foreach ($tagsArray as $tagGroup) { // parts now holds the hirarchical ordered parent list, without the rootParent named in $tagParent $parts = explode('>', $tagGroup); // we need to set the parent for every tag group // which can be a single comment or can have children // otherwise "Tag 3" (above example) would be a child of "Child Tag" $parent = $pages->getByPath("/$tagParent/"); foreach($parts as $part) { // try to get a childpage with name $part and parent = $parent // added second argument (2) to pageName sanitizer for translation // because the page creation uses this, so without it wouldn't find existing pages.. $p = $pages->getByPath($parent->path . $sanitizer->pageName($part, 2)); if(!$p->id) { // if it do not exist, create it now $p = new Page(); $p->parent = $parent; $p->template = 'tag'; $p->title = $part; $p->save(); } // switch parent to the next level: $parent = $p; $return->add($p); } } return $return; } Thanks a lot horst!! EDIT: I changed the $pages->get() queries to $pages->getByPath() which requires PW 3.0.6. Check out Ryans blog post with benchmarks EDIT 2: It's now returning the created (or existing) tags. Edited February 26, 2016 by Can 1 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