Jump to content
novalex

Adding a custom tab on page edit screen

Recommended Posts

Hi,

New to PW, please forgive my ignorance if this has been answered before, I have scoured the docs and forums but couldn't find anything.

I'm trying to add a custom tab to the Page Edit screen (or process), which will contain fields for a page hero. Ideally, I would have a "Hero" tab before "Content", which would contain fields for images, text, a CTA button, etc. What I have so far is this:

class HeroTab extends WireData implements Module {

	public static function getModuleInfo() {
		return array(
			'title'    => 'Page Hero',
			'version'  => 1,
			'summary'  => 'Header fields for pages.',
			'singular' => true,
			'autoload' => true,
		);
	}

	public function ready() {
		if(wire('page')->process != 'ProcessPageEdit') return;

		$this->addHookAfter('ProcessPageEdit::buildForm', $this, 'addTab');
	}

	public function addTab(HookEvent $event) {
		$form = $event->return;

		// create the tab
		$hero = new InputfieldWrapper();
		$hero->attr('id+name', $this->className() . 'hero');
		$hero->attr('title', $this->_('Hero'));

		// Images
		$fimages = $this->modules->get("InputfieldImage");
		$fimages->attr('id+name', 'hero_images');
		$fimages->label = $this->_('Images');
		$fimages->extensions = 'gif jpg jpeg png svg';
		$hero->append($fimages);

		// Text
		$ftext = $this->modules->get("InputfieldCKEditor");
		$ftext->attr('id+name', 'hero_text');
		$ftext->label = $this->_('Text');
		$hero->append($ftext);

		$form->prepend($hero);
	}
}

This adds the tab and the fields, but after the "View" tab. However, the bigger problem is that the fields do not save. When I click Save, the page refreshes, with the "Saved Page" notice, but the fields are empty.

I got inspiration from https://github.com/adrianbj/ProcessRedirectIds/blob/master/ProcessRedirectIds.module, but I think it is for the older 2.x version because it originally used $form->append which put the bottom save button between the tabs and tab content.

Any help would be appreciated, I am thoroughly lost and the documentation doesn't give any examples for what I'm trying to do.

Cheers

Screenshot from 2017-05-08 18:21:34.jpeg

Share this post


Link to post
Share on other sites

Hi and Welcome to the forums,

Maybe this one helps:

 

  • Like 1

Share this post


Link to post
Share on other sites

Thank you for the prompt reply!

I followed the instructions there and got the tab in the position I wanted. The fields are still not saving though, I'm really scratching my head now.

Share this post


Link to post
Share on other sites

Can't you just make a regular fieldset tab and put them in there, i have sometimes 2-3 content tabs, and there is no reason to make a module.

also on that example posted, the solution provided is only for outputting markup, like some instructions, or like a training video etc. AFAIK you cannot add a tab to page edit and expect those fields to automagically save to the database b/c the fields need to exist in the database to save to.

  • Like 3

Share this post


Link to post
Share on other sites
1 minute ago, Macrura said:

Can't you just make a regular fieldset tab and put them in there, i have sometimes 2-3 content tabs, and there is no reason to make a module.

I tried that as well, but these fields need to appear on every page and there's no way to set a fieldset as global, and I don't want them appearing on the fields list either, as I will eventually have many of these custom fields and it will be a mess.

Share this post


Link to post
Share on other sites

this has been discussed in the context of a repeater field with a limit of 1 item; afaik there is no way to do what you are describing

  • Like 1

Share this post


Link to post
Share on other sites
7 hours ago, novalex said:

I tried that as well, but these fields need to appear on every page and there's no way to set a fieldset as global, and I don't want them appearing on the fields list either, as I will eventually have many of these custom fields and it will be a mess.

All fields in PW are custom fields. And you can't save content to a page without an actual field added to the page's template to hold that content (in your module you are only dealing with inputfields which themselves do not save their content to the DB).

If you like you can add tags to your fields to create groups of fields within the fields list and keep things tidy. As @Macrura said, currently the only way to add a group of fields to a template in the form of a single unit is to create a repeater with those fields and limit it to a single repeater item. Or if you prefer, a PageTable or Profields Table in conjunction with Limit PageTable or Limit Table.

Another approach that I sometimes take (if the project is well planned out in advance) is first create a template with the fields/fieldsets that will be used on all templates, and then I duplicate that template as the starting point for each additional template.

  • Like 4

Share this post


Link to post
Share on other sites

yep. you can also read this post (the whole thread) to see one option:

 

  • Like 1

Share this post


Link to post
Share on other sites

Thanks for all the help guys, appreciated. I ended up just creating repeater fields, nested as needed, and it works well enough. Coming from WordPress with ACF or CMB2, I'm surprised how flexible the PW system is and how many options it offers for the fields. I just wish the documentation was a little more comprehensive and offered some examples as well, sort of like the WordPress codex, since I'm having a hard time understanding/following the source code.

