Jump to content

database table versus pages


Recommended Posts

Still a newbie to both processwire and php.......just checking that my thinking is long the right track

I want to set up a heirachical site with the following structure

Categories (6) > Subcategories (3 per parent) > Sub-subcategories(2-10 per parent) >Items (1-10 per parent).


References to the various levels of the heirachy will need to be available to other pages on the site.

I get the idea of doing it in pages with relational page fields, nicely explained in Tutorial: Approaches to categorising site content . It looks as though it is also possible to add  tables directly to the database (or even another database).

It's delightfully easy to use a template to display the data on each page any way you want. It seems there are two ways to access the data.

  1. With the data as pages, I could use a selector to query the database.e.g     
    $items = $pages->find("template=mytemplate"); //or any other selector
  2.  With custom database tables, I could query the database directly e.g. 
    $result = $this->db->query("SELECT id, name, title, url FROM yourtablename WHERE id=$id");

Is there anything I should know about the pro's and con's of either method before I build the site. The data already exists, but I'll be scraping a website to get it, so it will be added to my site under program control. I'm not sure whether my program should create processwire pages, or just create some database tables. Actually now that I think about it, both are possible,  table first, then pages created from a table.

I'd really appreciate any comments before I unknowingly head off down the wrong track. 

Link to comment
Share on other sites

Hi Wilsea,

It really depends on how you want to use and present your data at the end of the day + how much data we are talking... A search of the forums will tell you that most people would choose pages over custom tables. Why? For one, you get access to the powerful PW API. Of course, behind the scenes, it is all db tables, but PW takes care of that. There is (almost) a selector for any query you would want to make....If this is not the case, you can also query PW tables using normal MySQL queries. 

If you want to present your data at unique URLs, then pages is the way to go.... 

How many tables are we talking? You have probably noticed that PW is insanely fast. Ryan has done a tremendous job in optimizing selectors. With power comes responsibility; so, limit=xx is a good friend when using "find"....

Relational db/References...pages is the way to go...Page Reference Fields in PW make this very easy!!

If you went the pages route, you can also harness the extended power of templates, e.g. using templates to control page access...

For some people, having thousands of pages in the pages tree is not desirable. However, depending on how you structure your site, this may not be a problem. If it is a problem, then you might want to think of custom tables....although, there are ways around displaying your pages in a grid (as in a table) in the backend rather than the tree..Btw, I reckon you are talking about a local db table? (i.e. not external to your domain..). 

Easy-on-the-eyes...PW API is beautiful and easy to read....even though MySQL-like code is easy enough to read as well...

Bottom line is this: If you really don't have to, do not reinvent the wheel. PW already gives you an easy, consistent and powerful way to query your data....using the API..

It is late and I am not thinking straight. I could have missed something. Others will chip in. Also use Google to search the forums (e.g. custom tables...). You might also find it useful to read the various threads detailing how some folks here imported data from other platforms/websites into PW....There are also bulk editing modules such as CSV Import module...

Hope my comments give you a little idea how you might proceed...

Edited: for clarity + additions...

Edited by kongondo
  • Like 7
Link to comment
Share on other sites

Depending on your data structure, you might also consider this approach:


This example module shows you how to build a custom PW fieldtype that allows you to have the power of PW API while still storing the data in a more traditional way - multiple fields per DB row.

Again, the best option depends on lots of different things, but kongondo has outlined these very well already.

  • Like 3
Link to comment
Share on other sites

Kongodo summed it up well.

I would suggest gathering your data from the outside world into conventional database table(s) outside of PW. Set them up so they are easy for you to fill and check over. Then write a module based on Ryan Cramer's module for importing from CSV files. Make it read from your table(s) instead of a file. You can put all your code for massaging the content right in the module. With liberal use of the UI modules have for settings you can use the same tool to make various kinds of pages from input data.

