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

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 1

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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
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 AndZyk
      Hello,
      when you add a page you can see the page name of the page under the page title field. But when you change the page title afterwards, you have to go to the settings tab to also change the page name.
      We have many clients that change the page title afterwards but forget to change the page name, because they don't look in the settings tab or forget it.
      Is it possible to show the page name on the content tab under the page title?
      I hate to say this, but I like how WordPress handles this better:

      Or should I open an GitHub request?
      Regards, Andreas
    • By Robin S
      Pages At Bottom
      Keeps selected pages at the bottom of their siblings.
      A "bottom page" will stay at the bottom even if it is drag-sorted to a different location or another page is drag-sorted below it (after Page List is refreshed the bottom page will still be at the bottom).
      Newly added sibling pages will not appear below a bottom page.
      The module also prevents the API methods $pages->sort() and $pages->insertAfter() from affecting the position of bottom pages.
      Note: the module only works when the sort setting for children on the parent page/template is "Manual drag-n-drop".
      Why?
      Because you want some pages to always be at the bottom of their siblings for one reason or another. And someone requested it. 🙂
      Usage
      Install the Pages At Bottom module.
      Select one or more pages to keep at the bottom of their siblings. If you select more than one bottom page per parent then their sort order in the page list will be the same as the sort order in the module config.

       
      https://github.com/Toutouwai/PagesAtBottom
      https://modules.processwire.com/modules/pages-at-bottom/
    • By MoritzLost
      I'm trying to build a bitwise filter for a database query for my textformatter module, and I stumbled over some page statuses I don't quite understand:
      /** * Page has pending draft changes (name: "draft"). * #pw-internal * */ const statusDraft = 64; /** * Page has version data available (name: "versions"). * #pw-internal * */ const statusVersions = 128; If I'm not mistaked, there's no way to create multiple draft of a page in the ProcessWire core without module, is that correct? I initially assumed was the status assigned to unpublished pages, but the unpublished status corresponds to id 2048. Is the only way to create drafts with the ProDrafts module?
      For my purposes, I just need to understand how I should treat those statuses. I'm trying to get all pages that are published and either hidden or not hidden (I want to make this configurable). Do I need to exclude pages that have the statusDraft, or statusVersions? Only one of them? Only in combination with other statuses? Or can I safely ignore those (so it's fine if the pages have the status or not)? I don't own the ProDrafts module, so I can't check the code to see how individual drafts are stored and how the draft ids correspond to the published id.
      Any insight into those statuses is appreciated. Thanks in advance!
    • By gebeer
      Hello,
      I have a user page template with many fields that are organised in tabs. Tabs do not work on the profile edit screen. So I had to find a way how to let users edit their page with tabs in place.
      The way I solved this is having users edit their user page in the backend instead of their profile page. So basically they are on a page edit screen and not on their profile edit screen which is a different process. The drawback of this method is that the users edit their profile on a URL like .../youradminurl/access/users/edit/?id=1377. So I needed to make sure that users cannot edit other users' profiles by just switching out the id. I did this through hooks that redirect them to their own profile.
      This is far from a perfect solution. Ideally I would like to mask the page edit url to something like /myprofile but haven't found a way on how to do this, yet.
      How would you go about this?
      redirect rules in .htaccess hooking into the profile edit process? Either way I couldn't figure out how to accomplish it. Any pointers towards a solution would be very much appreciated.
    • By ridgedale
      Reference: PW 3.0.111 and uikit3 based site using the Regular-Master profile.
      I've setup a page where a member can edit contact details via the frontend displaying the field content using the <edit> ... </edit> tags.
      This works fine when the fields actually contain data. However fields that contain no data (i.e. empty) do not appear to be editable. No edit cursor appears (- possibly owing to the field width being 0px?)
      Is the only solution to recreate the page using a form, for example,  or is there a simple way to allow blank fields to be editable on the frontend?
      I wondered if anyone else has found a solution to this problem. Any assistance would be appreciated.
×
×
  • Create New...