I look forward to working with PW some more, I'm sure I'll get the hang of it soon and then it's bye-bye WordPress :)

  • Like 4

Share this post


Link to post
Share on other sites

hi novalex!

great that you found a way :) just take care if you have a more complex setup and need some advanced selectors the repeater setup COULD be a problem (or a little harder). if you have 2 regular fields forename and surname a selector would be:

$pages->find('forename=john, surname=doe');

if you have a repeater setup, it would be:

$pages->find('yourgroup.forename=john, yourgroup.surname=doe');

as long as it is simple like this it will work, but i can remember that it can lead to problems but don't remember exactly... just keep in mind that it could be easier to have "duplicate" fields and simple selectors than the other way round ;)

  • Like 1

Share this post


Link to post
Share on other sites

Yep, already came across this "issue", where I have to use something like "$page->home_tabs->home_tabs_content" in my template.

I'm not sure if I'm doing this right, I'm used to ACF where field IDs inside repeaters couldn't collide with other fields, so I could do "$home_tabs['content']", but since in PW each field has to have a unique ID, my selectors for nested fields are getting pretty long and hard to read because of the repetition. Any suggestions for that? I can't simplify too much, the site I'm working on now has some complex sections which require heavy repeater use.

Share this post


Link to post
Share on other sites
6 hours ago, novalex said:

Yep, already came across this "issue", where I have to use something like "$page->home_tabs->home_tabs_content" in my template.

You can avoid some repetition and shorten the way you get field content in your templates like this:

// Get the repeater item (the item is a page)
$r_item = $page->repeater_field->first();

// Get field content from the item
echo $r_item->foo;
echo $r_item->bar;
echo $r_item->baz;

 

  • Like 3

Share this post


Link to post
Share on other sites
Quote

I can't simplify too much, the site I'm working on now has some complex sections which require heavy repeater use.

you would not imagine how often i have thought that myself and then i found out how to do it the processwire-way and it just seemed too simple with something like a 3-liner ;)

"heavy use" of repeater sounds like you could maybe improve/change how you structured your content. in PW thats a very important part of your work. if you structure your project/data well, most of the time you end up with very simple and clean selector-calls like

$pages->find('template=product');
// or
$page->children('category=car');

of course that's just wild guesses, but if you want to share your setup i'm sure you'll get valuable feedback from lots of knowledable guys (and girls) here :)

  • Like 3

Share this post


Link to post
Share on other sites

@Robin S There's still repetition because the repeater field properties are also prefixed with the pertinent section ID, such as "home_tabs" to avoid field ID collision. Perhaps I could make a wrapper function to grab fields from a repeater, something like "get_section_field('content', 'home_tabs')", do you think it's a good idea? It seems easier to read to me.

@bernhard Agree on all points! Trouble is, this is a website for a client, the design is already approved and I cannot restructure it. I could have fields for each section, which would simplify things, but the client must be able to edit, add and remove sections as needed, hence the heavy use of repeaters.

I came across another issue, and I have no idea what the problem is. I need a few admin pages to keep various site options such as API keys, common content displayed across pages, etc. I have created two templates, set their icon, and added pages under the admin page tree using these templates. However, in the menu only the parent page appears, and its icon is the default sheet of paper, not the cog I have selected. Screenshot of the page tree and admin menu attached. Any idea what I'm doing wrong?

Cheers, and thanks for all the help so far!

Alex

Screenshot from 2017-05-17 11:47:36.png

Share this post


Link to post
Share on other sites
2 hours ago, novalex said:

There's still repetition because the repeater field properties are also prefixed with the pertinent section ID, such as "home_tabs" to avoid field ID collision.

I'm not sure what you mean here. There is no prefix to field names that are used in a repeater. For example, if you have the "title" field in your containing page template, and also the title field in your repeater template then the field name "title" applies to both without any prefix.

echo $page->title; // the containing page title
echo $page->my_repeater->first->title; // the first repeater item's title

Or do you mean that in Page Edit the inputfields inside a repeater have a suffix to their name, e.g. "title_repeater1147"? Because you don't need to use that when you get the field in your template.

  • Like 2

Share this post


Link to post
Share on other sites

@Robin S I mean when I create fields for a repeater, let's say I need an image, an icon, and text, I assign them IDs prefixed with the repeater ID, so I create 3 fields named "home_tabs_image", "home_tabs_icon", and "home_tabs_text" and add them to the "home_tabs" repeater. Your reply made me realize I've been going at it like a neanderthal, and I don't actually need to create unique fields for a repeater, I just need to create each type of field I'll need once and I can assign them multiple times to different templates and repeaters. Boy, do I feel dumb right now :lol:.

Share this post


Link to post
Share on other sites
2 hours ago, novalex said:

