Jump to content
a-ok

Mass create pages OR mass upload images and thus create pages

Recommended Posts

Hi folks,

This might be more a DB/mySQL question, perhaps, but thought I'd put it to the forum for discussion.

I have a lot of pages to add to a certain section of my PW site.

Portraits

> Portrait 1

> Portrait 2

...

> Portrait 100

Each page has one image only.

I am wondering if it is possible, if the image filenames and the titles of each 'page' are the same, if I can somehow mass upload these images to create pages from? Either through the backend or via the DB? So, for example:

julian.jpg > Julian (page created with this image)

kate.jpg > Kate (page created)

...

mat.jpg > Mat (page created)

This, of course, is only to save time... but wondered what you all thought? Or, even still, is it possible to mass create pages much like you can do with templates?

Thanks for your time.

Share this post


Link to post
Share on other sites

There are various topics in the forum about importers. The only thing different in really "mass" creation is that you need to be aware of timeouts / memory_limits and batching things before you hit them.

  • Like 1

Share this post


Link to post
Share on other sites
class ImageBatcher extends WireData implements Module {

    /**
     * getModuleInfo is a module required by all modules to tell ProcessWire about them
     *
     * @return array
     *
     */
    public static function getModuleInfo() {

        return array(

            'title' => 'Image Batcher', 
            'version' => 1, 
            'summary' => 'Do some additional actions after uploading an image',
            'singular' => true, 
            'autoload' => true,  
            );
    }

    /**
     * Initialize the module
     * 
     */
    public function init() {
        // do additional action after upload
        $this->addHookAfter('InputfieldImage::fileAdded', $this, 'createPageFromImage');
    }

    /**
     * create Page from uploaded Image
     *
     */
    public function createPageFromImage($event) {

        $file = $event->arguments(0);
        $parent = wire('pages')->get('/batcher'); // didn't know how to get the current page dynamically 

        // create new page
        $np = new Page();
        $np->parent = $parent;
        $np->template = 'portrait';
        $np->title = $file->name;
        $np->save(); // page has to be saved before adding images

        // add image
        $np->image->add($file->filename);
        $np->save();
    }

}

played a little around... something like this? :)

i didn't know how to get the current page dynamically... and i didn't manage to clear the added files from the "batcher" page because i got some errors i can't explore in detail right now.

this thread should also give you useful information: https://processwire.com/talk/topic/8698-creating-page-for-every-image-uploaded/

edit: i think hooking the method fileAdded should keep you save from timeouts though other things may get more complicated as it are all ajax requests (like the error i got when trying to remove all uploaded images from the batcher page)

edit2: of course you would have to check if the file was added to a "batcher" page. otherwise all your image uploads will create new pages. or you could bind the module to a specific imagefield only.

  • Like 1

Share this post


Link to post
Share on other sites

you would have to name this file ImageBatcher.module and place it in your modules folder /site/modules

then go to modules > install > new and maybe refresh, then install

but this is no working and bulletproof code! use a dev-installation to test everything!

here are lots of informations:

https://processwire.com/api/modules/

https://processwire.com/api/hooks/

Share this post


Link to post
Share on other sites

Thanks, BernhardB. I'm thinking a PHP query that writes each image from a folder into the DB, as it is a one-off scenario, and uses a similar structure to what you suggested.

All the filenames have the year and title of the page, so for example:

2006_ALI.jpg should equal a page created called Ali, under the parent of 1026 and the date field should have the 2006

parent id in the DB for each page is 1026

title field in the DB is field_title (eg. Ali)
date field in DB is field_works_date (eg. 2007)
image field in the DB is field_works_image (eg. ocean_liner.jpg)

What do you think? Possible?

Share this post


Link to post
Share on other sites

sure possible

why do you want to write directly to the DB? if you create pages you have all the benefits of processwire like page editing, pagination, file handling and so on.

just use my example and replace:

$parent = wire('pages')->get(1026); // your given id of the new parent

$np->title = your part of the image filename that represents the title (see php string functions)

