Jump to content
FrancisChung

Copying pages or content from one Processwire instance to another

Recommended Posts

Hi there,

I was wondering if there's a module that allows me to copy certain pages or content from one instance of Processwire to another instance?

Unfortunately, I can't copy a whole instance across as there needs to be some major cleanup job performed and it won't get done in time.

Otherwise, if anyone has any code samples that would be much appreciated.

Share this post


Link to post
Share on other sites

@FrancisChung - I am going to be offline for about a month, but please let me know how Migrator works out for you. I use it a lot in my development process for migrating new branches of content from dev to live, but I do know that there are still some issues that need to be sorted out. As I mentioned in the Migrator support thread, it's definitely not abandoned, I just need to find a good chunk of time to address some bugs.

I would definitely recommend testing the migration from one dev site to another dev site first and if that goes as expected it should be safe to migrate to a live site. Also be sure to use the the inbuilt backup option just in case.

Hopefully sometime in the new year this module will get some more love.

  • Like 2

Share this post


Link to post
Share on other sites

Thanks for the feedback Adrian. 

I've had some mixed results with the Migrator. It worked for some of our content but it didn't seem to work for Blog Articles i was trying to export.

But I've realised the Blog are complex objects that have a lot of dependencies and I may have not specified them correctly.

The Blog articles i'm using are part of the ProcessBlog module.

All in all it's been positive overall and I think it's probably best for me to stick to simple pages or objects when it comes to the Migrator.

I look forward to the bug fixes and I hope it gets the love and attention it deserves.

  • Like 1

Share this post


Link to post
Share on other sites

Hi, I was wondering if there's an alternative ways of doing this other than using Migrator?

Has there been a new module out that allows this? 
Or is it possible via API to get pages from one site, programatically go through each fields and create + save down to a new page on another site?

Share this post


Link to post
Share on other sites

i had this problem some days ago and wrote a simple script on both websites. both online on different domains:

export on old website:

<?php 
$export = false;
if($export AND $input->get->export == 'blogitems') {
    echo "<?xml version='1.0' ?>";
    echo '<pages>';

    $parent = $pages->get('/blog');
    $results = $parent->children();
    //$results = $pages->find('id=3198'); // ohne pic
    //$results = $pages->find('id=3204'); // mit pic

    foreach($results as $p):
        $p->of(false);
        ?>
        <page>
            <title><?= $p->title ?></title>
            <date><?= $p->blog_date ?: $p->created ?></date>
            <featured>1</featured>
            <pic><?= $p->main_slider_coverpic->first()->httpUrl ?: '' ?></pic>
            <body><?= $p->body ?></body>
            <images><?php foreach($p->images as $image) {
                echo '<image>' . $image->httpUrl . '</image>';
            } ?></images>
            <files><?php foreach($p->files as $file) {
                echo '<file>' . $file->httpUrl . '</file>';
            } ?></files>
            <gallery><?php foreach($p->gallery as $image) {
                echo '<image>' . $image->httpUrl . '</image>';
            } ?></gallery>
        </page>
    <?php endforeach;
    echo '</pages>';
    die();
}

and then the import:

<?php
$import = false;
if($import AND $input->get->import == 'blogitems') {
    $items = simplexml_load_file('https://www.your-old-website.com/?export=blogitems');

    foreach($items as $page) {
        $p = new Page();
        $p->template = 'blogitem';
        $p->parent = '/news';

        $p->title = $page->title;
        $p->name = $sanitizer->pageNameUTF8($page->title, true);
        while($pages->find('parent='.$p->parent.',name='.$p->name)->count() > 0) $p->name .= '-1';

        $p->date = $page->date;
        $p->featured = $page->featured;

        // get body html and remove root node
        // $p->body = substr($page->body->asXML(), 6, -7);
		// ###### update: it's better to use base64_encode($page->body) in your export and then base64_decode($page->body) in your import #####

        $p->save();

        // add images
        if(strlen($page->pic)) $p->pic->add((string)$page->pic);
        foreach($page->images->image as $image) $p->images->add((string)$image);
        foreach($page->files->file as $file) $p->files->add((string)$file);
        foreach($page->gallery->image as $image) $p->gallery->add((string)$image);

        $p->save();
        echo 'new page <a href="' . $p->editUrl . '" target="_blank">' . $p->path . '</a><br>';
    }
    die();
}

