Jump to content

Removing "Add new" from PageTable field

Recommended Posts

Hi everyone,

after successfully solving the mystery "PageTable", I stumbled upon another one: removing the "add new" button from PageTable (in the template) via hooks.

So, I read about hooks. I never implemented one myself, but tried using the "init" PHP file from the default site, but that didn't work out too well. So again I am a bit stuck in the process. :(

Basically, I check if an array is empty. If it is, the PageTable field on my template shouldn't display the "add new" button. That's about it.

Since PageTable is fairly new, I didn't find too much info about it. Maybe someone of you is able to help me?

Thanks a lot!

Share this post

Link to post
Share on other sites

EDIT: Ignore this idea completely - soma's solution hooking into InputfieldButton::render is obviously a much better idea :)

I don't have time right now to put a working solution together, but you'll want to hook into InputfieldPageTable::render and do an $event->replace = true and then scan the content and strip out the add new button. You could do that with a regex, eg:

function strip_selected_tags_by_id_or_class($array_of_id_or_class, $text) 
   $name = implode('|', $array_of_id_or_class); 
   $regex = '#<(\w+)\s[^>]*(class|id)\s*=\s*[\'"](' . $name . 
   return(preg_replace($regex, '', $text)); 

or perhaps more efficiently with domdocument's removeChild() - eg: http://stackoverflow.com/questions/12903483/remove-a-domnode-with-a-certain-class-in-php

Something like this:

class RemoveAddButton extends WireData implements Module {

    public static function getModuleInfo() {
        return array(
            'title' => 'Conditionally Remove Page Table Add Button',
            'version' => 1,
            'singular' => true,
            'autoload' => true

    public function init() {
        $this->addHookAfter('InputfieldPageTable::render', $this, 'removeButton');

    public function removeButton(HookEvent $event) {
        $event->replace = true;
            $event->return = regex or removechild here to remove button from original $event->return;

Hope that gets you going. Otherwise, I'll put something working together for you tomorrow.

Edited by adrian
Obviously not a good approach to things :)
  • Like 4

Share this post

Link to post
Share on other sites

I've to add a few things here. In your other thread we where talking about denying the page creating and your idea now is hiding the button upfront. Both ways to solve your problem should be not that different to implement, as both need just hooks to work. 

Now, after writing the post, came this to my mind: 
InputfieldPageTable::render is only called on, big surprise, page render. So in your usecase, this wouldn't be great, because the limit of pages in your pagetable has to work even if the user doesn't leave the page. So I still think that my suggestion of using Pages::add would be more useful, even if it's a little bit less userfriendly, because the add button will throw an error, instead of simply disappearing.

An addition to adrians post: You put your hook in the init.php in the template folder? If so, it can't work because this file is only called if your browsing the frontend. You need your hook to work in the backend. While you can use hooks in template files, we don't change the core admin template files. So the best way to get your hook into the backend is via a small module, like the one adrian posted. This example code with the docs about hooks and modules here on processwire.com should get you at least somewhere.
What's missing in the code of adrian, is a condition, when to remove the "add" button. I would limit the check for players / positions to the right template or the right field in the hook and only then do the checkup.

  • Like 3

Share this post

Link to post
Share on other sites

Here's an example module that removes "Add New" button(s) on InputfieldPageTable on a condition (here if there's 2 ore more entries).

Hook before InputfieldPageTable::render, then add hook after InputfieldButton::render. Since InputfieldButton is used by PageTable, we just use that hook to empty the returned markup for the button. Then remove that button hook after the InputfieldPageTable rendered.


  • Like 9

Share this post

Link to post
Share on other sites

Okay guys I am truly overwhelmed by your support. I think this is VERY rare nowadays.

That really encourages me to support PW even more by buying some Pro modules soon. It's really, really good to have a community like this! :lol:

@adrian: Thank you for you effort. After reading your code it gave me a more deeper understanding on where to put the hooks!

@LostKobrakai: Your dedication is stunning. ;) And you're right: the "init" PHP is only executed front-end wise. Thank you for opening my eyes!

Basically, you're right. Adding this hook globally to all pages might seem too much, but Soma does a little check before doing anything:

if($table->name !== "mypagetable") return;

I think the performance hit (if any) is still bearable.

@Soma: Hero Member really suits you. I just copied your source from Git, installed the module and it worked out of the box! :rolleyes:

I cannot mark two posts as "solved", so the "solved" goes also to yours, adrian!

Just a short follow up to working with classes: since I'm outside the normal scope of the "$pages" object, I have to use the global (ugh) "wire('pages')" inside the class instead, am I right?

  • Like 3

Share this post

Link to post
Share on other sites

Obviously a much better approach from Soma! so I definitely don't deserve a "Solved" on this one :)

Of course my original code snippet didn't exclude other fields, but I was thinking something along the lines of checking the name of the field before proceeding - just didn't get that far when posting in a rush yesterday :)

  • Like 1

Share this post

Link to post
Share on other sites

Solved: I used the wrong type of "$page" when trying to access the CURRENT viewed page. The result was always the "admin" template. Which led me to using the $pages->get($_GET[id]) thingy. :)

Share this post

Link to post
Share on other sites

Hello @ all,

I read Somas solution how to remove the add button and I have tried to adapt the code for another condition. Soma uses the number of rows as his condition but I want to use the value of a field instead, but I can get it to work.

In my case I want to use a fieldtype option (select) in the page template to remove the add button or not. If option "1" is selected the button should be removed - if option "2" is selected the button should be still there.