$np->date (you have to create this field) = part of the filename that represents the date (year)

Share this post


Link to post
Share on other sites

ImagesManager is made for such tasks.

  • Like 1

Share this post


Link to post
Share on other sites

I'm confused as I am unsure where to execute the module? Where do I upload the images?

I couldn't find ImagesManager, @Soma.

Share this post


Link to post
Share on other sites

UNTESTED, probably have some typos + poorly formatted code (I gotta run...)

You want to add this to your template file....Wrap it around code that ensures only Superuser can load the code...

//absolute path to a directory called 'tmp' within the site folder where we have our images
$dir = $config->paths->site . 'tmp';

$addAndPublish = false;//true if you want to publish on save
//prepare some variables we'll need later
$a = 0;//for photo pages count
$failed = array();

$parent =$pages->get('/portraits/');
$t = wire('templates')->get('your-portrait-template-name');

//if we found the directory (here we use Standard PHP Library (SPL))
if (is_dir($dir)) {

    $directory = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS); 

    //iterate through each file in this directory
    foreach ($directory as $path ) {            

       set_time_limit(30);//we try to avoid timing out

       //Remove and delete invalid file types
       $validImagesExts = array('jpg', 'png', 'gif', 'jpeg');
       if($path->isFile() && !in_array($path->getExtension(), $validImagesExts)) {
        unlink($path);//we delete the invalid file
        continue;
    }

     //if valid image file we create a page named after it and later save it to the page
     if($path->isFile()) {

     //we are ready to start creating pages...
     $p = new Page();
    $p->parent =$parent;
    $p->template = $t;
    $title = $path->getBasename('.' . $path->getExtension());
    $p->title = $this->sanitizer->text($title);
    if (!$p->title) continue;//skip to next if no title found (just in case)
   $p->name = $this->sanitizer->pageName($p->title);//sanitize and convert to a URL friendly page name

    //check if name already taken
    if($p->parent->child("name={$p->name}, include=all")->id) {

        //if the same name already exists, add it to the $failed array [to display to user in error later] and skip to next title
        if ($path->isFile()) {
          $failed [] = $path->getFilename();
        }

        continue;
     }

     //if add and publish is false, we save new page unpublished
     if (!$addAndPublish) $p->addStatus(Page::statusUnpublished);
     $p->save();

      //add image to the page and save again
      $p->images_field->add($dir . '/' . $path->getFilename());
      $p->save();

      $a++;
      unlink($path);//we delete the temp file

    }

}//end foreach

     //delete the tmp directory
     wireRmdir($dir, $recursive = true);

    //create a string of "failed" category titles to add to error message
    $failedTitles = implode(', ', $failed);

    //give the user some feedback...
    if($a > 0) echo 'Added' . $a . 'Portraits<br>';
    if($failedTitles) echo 'Some Portraits not added because names already in use. These are:' . $failedTitles;

}//end if (is_dir($dir)))

else echo 'No Such Directory Found!';
Edited by kongondo
  • Like 7

Share this post


Link to post
Share on other sites

This was great and was really what I was after... helped me loads. I made a few tweaks to add in dates and stuff but I really appreciate you helping me out there. Hopefully some other people can use this method too!

Share this post


Link to post
Share on other sites

@Richard, glad you got it sorted.

Btw, I have another version that recursively searches through folders, sub-folders, etc....The Standard PHP Library (SPL)) is really cool :-)

  • Like 1

Share this post