of course that is not bulletproof but it's really simple and you can do whatever you want (export junks by adding start=0, limit=10 or the like to your selector)

you can also try adrians batch child editor. or csv importer. but for me the example above worked like a charm :)

ps: try it with limit=1 for testing ;)

  • Like 6

Share this post


Link to post
Share on other sites

Bernhard, thanks for the quick response and the code! Sehr Danke!

I'll repurpose it for my situation and let you know how I went.

 

If I have time, perhaps I could even try and make a more general purpose module that syncs between 2 instances.

  • Like 1

Share this post


Link to post
Share on other sites

a module would be cool. but i think it will be difficult to handle all situations... the freedom of processwire will make it difficult to find some common standard in all installations / setups... i guess it will almost always be faster to use some simple unique script like mine above but i'm happy if you prove me wrong ;)

good luck with your import!

Share this post


Link to post
Share on other sites

I agree with you on the difficulty in trying to create something that will handle all scenarios.  Always quicker to build something simple and custom fit.

I think the difficulty lies in how to identify and deal with complex and compound data types, whether it is built by the user or introduced by module(s) the site is using. Is it straight forward to access those types using the API, for example? (I assume Yes but you never know)

 Also, if there are any new types introduced to PW Ecosystem, then it will have to retrospectively be able to handle it so you'll always be catching up.

Probably the correct way to write something generic is to use Reflection and infer capabiltiies and attributes of your target objects, ala how PW does with its API documentation (Btw, how cool is that? Self documenting APIs! Sehr Guile!)

 https://processwire.com/blog/posts/processwire-3.x-api-reference/ . 

  • Like 2

Share this post


Link to post
Share on other sites

i think what COULD make sense is some kind of helper module that makes it easy to handle some more advanced features (sometimes necessities) like deviding the import in chunks or providing some helper functions like handling pagename collisions, importing images and so on.

but i don't know if there are better solutions already providing such things like using lister pro or batch child editor, import csv and so on. for me it was just the quickest solution to code it on my own. i had only 168 pages in the blog and 165 persons to import and that went without even increasing execution time :) 

  • Like 1

Share this post


Link to post
Share on other sites

I certainly agree with your Helper Module sentiments.

I would actually go one step further and say a framework built on the PW API would be awesome as I sometimes find myself spending a lot of time trying to get certain tasks done, something a Framework could have easily mitigated.

I tried to incorporate your code and I got it working for most part.
I have a problem where I'm trying to populate a TextArea field from the XML file.

$p->content = $xml->content;

No errors but no data populated either. 
I'm guessing I may have to do some sort of casting or conversion?

Has anyone got any experience or ideas on this?

Share this post


Link to post
Share on other sites

i would recommend using @adrian s awesome tracy console:

$items = simplexml_load_file('https://www.your-old-website.com/?export=blogitems');
foreach($items as $page) d($page->yourxmlnode->whatsoever);

on the other site you can easily see what's happening like this:

$p = $pages->get(2427); // your-test-page-id
$p->of(false);
$p->eventcancelled = 'your_console_output_from_other_site';
d($p->eventcancelled);

as this field is a checkbox it would modify the '<p>test</p>' to 1 and you would know on which side the problem exists:

2016-09-07 13_41_23-Program Manager.png

but still i have to add that i have no experience with more complex import/export scenarios. for example multilanguage. maybe that's already possible with the other solutions :)

  • Like 1

Share this post


Link to post
Share on other sites
<content>
    <p>Liebe Sonne komm gekrochen,</p>
    <p>denn mich friert` s an meine Knochen.</p>
    <p>Liebe Sonne, komm gerennt,</p>
    <p>denn mich friert` s an meine Händ.</p>
</content>

This is the content field I'm trying to update as currently represented in the XML file

Share this post


Link to post
Share on other sites