Here is what I have tried:

   public function renderPageTable(HookEvent $event){
         // get the table field
        $table = $event->object;
        $page = $event->arguments[0];
        // make sure this is our field
        if($table->name !== "singleeventtable") return;
        // rendered by InputfieldButton::render
        if($page->eventkindchooser == "1") {
            $this->buttonHook = $this->addHookAfter("InputfieldButton::render", null, function(HookEvent $event){
                // overwrite/remove button markup
                $event->return = '';

Eventkindchooser is the name of the option fieldtype.

Can anyone point me into the right direction?

Share this post

Link to post
Share on other sites
On 8/31/2014 at 3:44 AM, Soma said:

Here's an example module that removes "Add New" button(s) on InputfieldPageTable on a condition (here if there's 2 ore more entries).


Thank you so much for this. It's a fantastic example which I'm using as of yesterday. I particularly appreciate you posting clean code as I find reading code the best way for me to learn how things work.


Do you possibly have any examples of a hook in which I could manipulate more of the admin interface? I'd like to do a couple things:

1. Remove the "settings tab" in the iframe that pops up when editing a PageTable entry. Maybe it's possible to do so with roles and permissions or a technique similar to removing the button.

2. Change the function of the "Add New" button completely - don't create/load the iframe and just create a new PageTable entry programmatically.

If there are hooks to point me at I can figure them out. I've spent time with Captain Hook and but am a bit overwhelmed with the sheer number as well as the fact that I don't know much about how the admin interface is constructed.


Share this post

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

Remove the "settings tab" in the iframe that pops up when editing a PageTable entry. Maybe it's possible to do so with roles and permissions or a technique similar to removing the button.

I found this in the meantime - thanks for this post as well.

I got the this working by turning on $config->advanced = true; in config.php which allows hiding the settings tab on a per-template basis! Nice.

It seems that the code in the thread turns off the general ProcessWire menus as well:

Before and after shots attached.

Screenshot from 2017-04-23 08-57-52.png

Screenshot from 2017-04-23 08-59-39.png

I'm working on 2) now.


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 Guy Incognito
      I've created a simple sports league fixture generator in a template called 'League'. Teams are added as page references then a fixture list is created as a ProFields table by hooking page save to add new rows to the table.
      The bit I need help with is that I'm trying to check a fixture doesn't already exist before adding it to the table (e.g. if a new team is added to the league). I'm trying to do this with a PW selector to filter the fixtures table and check whether Team A vs Team B already exists in the table. Then on the next line checking no fixture was found by using count().
      However as soon as I add the selector the script no longer adds any rows to the table. If I take it out, it all works fine (albeit with duplicate fixtures each time the page is saved). I've also tested the selector in a page template and it filters as expected. It's late here (UK)... I'm probably doing something stupid! Any ideas?
      <?php //Hook page save to generate league fixture lists $wire->addHookAfter("Pages::saved(template=league)", function ($event) { //Get which page has been saved $page = $event->arguments(0); $noFixturesAdded = 0; //For each team in league cycle through and add home fixtures foreach ($page->teams_in_league as $teamA) { foreach ($page->teams_in_league as $teamB) { //Check if fixture already exists $existingFixtures = $page->fixtures("team_a=$teamA,team_b=$teamB"); //Check team A is not the same as team B as you can't play yourself //Then add row to fixture table if ($teamB != $teamA && $existingFixtures->count() < 1 ) { $fixture = $page->fixtures->makeBlankItem(); $fixture->team_a = $teamA->id; $fixture->team_b = $teamB->id; $page->fixtures->add($fixture); $noFixturesAdded ++; } } } //Save updates to table $page->save('fixtures'); $message = "League saved. $noFixturesAdded new fixtures were added"; $this->message($message); });  
    • By Macaco
      It's a bilingual site. There are two pages: "Artists" and "Events" each with a "Page Reference" field connecting each other.
      - Artists has a field where one can choose events available.
      - Events has a field where you can either choose artists available or create new ones.
      The problems: 
      - When I create an "Artist" page and select events from the list, it doesn't update the collection of participating artists on the "Event" page.
      - When I create an artist from the "Event" page. The field 'artist page > settings > language' is not "Active" for the second language.  When the artist page is created manually,"Active" is on by default.
      I know this all have to do with hooks, but I'm don't fully understand the logics.
    • By DooM
      I'm working on something like "structure generator" for my own needs which is run after clean installation of PW to create basic structure, fields, install modules, remove unnecessities, etc.
      I'm trying to remove site/templates/scripts and site/templates/styles folders, but I'm out of ideas already. When I try PHP's unlink function, it says that the path doesn't exists, which is obvious, because it will try to delete those folders under FileCompiler folder. This is probably because PW compilation process? I'm initializing this mine "structure generator" in ready.php.
      Do any of you guys have any idea how to get rid of those folders? My styles and scripts folders are separated, so I don't need those two inside templates folder.
      Thanks for every advice. 🙂
    • By VeiJari
      Hello forum! 
      I started to write my first hook for Processwire but I'm pretty confused how you should write these. My idea is to hook after publishing in init.php (called before templates)  for a certain template. 
      Here's the code: 

      Trying to reset the checkbox (ajasta) and then saving it so it shows unchecked in the admin page when publishing "article" page. 
      But the code isn't doing anything. Not even dumping anything
      What seems to be the problem? And have you made a similar hook for this usage or am I doing it totally wrong? 😄
      Thanks for the support in advance!
    • By celfred
      I am getting nuts trying to understand hooks and I hope someone in the community will be able to help. This is deiving me crazy ! I have tested tens of possibilities to eventually reduce my code to this :
        bd('outside');   $wire->addHookAfter('Page::render', function($event) {     bd('inside');   }); And if someone could tell me why my bd('inside'); never triggers... I would be infinitely grateful !
      EDIT : Forgot to say : this piece of code is in my _init.php included in my template (but I've also tried in my site/ready.php for no better results...)
  • Create New...