Jump to content

recursive page creation


Can
 Share

Recommended Posts

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

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 by horst
  • Like 1
Link to comment
Share on other sites

Thank you horst!

Anyway your code is awesome, so much cleaner! :D Even though I added a second loop to handle multiple comma (or dash) separated tag groups and added comments your version is still shorter! :D

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 by Can
  • Like 1
Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...