Working with an external database can be pretty simple:  
    protected function externalDbConnect(){  
        $this->extDb = new mysqli('localhost', 'xxxx', 'yyyy', 'zzzz');
    protected function queryCount($qry){
        $result = $this->extDb->query($qry);
        return $result->num_rows;
    protected function queryForFields($table){
        $a = array();
        $result = $this->extDb->query('SHOW COLUMNS FROM '.$table);
        while($row = $result->fetch_array(MYSQLI_ASSOC)) $a[] = $row['Field'];
        return $a;

  • Like 4
Link to comment
Share on other sites

Thankyou both for the blazingly fast replies. A big help in clarifying my thinking.

I hadn't thought about URL's, obviously a big point in favour of pages, which got me thinking about url's verus ajax, and bookmarking/back button issues.

Those event field types look really interesting.  I'm really intrigued by how much can be done with a small amount of code in a module! Heady stuff if I can only get my head around it all. I see a table with the data is added to the database, with multiple columns instead of the usual two column field tables.  I guess once the table is created I could add records to it using regular php.  I'm also guessing that I could customise it by changing the fields in the __construct()  array of Event.php,  (Sorry if I'm stating the obvious - I'm still wobbling around on trainer wheels. Just checking to see I'm on the right path).


If I was using a regular mySQL database there would be about 5 or 6  tables, most of them very small. The biggest one will have about 2000 records. The data is static - no CRUD at all once it's in place, but other pages on the site will reference to it, and the data will need to be easily browsed and displayed by various search configurations.

Still mulling over the options over the best way to go.

Thanks very much for the suggestions. They've given me a lot to think about.

Link to comment
Share on other sites

Yep, you can definitely customize the fields from the events example. That module, although useful in its own right, was meant as an example to be modified to your needs.

Let us know if you have more questions once you dive in!

Link to comment
Share on other sites

I'd probably still do it as pages to be honest, just because it's easier and we're not talking about a lot if data by the sound if it.

Any chance you can post the database structure? That would give us a better idea as to which way might be the more appropriate route

Link to comment
Share on other sites

Thanks Pete, delighted to post the database structure. Basically it's a simple 5 level heirachy, one to many down through each level. 

Level 1 - Subject - 6 records (name only)

Level 2 - Sub-subject - 18 records (name only)

Level 3 - strand -  40 records (name only)(3rd letter of topic_code)

Level 4 - topic - 1000 records (4 fields + id) (4th and 5th letters of topic_code)

Level 5 - details - 3000 records (2 fields + id)

Subject and sub_subject probably don't need to be in the database, as they are pretty small and consist of only a name field. Fortunately the topics table has a topic_code field which can be parsed to get information about the subject and sub_subject. The topic_code is a unique field about 98% of the time.    topic_code plus topic_level is always unique.


Id fields at the top level of each table are auto-increment numbers.

Likely searches and groupings will be on subject, sub_subject, strand and topic_level (there are only 10 topic_levels). Page fields for each of these.will be handy for the rest of the site.  It's highly unlikely that the details table will ever need to be searched directly, but the topics table will often have records retrieved by the topic_code.

 I rather like the idea of a custom table field like the FiletypeEvents for the topics table, but I'm not sure how to go about setting up the relationship between the topics table and the details table. I haven't figured out what is doing the actual save in the Fieldtype Events. table. It seems to be a submit post to itself, but I can't find any actual save type code any where, and I'm not sure where to look.

Thanks for following this post. Great forum! :)

Link to comment
Share on other sites

Thanks so much for all the suggestions people. I ended up opting for pages built from four tables, and that seems to everything I want and more.

For the benefit of any future readers.....

While it's probably self-evident, a separate template for each table made the whole process easier to manage.Tables imported like a dream with the import Pages from CSV module. What was even dreamier was correcting a few mistakes or three (having too much fun with  PW to catch up on some sleep) with the ability to do bulk trash/change templates operations with the Batcher module. I found out the comma delimiter is a bad idea if your field already has commas in it (duh). Delete mangled pages, reimport as tab delimited, problem solved.

Linking the tables/pages up inside PW was a joy instead of a nightmare. There's probably better/other ways, but I just coded the templates to provide the functionality (mostly navigation and display) that I needed. I'm wrapt and can't wait to push the envelope further.  

Who'd of thought  Christmas would come round again so quickly. :D 

  • Like 6
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

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Similar Content

    • By jds43
      Hello, I'm trying to list the categories, on the front through select options, that have been selected by page reference field (multiple pages PageArray) on the child pages.
      Things to Do (would only display three, six, seven, nine in select)
      -thing one (-category three, -category nine)
      -thing two (-category six, -category seven)

      Lodging (would only display one, two, three, four in select)
      -lodging one (-category one, -category two)
      -lodging two (-category three, -category four)

      Dining (would only display five, six, seven, eight in select)
      -dining one (-category five, -category six)
      -dining two (-category seven, -category eight)
      Categories(hidden page)
      -category one
      -category two
      -category there
      -category four
      -category five
      -category six
      -category seven
      -category eight
      -category nine
      -category ten
      $categories = $pages->find(1129)->children('include=hidden'); foreach($categories->references('category') as $ref) { echo $ref->title; } This selector isn't working, but it seems 'references' would be helpful. I've never used it before, so I'm not sure how to employ for this.
    • By stanoliver
      Good morning everyone!
      I have a growing number of posts about cars, bikes, airplanes, etc. 
      The following code (below) just works fine and returns only the posts of the category=cars as I desired together with pagination.
      In my url I have for example /categories/cars/car1 or /categories/bikes/bike1
      I do want to filter my posts not only with ... category=cars ... but also with category=bikes or category=airplanes and at best:
      If my url is /categories/bikes/ then ... category=cars ... should be overwritten or replaced by ... category=bikes ... 
      If my url is /categories/airplanes/ ... then the filter should be ... category=airplanes ... (I know a work around by creating almost identical templates where I could just change the "category=cars" part of my code but that's comes of a prize by repeating a lot of identical code and is not a good habit). In the documentation I read something about the "has_parent" selector but I could not get to work it related to the urls mentioned above.
      <?php foreach ( $results = $pages->find('id>1, template=templateblogpost, category=cars, limit=5, sort=-postdate') as $post 😞?> <!-- Blog entry --> <div class="g8-card-4 g8-margin g8-white"> <!--<img src="/g8images/bridge.jpg" alt="Norway" style="width:100%">--> <div class="g8-container"> <h3><b><?= $post->title; ?></b></h3> <h5>Datum: <span class="g8-opacity"><?= $post->postdate; ?></span></h5> </div>   <div class="g8-container"> <p><?= $post->posteditor; ?></p> <div class="g8-row"> <div class="g8-col m8 s12"> <p> <a href="<?= $post->url; ?>"><button class="g8-button g8-padding-large g8-white g8-border"><b>Details lesen &raquo;</b></button></a> </p> </div> <div class="g8-col m4 g8-hide-small"> <!--<p><span class="g8-padding-large g8-right"><b>Comments &nbsp;</b> <span class="g8-badge">2</span></span></p>--> </div> </div> </div> </div> <!-- END BLOG ENTRIES --> <?php endforeach; ?>   <? echo $results->renderPager(array( 'nextItemLabel' => "rückwärts", 'previousItemLabel' => "vorwärts")); ?>
    • By adrian_gp
      Hello everyone,
      I'm new in this forum and my english is not perfect so sorry for the mistakes.
      I have an Blog Project and i will use categories. 
      Here is the structure:
      Blog -> displays all the Blogposts (template=BlogPage) Post-Name -> display the specific Post (template=BlogPost) Categories -> not visible in the menu (template=CategoriesPage) Categorie-Name -> not visible in the menu (template=CategoriePage) For your information:
      (BlogPost) every blogpost has its own page (BlogPost) in Admin i can select the categorie per Field -> SelectMultiple Pages (Checkbox) (fieldname=categories) (Blog) displays all the BlogPosts and all the categories under the ParentTemplate CategoriesPage, which also have their own side Now the Problem:
      On Blog -> I would like to click on a category and only see the post that has this category checked in the BlogPost.
      CategoriePage -> what do I have to insert there to show only the specific posts which use the checked categorie?

      Let me know if you need more information

      Thanks for your support
    • By zaib
      I've a page "blog" which have child pages (blog posts). Right now I've 11 pages (blog posts) and I'm fetching all the posts in my "blog" pages which displaying fine, Issue is only 10 results are showing this is how I'm fetching
      $entries = $pages->find("template=blog-entry"); foreach($entries as $entry){ <a href='{$entry->url}'>$entry->title</a> }  
  • Create New...