Boy, do I feel dumb right now :lol:

never mind, the simplicity of processwire was a big hurdle for many of us in the beginning ;):P

...and i'm still curious what setup would need lots of repeaters for structuring everything. usually you can keep everything very clean just by using different templates, different parents in the tree and doing the relations via pagefields. don't get me wrong. it's just my experience that whenever something felt complex/complicated it was most of the times a problem of my (or other forum users) setup :)

i wish you lots of happy aha-moments ;)

  • Like 3

Share this post


Link to post
Share on other sites

Yep, if I'd learned PW from the start I'd probably be better off, but I'm used to the WP + ACF way of doing things, so they creep into this PW project as well.

As for the setup, for example, I have a group of tabs on the homepage, and each tab has sections with an image, icon and text. I figured the best way to do this would be to have a repeater for the tabs themselves and a nested repeater for each tab's sections. I have a pretty short deadline, so I had to just jump in head-first and get the homepage done to show the client. I'll definitely need some time to learn the ropes properly, and then I'll be able to better think every field and template out from the start and make things simpler.

Thanks a lot, once again, to all of you who took the time to help a newbie out, I hope to return the favor sometimes.

  • Like 2

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 Robin S
      A new module that hasn't had a lot of testing yet. Please do your own testing before deploying on any production website.
      Custom Paths
      Allows any page to have a custom path/URL.
      Note: Custom Paths is incompatible with the core LanguageSupportPageNames module. I have no experience working with LanguageSupportPageNames or multi-language sites in general so I'm not in a position to work out if a fix is possible. If anyone with multi-language experience can contribute a fix it would be much appreciated!
      Screenshot

      Usage
      The module creates a field named custom_path on install. Add the custom_path field to the template of any page you want to set a custom path for. Whatever path is entered into this field determines the path and URL of the page ($page->path and $page->url). Page numbers and URL segments are supported if these are enabled for the template, and previous custom paths are managed by PagePathHistory if that module is installed.
      The custom_path field appears on the Settings tab in Page Edit by default but there is an option in the module configuration to disable this if you want to position the field among the other template fields.
      If the custom_path field is populated for a page it should be a path that is relative to the site root and that starts with a forward slash. The module prevents the same custom path being set for more than one page.
      The custom_path value takes precedence over any ProcessWire path. You can even override the Home page by setting a custom path of "/" for a page.
      It is highly recommended to set access controls on the custom_path field so that only privileged roles can edit it: superuser-only is recommended.
      It is up to the user to set and maintain suitable custom paths for any pages where the module is in use. Make sure your custom paths are compatible with ProcessWire's $config and .htaccess settings, and if you are basing the custom path on the names of parent pages you will probably want to have a strategy for updating custom paths if parent pages are renamed or moved.
      Example hooks to Pages::saveReady
      You might want to use a Pages::saveReady hook to automatically set the custom path for some pages. Below are a couple of examples.
      1. In this example the start of the custom path is fixed but the end of the path will update dynamically according to the name of the page:
      $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'my_template') { $page->custom_path = "/some-custom/path-segments/$page->name/"; } }); 2. The Custom Paths module adds a new Page::realPath method/property that can be used to get the "real" ProcessWire path to a page that might have a custom path set. In this example the custom path for news items is derived from the real ProcessWire path but a parent named "news-items" is removed:
      $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'news_item') { $page->custom_path = str_replace('/news-items/', '/', $page->realPath); } }); Caveats
      The custom paths will be used automatically for links created in CKEditor fields, but if you have the "link abstraction" option enabled for CKEditor fields (Details > Markup/HTML (Content Type) > HTML Options) then you will see notices from MarkupQA warning you that it is unable to resolve the links.
      Installation
      Install the Custom Paths module.
      Uninstallation
      The custom_path field is not automatically deleted when the module is uninstalled. You can delete it manually if the field is no longer needed.
       
      https://github.com/Toutouwai/CustomPaths
      https://modules.processwire.com/modules/custom-paths/
    • By louisstephens
      So I ran into a very strange issue today. I have a template with a pagetable and I went to add an item to it, when I went to select an image (for an image field) the page instantly threw up an error
      "ProcessPageSearchLive: No search specified"
      The page's content also switched to the image attached. This all worked perfectly last week (local mamp box). Has anyone experienced this before, and how did you solve it?
       

    • By Pip
      Hi everyone, 
      Is there a way for us to replicate the "http://mydomain.com/processwire/page/edit/?id=xxx" and change the template to match my site template? 
      I'm terribly happy with the admin / backend page edit. It covers literaly everything I want to empower my non super admin user in updating pages such as validation, repeater management, file upload. 
      I wish not to allow the users to see the backend for both security and aesthetic reasons. 
      Thanks and hope to hear from you soon. 
       
×
×
  • Create New...