Jump to content

Adding pages through the API

Recommended Posts


I'm working around a module that adds pages in my ProcessWire installation. The pages are added based on a JSON array that will be imported through a page save. Everything works fine except for when the pages are added. I get the following error

Integrity constraint violation: 1062 Duplicate entry '3e215ecd6774fd99c2b0eb5cadf36a07-1269' for key 'name_parent_id'

I'm using the following code/loop to generate the pages.

// Loop through the files
foreach ($p->importFile as $file)
    // Set the file location
    $name = $file->data["basename"];
    $path = $p->importFile->path;
    $location = $path . $name;

    // Get the file
    $json = file_get_contents($location);
    $json = json_decode($json);

    // Loop through the rows of the import
    foreach ($json->ttEntityDelAddrLink as $client)
        // Create new page
        $new = new Page();

        // Create unique hash
        $unique = md5(date("Y-m-d H:i:s") . "-" . $client->CustomerCode);

        // Set some variables for the new page
        $new->template = "_client";
        $new->parent = $p;

        // Create hash
        $new->title = $client->DelAddressName;
        $new->name = $unique;

        // Page specific fields
        $new->company = $client->DelAddressName;
        $new->companyId = $client->CustomerCode;
        $new->city = $client->DelAddressCity;
        $new->address = $client->DelAddressStreet;
        $new->postcode = $client->DelAddressZipCode;
        $new->country = $countries[$client->DelAddressCountryCode];

        // Save the page

    // Exit for debugging

Does anybody know what's wrong?

Share this post

Link to post
Share on other sites

If the CustomerCode can be identical, you're likely creating identical names within a second. In that case, I'd add a simple counter to the page name seed.


  • Like 4

Share this post

Link to post
Share on other sites