2016-09-07 13_59_38-Edit Page_ Demo-Event • mustangs.do2.baumrock.com.png

PS: see how i did it this with my body field

        // get body html and remove root node
        $p->body = substr($page->body->asXML(), 6, -7);

PPS: i had problems with the umlaut complaining about UTF8 but i had this problem on another spot and think that might be a problem with my setup and not related to this topic or tracy...

Share this post


Link to post
Share on other sites
58 minutes ago, FrancisChung said:

I would actually go one step further and say a framework built on the PW API would be awesome as I sometimes find myself spending a lot of time trying to get certain tasks done, something a Framework could have easily mitigated.

I'm curious what you think a framework could migrate, that processwire can't.

  • Like 1

Share this post


Link to post
Share on other sites
5 hours ago, LostKobrakai said:

I'm curious what you think a framework could migrate, that processwire can't.

It's not so much migrate or migration but just building upon what the processwire API provides. I really do appreciate the "freedom" the API provides, but I also sometimes wished there was some structure or guidance to follow (i.e. a Framework). You'll have to excuse me coming from a .NET background and still struggling with a lot of PHP's idiosyncrasies and gotchas.

I'm not saying a Framework is useful for every scenarios, but for some scenarios it would be much quicker to get a site going if we could leverage reusable, tested components ala a Framework. I'm sure there are plenty here that have built their own framework(s) over the years. Would be nice to see an official or a collaborated effort.

  • Like 2

Share this post


Link to post
Share on other sites

I thought I should post my implementation based on Bernhard's code.

It tries to work out the length of the first tag and modifies the ->asXML parameters accordingly.


The Import Code is as follows :

class ImportFromXML
{

    private $file;

    public function __construct($file)
    {
        $this->file = $file;
    }

    public function Execute()
    {
        $import = true;
        $xmlFile = $this->file;
        if ($import) {
            if (!file_exists($xmlFile))
                exit($xmlFile . ' failed to open');

            $items = simplexml_load_file($xmlFile);

            foreach ($items as $xml) {
                $p = new \Processwire\Page();
                //$p = new \Page();

                $p->of(false);

                $p->template = wire(templates)->get("id=" . $xml->template);
                $p->parent = wire(pages)->get("id=" . $xml->parent);
                $p->title = $xml->title;
                //Struggle to call Sanitizer  $p->name = wire(sanitizer)->pageNameUTF8($xml->title, true);
                $p->name = $xml->title;
                //while ($xmls->find('parent=' . $p->parent . ',name=' . $p->name)->count() > 0) $p->name .= '-1';

                //$p->content = $this->PopulateContent($xml->content);
                $p->content = $this->PopulateMarkup($xml->content);
                //$p->content_intro = $this->PopulateIntro($xml->content_intro);
                $p->content_intro = $this->PopulateMarkup($xml->content_intro);
                $p->author = $xml->author;
                $p->content_path = $xml->content_path;
                $p->seo_title = $xml->seo_title;
                $p->seo_keywords = $xml->seo_keywords;
                $p->seo_description = $xml->seo_description;
                $p->seo_image = $xml->seo_image;
                $p->seo_custom = $xml->seo_custom;
                $p->image = $xml->seo_custom;
                $p->image_alt = $xml->image_alt;
                $p->keywords = $xml->keywords;
                $p->title_nav = $xml->title_nav;
                $p->seo_section_title = $xml->seo_section_title;

                //$p->save();

                // try creating PageArray first ????
                //$cats = new \PageArray();
                $cats = new \Processwire\PageArray();

                foreach ($xml->category->id as $id) {

                    //$cat = wire(pages)->get("name='" . $catname . "', parent='/Categories/'");

                    $pageid = (string) $id;
                    $cat = wire(pages)->get($pageid);

                    if (!IsNullPage($cat))
                        $cats->add($cat);
                        //$p->categories->add($cat);-
                }

                $p->category->import($cats);


                $p->save();
                echo 'new page <a href="' . $p->editUrl . '" target="_blank">' . $p->path . '</a><br>';
            }
            //die();
        }
    }