Link to post
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

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By benbyf
      Hi, Looking to create form elements on a page–some input with a colection of form inputs and the appropriate labels and variables for that input. I've used ProForms in the past and rolled out my own when creating simply one off forms, but I wonder if anyone has found a good way of allowing form creation on page editing so that clients can adhocly make and edit forms?
      Thanks
    • By dimitrios
      Hello,
      this module can publish content of a Processwire page on a Facebook page, triggered by saving the Processwire page.
      To set it up, configure the module with a Facebook app ID, secret and a Page ID. Following is additional configuration on Facebook for developers:
      Minimum Required Facebook App configuration:
      on Settings -> Basics, provide the App Domains, provide the Site URL, on Settings -> Advanced, set the API version (has been tested up to v3.3), add Product: Facebook Login, on Facebook Login -> Settings, set Client OAuth Login: Yes, set Web OAuth Login: Yes, set Enforce HTTPS: Yes, add "https://www.example.com/processwire/page/" to field Valid OAuth Redirect URIs. This module is configurable as follows:
      Templates: posts can take place only for pages with the defined templates. On/Off switch: specify a checkbox field that will not allow the post if checked. Specify a message and/or an image for the post.
      Usage
      edit the desired PW page and save; it will post right after the initial Facebook log in and permission granting. After that, an access token is kept.
       
      Download
      PW module directory: http://modules.processwire.com/modules/auto-fb-post/ Github: https://github.com/kastrind/AutoFbPost   Note: Facebook SDK for PHP is utilized.


    • By David Karich
      The Page Hit Counter module for ProcessWire implements a simple page view counter in backend. Page views of visitors are automatically tracked on defined templates, with monitoring of multiple page views. This gives you a quick overview of how many visitors have read a news or a blog post, for example, without first having to open complex tools such as Google Analytics. This module quickly provides simple information, e.g. for editors. Or, for example, to sort certain news by most page views. For example for "Trending Topics".

       
      Works with ProCache and AdBlockers. With a lightweight tracking code of only ~320 bytes (gzipped). And no code changes necessary! In addition GDPR compliant, since no personal data or IP addresses are stored. Only session cookies are stored without information. 
      In addition, there are some options, for example filtering IP addresses (for CronJobs) and filtering bots, spiders and crawlers. You can also configure the lifetime of the session cookies. Repeated page views are not counted during this period. It is also possible to exclude certain roles from tracking. For example, logged in editors who work on a page are not counted as page views.

      Sort by hits and access page views (hit value)
      Each trackable template has an additional field called phits. For example, you want to output all news sorted by the number of page views.
      // It is assumed that the template, e.g. with the name "news", has been configured for tracking. $news = $pages->find("template=news, sort=-phits"); To output the page views of a tracked page, use:
      echo $page->phits; Example: Reset counter per API
      $modules->get("PageHitCounter")->resetPageViews("template=whatever", false); Example: Tracking a page hit via API and jQuery
      If you want to track a template that does not represent a full page to automatically inject a tracking script, you can define allowed API templates in the module that you can track. Below is an example of how you can track a click on news tag using jQuery. This will allow you to find out which keywords are clicked the most. For example, you can sort and display a tag cloud by the number of hits. Suppose your keywords have the template "news_tag". The template "news_tag" was also configured in the Page Hit Counter Module as a trackable API template.
      Example PHP output of keywords / tags:
      // Required: the data attribute "data-pid" with the ID of the template to be tracked. echo $pages->find("template=news_tag, sort=-phits")->each("<a href='{url}' class='news_tag' data-pid='{id}'>{title}</a>"); Example Tracking Script with jQuery:
      /** * Required: Data attribute "data-pid" with the ID of the news tag template * Required: Send the POST request to the URL "location.pathname.replace(/\/?$/, '/') + 'phcv1'" * Required: The POST parameter "pid" with the ID of the template */ $(function(){ if($('a.news_tag').length > 0) { $('a.news_tag').each(function(){ var tPID = $(this).data("pid"); if(tPID) { $(this).on("click", function(){ $.post(location.pathname.replace(/\/?$/, '/') + 'phcv1', {pid: tPID}); }); } }); } }); So simply every click on a tag is counted. Including all checks as for automatic tracking. Like Bot Filtering, Session Lifetime, etc.
      Notice: Tracking with URL segments
      If the option "Allow URL Segments" is activated on a template, the hits are only counted if the base URL of the page is called. If you want the hit to be counted even when a segment is requested, you MUST configure the segments in the template configuration. How to do this can be found here. If you use dynamic segments, configure them as RegEx. There is currently no other option. The problem is that the Page Hit Counter hooked into the PageNotFound process. If URL segments are allowed but not defined, a 404 is never triggered. This means that the Page Hit Counter cannot be called.
      _______________________________________________________
      Background: This module is the result of a customer requirement, where the editors are overwhelmed with analytics or no tracking tools were allowed to be used. However, a way had to be found to at least count page views in a simple form for evaluations. Furthermore, by using ProCache, a way had to be found to count views of a page without clearing the cache.
      _______________________________________________________
      Pros
      Automatic Page View Tracking Lightweight tracking code, only ~320 bytes (gzipped) No code or frontend changes necessary Works with ProCache! Even if no PHP is executed on the cached page, the tracking works Works with browser AdBlockers No cache triggers (for example, ProCache) are triggered. The cache remains persistent GDPR compliant, session-based cookie only, no personal information Filtering of IPs and bots possible Exclude certain roles from tracking Ability to reset Page Views Works with all admin themes Counter database is created as write-optimized InnoDB API to track events for templates that are not viewable No dependencies on libraries, pure VanillaJS (Automatic tracking script) Works in all modern browsers Pages are sortable by hits Cons
      Only for ProcessWire version 3.0.80 or higher (Requires wireCount()) Only for PHP version 5.6.x or higher No support for Internet Explorer <= version 9 (Because of XMLHttpRequest()) No historical data, just simple summation (Because of GDPR) Segment URLs can only be counted if the segments are defined Planned Features / ToDos
      API access to hit values Since version 1.2.1 Possibility to sort the pages by hits (Request by @Zeka) Since version 1.2.0 Don't track logged in users with certain roles (Request by @wbmnfktr) Since version 1.1.0 Possibility to reset the counter for certain pages or templates (Request by @wbmnfktr) Since version 1.1.0 Better bot filter Since version 1.1.0 Disable session lifetime, don't store cookies to track every page view (Request by @matjazp) Since version 1.2.1 Option to hide the counter in the page tree (Request by @matjazp) Since version 1.2.1 Option to hide the counter in the page tree on certain templates Since version 1.2.1 API to track events for templates that are not viewable Since version 1.2.2 Changelog
      1.2.6
      Bug-Fix: Set the counter of a cloned page to 0 Enhancement: The function for resetting counters is now available in the module as a public function to reset counters via own scripts on the API side (Request by @VeiJari) Enhancement: Documentation improvement API reset 1.2.5
      Bug-Fix: When counting 404 hits, cookies are no longer set. The session lifetime is deactivated for the 404 page Enhancement: Documentation improvement regarding URL segments 1.2.4
      Bug-Fix: Resetting the counters on system pages (e.g. 404) does not work (Reported by wbmnfktr) Bug-Fix: Tracking endpoint is logged as 404 if module "Jumplinks" is installed (Reported by wbmnfktr) Enhancement: Corrected few typos (Merged from Sergio #6 – THX!) 1.2.3
      Bug-Fix: Tracking script triggers 404 if pages are configured without slash (#3) Reported by @maxf5 Enhancement: Reduction of the tracking script size if it's gzipped (~320 bytes) Enhancement: Documentation improvement Enhancement: Corrected few typos 1.2.2
      New feature: API to track events for templates that are not viewable Enhancement: Documentation improvement 1.2.1
      API access to hit values Use $page->phits Bug-Fix: No tracking on welcomepage (Reported by wbmnfktr; Thx to matjazp) Bug-Fix: Tracking script path on subfolders (Reported by matjazp) Bug-Fix: Tracking on pages with status "hidden" Enhancement: Change database engine to InnoDB for phits field Enhancement: Option to disable session lifetime set session lifetime to 0, no cookies Enhancement: Better installation check Enhancement: AJAX Request asyncron Enhancement: Reduction of the tracking script size by ~20% Enhancement: Option to hide the counter in the page tree You can output the counter with the field name "phits" Enhancement: Option to hide the counter in the page tree on certain templates Enhancement: Option for activate general IP validation Enhancement: Reduction of tracking overhead up to ~30ms Enhancement: Better bot list for detection 1.2.0
      New feature: Sort pages by hits – New field phits Migrate old counter data to new field 1.1.0
      New feature: Exclude tracking of certain roles New feature: Reset Page Views Better bot filter and detection 1.0.0
      Initial release Notes
      By default, the page views are stored as INT in the database. This allows a maximum counter value of 4.2 billion views (4,294,967,295) per page. If you need more, change the type to BIGINT directly in the database. But I recommend to use Google Analytics or similar tools if you have such a large number of users.
      _______________________________________________________
      Download GitHub: ProcessWire Page Hit Counter (Version 1.2.6)
      PW Module Directory: ProcessWire Page Hit Counter (Version 1.2.6)
      Install via ProcessWire (Classname): PageHitCounter
      _______________________________________________________
      Update information
      If you have used version 1.2.1 from the DEV branch, please replace it completely with the new master version.
    • By Atlasfreeman
      Hi!
      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 Liam88
      Hi All,
      New user over at Processwire and have been rebuilding my site based on this CMS.
      I have been able to find so many answers through Google but I'm a little stuck on this one.
      I have my services page -> services categories -> category children.
      An example of those would be - domain -> services -> ppc -> management
      I also have a set of tags which have different names - services-tag -> grow-your-traffic
      Under these tags I would have multiple links to pages such as ppc, seo, social media and so on.
      A second example would be - services-tag -> convert-your-traffic
      Under here i would have multiple links to pages such as CRO
      Now the set of tags are not visible on-site as they are only created to give overview content to the main services categories.
      Using the categories and the tags I am looking to produce a layout such as (i have also attached an image as an example:
      Tag_1 headline
      Pull all services categories linking to Tag_1
      Tag_1 snippet
      Tag_2 headline
      Pull all services categories linking to Tag_2
      Tag_2 snippet
      So far I have this snippet which is pulling in the tag content but unable to get the posts to show under each of the tags. 
      If i change the if and statement to "tags" instead of "tag" then all posts show under all tags. Where as i want it to show only the posts which are linked to that tag.
      <?php namespace ProcessWire; $tags = $pages->get("/categories-services/")->children(); // Gets the tags $posts = $pages->get("/services/")->children(); // Gets the services categories $link = $tags->ref_6; // Gets the tags and services categories link - under here you have pages_id (services cat id) and data (tags id) // Tag header and summary foreach($tags as $tag) { // This breaks down the tags into sections echo '<section id="services"> <div class="container"> <div class="row"> <h2 class="heading-1"><span>'. $tag->headline.'</span></h2> <p class="mb-5">'. $tag->summary.'</p> </div> <div class="row justify-content-around services">'; // Main services categories that link to the above tags if ($posts->id === $link->pages_id && $tag->id === $link->data){ foreach($posts as $service){ // This pulls in the services categories under the tag header. echo '<div class="card flex-card" id=""> <div class="card-img"> <a href="/'. $service->name.'" title="'. $service->name .'"> <img class="card-img-top" src="../assets/files/'. $service->id.'/'. $service->img_1.'" alt="'. $service->img_1.'" title="'. $service->img_1.'"></a> </div> <div class="card-body"> <h3 class="card-title">'. $service->headline.'</h3> <p class="card-text">'. $service->summary .'</p> <div class="card-action"> <a href="" title="'. $service->name .'" role="link" class="link">View service<span></span></a> </div> </div> </div> '; } } // Grey snippet text echo '</div> </div> </section> <div class="snip-2 light-grey"> <div class="container"> <div class="row text-center">'. $tag->get('grey') .'</div> </div> </div>'; } ?> I appreciate this is a long post but i'm trying to be clear as I appreciate everyone's time.
      Any insight into where I am going wrong is greatly appreciated.
      Liam



×
×
  • Create New...