Ok, but that's why I'm trying to prevent with the hash as $page->name. I'm using the ID of the customer combined with a timestamp to generate a md5 hash that's "unique". (See the code, I'm pretty sure it should work). 

Also, the next entry in the array has a complete different customer id. So it should be "impossible" to be duplicated.

I'm using this code within a pageSaveHook (module). Could this be a problem? Furthermore, the array counts 11000+ entries, could it be that this is a problem? The platform is hosted on a stable and fast VPS and I cranked up the PHP execution time to 10 minutes, so it shouldn't cause any serious trouble.

Share this post

Link to post
Share on other sites
1 hour ago, jrtderonde said:

Ok, but that's why I'm trying to prevent with the hash as $page->name. I'm using the ID of the customer combined with a timestamp to generate a md5 hash that's "unique". (See the code, I'm pretty sure it should work). 

What @BitPoet said. In other words, PHP is fast, MySQL is fast. So, there is no guarantee that you will have only 1 page created per second (your date), or even per microsecond! That leaves you with uniqueness dependent only on the customer ID ($client->CustomerCode). If you can guarantee that customer IDs are unique and that they only appear once per data set, (your JSON array) then you would be fine. The fact that you are getting a SQL error tells us that either your customer IDs are not unique and/or one customer ID is appearing more than once in your data set (i.e., it may be uniqe to the customer, but not the data set). If the database says so, then it must be so ;). Let me illustrate (non-unique customer ID and/or replicated customer ID):


$clientCustomerCode = 12345;// replicating repeated use of customer ID
$p = $pages->get(1722);

for ($i=0; $i < 30; $i++) { 
	// Create new page
	$new = new Page();
	// Create unique hash {no guarantee this will be unique if same customer ID used}
	$unique = md5(date("Y-m-d H:i:s") . "-" . $clientCustomerCode);
        // even these (microseconds) do not guarantee uniqueness throughout
	#$unique = round(microtime(true) * 1000) . "-". $clientCustomerCode;
	#$unique = microtime(true) . "-". $clientCustomerCode;
	#$unique = microtime() . "-". $clientCustomerCode;

	echo $i . ': ' . $unique . '<br>';// display 'uniqueness'; you should see duplicates here

	// Set some variables for the new page
	//$new->setOutputFormatting(false);// not needed for a new page (I think)
	$new->template = "basic-page";
	$new->parent = $p;   
	// Create hash
	$new->title = "Title " . rand(5,15);// just for testing
	$new->name = $unique;// not really unique!
	// Save the page
	#$new->save();// you'll get PDO error here within a second


Using the above code, you'll be hit by the duplicate entry violation error within a second...

Edited by kongondo
  • Like 7

Share this post

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Atlasfreeman
      I want to make a small site, a one page site.
      And i have this idea about doing 2 to 3 diffrent template that i can load into the index / home page.

      I want to do this with an array so that i can keep creating more topics (with the template) id needed.
      <?php include('./head.inc'); // include header markup ?> <?php $children = $page->get('template=onecolmn|twocolumn, sort=sort'); foreach($children as $child) { include($child); } ?> <?php include('./foot.inc'); // include footer markup ?>  
      As you can see i have to template wish i want to control from the backend.
      I know include does not work this way, put what is my other option to make an array that loads the whole page on an other pages.
    • By Noel Boss
      👋 PW Pros…
      I have some hooks that I need to bind at the init phase (or even __construct) and I was wondering, and I couldn't find a good and simple way to determine if I'm in the admin. Would be nice if there is a reliable short option to do so, but I can't seem to find one… Is there a coherent way to tell this no matter where I am?
      Right now, I use the following method inside one of my modules:
      public function isAdmin($page = null) { if ( strpos($this->input->url, $this->urls->admin) !== false || $this->process instanceof ProcessPageList || $this->process instanceof ProcessPageEdit || ($page instanceof Page && $page->rootParent->id == $this->config->adminRootPageID) ) { return true; } return false; } @ryan wouldn't it be nice to have something like wire()->isAdmin(); like wire()->user->isLoggedin(); to tell if we are in admin – very early on (probably even in __construct() phase of modules?
    • By jom
      Hi everyone
      It seems that I don't fully understand the wireTempPath() function and I need some help.
      I use wireTempPath() to create a new location in assets/cache/WireTempDir and than copy a pdf from the assets/files/page folder to the new folder. I want the file to be accessible only for a limited time, that's why I use wireTempPath.
      The file seems to be copied to the right location, but gets deleted right afterwards, according to 
      As mentioned in the topic above, 
      $wireTempDir->setRemove(false); prevents the file to be deleted. But I like the file to be automatically deleted after a few days. So, how can I do that?
      My code so far (everything works, but the automatic removal of the tempDir folder):
      //generate and show download link $folder = time(); // timestamp as temporary folder $maxAge = (int) $settings->options_downloadlink_valid_hours * 3600; //tempDir wants maxAge as seconds $options = array( 'maxAge' => $maxAge ); $wireTempDir = wireTempDir($folder, $options); $wireTempDir->setRemove(false); $src_file = $page->ebook_download->filename; // Create a new directory in ProcessWire's cache dir if(wire('files')->mkdir($wireTempDir, $recursive = true)) { if(wire('files')->copy($src_file, $wireTempDir)){ //get subdirs from tempDir: $pos = strpos($wireTempDir, "WireTempDir"); $subdir = substr($wireTempDir, $pos, 100); $out .= "<p><a href='" . wire('pages')->get('template=passthrough')->httpUrl . "?file=" . $subdir . $page->ebook_download->basename . "' target='_blank'>$page->title</a></p>"; } } I appreciate any ideas - thanks!
    • By VeiJari
      Hello forum, this is my first security related post, so I'm a bit of a newbie.
      I understand that when I have direct front-input from user I should sanitize the input, but how about when I use a secret key for showing a API for a third-party supplier? Should I sanitize the input->get() key?
      I've tested this issue and I tried ?key=<?php echo $page->field; ?> And without adding any sanitization it comes back: /?key=<?php%20echo%20$page->field;%20?>
      So can I rely on this, or should I still use $sanitizer just in case?
      Thanks for the help!
    • By EyeDentify
      I have been experimenting with the new $page->meta() method and find it useful.

      Once i figured out that the data i "save" with it is tied to the page where i called the method from.

      So this is not obvious at least not for me in the documentation:
      So i just wanted to share that revelation with the community so you don´t get as confused as i was.

      Happy Coding Everyone.
  • Create New...