    private function PopulateMarkup($node)
    {
        $xml = $node->asXML();

        //Check for tags
        if($xml != strip_tags($xml)) {
            //$startTag  = strpos($node,"<");
            $endTag = strpos($xml,">");

            if ($endTag > 0)
                return substr($xml, $endTag+1, -1*($endTag+2));
        }

        return $node;
    }
}

 

And the Export :

 

class ExportToXML  {

    private $pages ;
    
    public function __construct($pages)
    {
        $this->pages=$pages;
    }

    public function Execute()
    {
        $import = true;
        if($import) {

            echo "<?xml version='1.0' ?>";
            echo '<pages>';

            //$parent = $pages->get('/blog');
            $results = $this->pages;
            //$results = $pages->find('id=3198'); // ohne pic
            //$results = $pages->find('id=3204'); // mit pic

            foreach($results as $p):
                $p->of(false);
                ?>
                <page>
                    <name><?= $p->name ?></name>
                    <title><?= $p->title ?></title>
                    <template><?= $p->template->id ?></template>
                    <parent><?= $p->parent ?></parent>
                    <category><?php foreach($p->category as $category) {
                            echo '<id>' . $category->id . '</id>';
                        } ?></category>
                    <content><?= $p->content ?></content>
                    <content_intro><?= $p->content_intro ?></content_intro>
                    <author><?= $p->author ?></author>
                    <content_path><?= $p->content_path ?></content_path>
                    <seo_title><?= $p->seo_title ?></seo_title>
                    <seo_keywords><?= $p->seo_keywords ?></seo_keywords>
                    <seo_description><?= $p->seo_description ?></seo_description>
                    <seo_image><?= $p->seo_image ?></seo_image>
                    <seo_custom><?= $p->seo_custom ?></seo_custom>
                    <seo_canonical><?= $p->seo_canonical ?></seo_canonical>
                    <image><?= $p->image ?></image>
                    <image_alt><?= $p->image_alt ?></image_alt>
                    <keywords><?= $p->keywords ?></keywords>
                    <title_nav><?= $p->title_nav ?></title_nav>
                    <seo_section_title><?= $p->seo_section_title ?></seo_section_title>
                </page>
            <?php endforeach;
            echo '</pages>';
            //die();
            /**
             *  <date><?= $p->created ?></date>
                <featured>1</featured> */
            }
        }
}

 

In particular, I had a field that was a PageArray linking to other Pages.

 

                    <category><?php foreach($p->category as $category) {
                            echo '<id>' . $category->id . '</id>';
                        } ?></category>

 

Hope it helps some one out!

  • Like 4

Share this post


Link to post
Share on other sites

just because i needed this again today:

if you are dealing with any sort of tags (HTML data) in your fields, than the easiest solution is to base64_encode($var) your data in the export and then base64_decode($var) it in your import.

i had to import some pages with inline images today and if you know how to do it, that is also quite easy and straigtforward. the problem is, that you have some html like img src="/site/assets/files/12345/your-image.jpg" in your field and the ID will change after the import!

sample export xml - note the tag <pid> holding the old id

echo "<?xml version='1.0' ?>";
echo '<pages>';

// find pages
$results = $pages->find('parent=/your-parent/');
$results->add($pages->find('parent=/something-else/'));

foreach($results as $p):
    $p->of(false);
    ?>
    <page>
        <title><?= $p->get('headline|title') ?></title>
        <date><?= $p->created ?></date>
        <featured>1</featured>
        <pid><?= $p->id ?></pid>
        <pic><?= $p->coverpic->first()->httpUrl ?: '' ?></pic>
        <body><?= base64_encode($p->body) ?></body>
        <images><?php foreach($p->images as $image) {
            echo '<image>' . $image->httpUrl . '</image>';
        } ?></images>
        <files><?php foreach($p->attachments as $file) {
            echo '<file>' . $file->httpUrl . '</file>';
        } ?></files>
        <gallery><?php foreach($p->gallery as $image) {
            echo '<image>' . $image->httpUrl . '</image>';
        } ?></gallery>
    </page>
<?php endforeach;
echo '</pages>';
die();

and then the import:

$items = simplexml_load_file('your-url-of-export-data');

foreach($items as $page) {
    $p = new Page();
    $p->template = 'blogitem';
    $p->parent = '/news';

    $p->title = $page->title;
    $p->name = $sanitizer->pageName($page->title, true);
    while($pages->find('parent='.$p->parent.',name='.$p->name)->count() > 0) $p->name .= '-';

    $p->date = $page->date;
    $p->featured = $page->featured;

    // get body html and remove root node
    $p->body = base64_decode($page->body);
    $p->save();

    // change images in body field
    $re = '/src="\/site\/assets\/files\/' . $page->pid . '\//';
    $p->body = preg_replace($re, 'src="/site/assets/files/' . $p->id . '/', $p->body);
    $p->save();

    // add images
    if(strlen($page->pic)) $p->pic->add((string)$page->pic);
    foreach($page->images->image as $image) $p->images->add((string)$image);
    foreach($page->files->file as $file) $p->files->add((string)$file);
    foreach($page->gallery->image as $image) $p->gallery->add((string)$image);

    $p->save();
    echo 'new page <a href="' . $p->editUrl . '" target="_blank">' . $p->path . '</a><br>';
}
die();

just set your ckeditor field settings porperly before your import and all images will be recreated on your new site! :)

2016-11-01 22_00_57-Edit Field_ body • svt.dev.png

remark: this will only replace images from the same page and not any images that are linked from a different page with different page-id. that would need some extra mapping of old-id --> new-id

  • Like 6

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 gebeer
      Hello all,
      wasn't sure where to put this, so it goes in General section.
      Ryan shows a hook that we can use to mirror files on demand from live server to development environment to be up to date with the files on the server without having to download complete site/assets/files folder.
      I just implemented this but had problems getting files to load from a site in development that is secured with user/password via htaccess.
      First I tried to use WireHttp setHeader method for basic authentication like this
      function mirrorFilesfromLiveServer(HookEvent $event) { $config = $event->wire('config'); $file = $event->return; if ($event->method == 'url') { // convert url to disk path $file = $config->paths->root . substr($file, strlen($config->urls->root)); } if (!file_exists($file)) { // download file from source if it doesn't exist here $src = 'http://mydomain.com/site/assets/files/'; $url = str_replace($config->paths->files, $src, $file); $http = new WireHttp(); // basic authentication $u = 'myuser'; $pw = 'mypassword'; $http->setHeader('Authorization: Basic', base64_encode("$u:$pw")); $http->download($url, $file); } } But, unfortunately this didn't work.
      So now I am using curl to do the download. My hook function now looks like this
      function mirrorFilesfromLiveServer(HookEvent $event) { $config = $event->wire('config'); $file = $event->return; if ($event->method == 'url') { // convert url to disk path $file = $config->paths->root . substr($file, strlen($config->urls->root)); } if (!file_exists($file)) { // download file from source if it doesn't exist here $src = 'http://mydomain.com/site/assets/files/'; $fp = fopen($file, 'w+'); // init file pointer $url = str_replace($config->paths->files, $src, $file); $u = 'myuser'; $pw = 'mypassword'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_TIMEOUT, 50); // crazy high timeout just in case there are very large files curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERPWD, "$u:$pw"); // authentication curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); // authentication curl_setopt($ch, CURLOPT_FILE, $fp); // give curl the file pointer so that it can write to it curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $data = curl_exec($ch); curl_close($ch); } } Now I can load files and images from the htaccess protected development server 🙂
      If anyone knows how to get this to work with WireHttp, please let me know. Thank you.
    • 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 DooM
      Hello guys,
      I'm trying to figure out how to sync fields and templates between staging and production environments.
      I've found Migrations module by Lostkobrakai, but with use of it all the fields and templates must be created by API, which is kind of uncomfortable.
      I also tried ProcessDatabaseBackups module which can export only certain tables, but I don't think it's the best practice to do that.
      How do you guys solve this problem? It's very annoying to setup everything three times (dev, staging, production).
      Thanks a lot :)
×
×
  • Create New...