Popular Post bernhard Posted November 9, 2017 Popular Post Share Posted November 9, 2017 Edit: Because of the great response to this topic I wrote a guest blogpost: https://processwire.com/blog/posts/building-custom-admin-pages-with-process-modules/ One of the hidden treasures of processwire seems to be the creation of custom admin pages. Technically speaking those pages are ProcessModules - but i guess that's the reason why so many people out there seem to be afraid of building them... it sounds so hard! You've never created a module for ProcessWire? You have never created a plugin for any other CMS? You have no clue about OOP with all its classes, methods and properties? No problem! I'll show you how simple you can start: <?php class CustomAdminPage extends Process { public static function getModuleinfo() { return [ 'title' => 'Custom Admin Page Example', 'summary' => 'Minimalistic ProcessModule to show that nobody has to be afraid of building custom admin pages.', 'href' => 'https://processwire.com/talk/topic/17709-how-to-create-custom-admin-pages-aka-processmodules-yes-its-that-simple/', 'author' => 'Bernhard Baumrock, baumrock.com', 'version' => 1, // page that you want created to execute this module 'page' => [ 'name' => 'customadmin', // your page will be online at /youradmin/setup/customadmin/ 'parent' => 'setup', 'title' => 'Custom Admin Page Example' ], ]; } public function ___execute() { return 'This is the most simple Admin-Page you have ever seen :)'; } } Now save this file as CustomAdminPage.module and place it in your /site/modules folder. After a refresh it will show your module in the modules manager of your site where you can install it: After installation you already have your first very own admin page! Congratulations! Was not too hard, was it? It's as simple as that! Now lets add some more custom HTML. And to show you another nice feature we will add this code to a separate method called executeDemo(). And because everything is so simple we will also add some javascript to this page public function ___executeDemo() { $out = ''; $out .= '<h1>H1 has some special css styling in the admin, thats why it seems to have no effect</h1>'; $out .= '<h2>H2 looks different ;)</h2>'; $out .= '<h3>...and so does H3</h3>'; $out .= '<button onclick="myFunction()">Click me</button>'; $out .= '<script>function myFunction() { alert("this is a demo javascript"); }</script>'; return $out; return ''; } Now thanks to ProcessWire-magic your page will already have its own URL: Just append /demo to your url and see what you get: And of course don't forget to click the button Ok, now that code looks a bit hacky, right? Inputfields and especially InputfieldMarkup for the win! We add another method with some advanced code. To use inputfields we need a form that holds all those inputfields and that makes it possible to handle user input lateron. See somas great tutorial about forms here for a quickstart and more details: public function ___executeAdvanced() { $out = '<h2>A more complex Example</h2>'; $form = wire()->modules->get('InputfieldForm'); $field = wire()->modules->get('InputfieldMarkup'); $field->label = 'Markup Test 1'; $field->value = '<h1>h1</h1><h2>h2</h2><h3>h3</h3><h4>h4</h4>'; $form->add($field); $out .= $form->render(); return $out; } Ok, it get's boring Let's do something more fun and add a chart in a second field and change the fields to 50% screen width (I'm sure you know that already from the GUI template editor)! public function ___executeAdvanced() { $out = '<h2>A more complex Example</h2>'; $form = wire()->modules->get('InputfieldForm'); $field = wire()->modules->get('InputfieldMarkup'); $field->label = 'Markup Test 1'; $field->value = '<h1>h1</h1><h2>h2</h2><h3>h3</h3><h4>h4</h4>'; $field->columnWidth = 50; $form->add($field); $field = wire()->modules->get('InputfieldMarkup'); $field->label = 'Chart Sample'; $field->value = '$chart'; //$field->notes = 'Example code taken from here: http://www.chartjs.org/docs/latest/getting-started/usage.html'; $field->columnWidth = 50; $form->add($field); $out .= $form->render(); return $out; } OK, we are almost there... we only need to add the chart library! To keep everything clean we will put the code for the chart in another method. We will make that method PRIVATE to add some security. Our new Method: private function renderChart() { // prepare chart code wire()->config->scripts->add('https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.min.js'); ob_start(); ?> <canvas id="myChart"></canvas> <script> var ctx = document.getElementById("myChart"); var myChart = new Chart(ctx, { type: 'bar', data: { labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], backgroundColor: [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)' ], borderColor: [ 'rgba(255,99,132,1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)' ], borderWidth: 1 }] }, options: { scales: { yAxes: [{ ticks: { beginAtZero:true } }] } } }); </script> <?php return ob_get_clean(); } Now we just need to call $this->renderChart() in the right place! Here is the complete Module: <?php class CustomAdminPage extends Process { public static function getModuleinfo() { return [ 'title' => 'Custom Admin Page Example', 'summary' => 'Minimalistic ProcessModule to show that nobody has to be afraid of building custom admin pages.', 'href' => 'https://processwire.com/talk/topic/17709-how-to-create-custom-admin-pages-aka-processmodules-yes-its-that-simple/', 'author' => 'Bernhard Baumrock, baumrock.com', 'version' => 1, // page that you want created to execute this module 'page' => [ 'name' => 'customadmin', // your page will be online at /youradmin/setup/customadmin/ 'parent' => 'setup', 'title' => 'Custom Admin Page Example' ], ]; } public function ___execute() { return 'This is the most simple Admin-Page you have ever seen :)'; } public function ___executeDemo() { $out = ''; $out .= '<h1>H1 has some special css styling in the admin, thats why it seems to have no effect</h1>'; $out .= '<h2>H2 looks different ;)</h2>'; $out .= '<h3>...and so does H3</h3>'; $out .= '<button onclick="myFunction()">Click me</button>'; $out .= '<script>function myFunction() { alert("this is a demo javascript"); }</script>'; return $out; return ''; } public function ___executeAdvanced() { $out = '<h2>A more complex Example</h2>'; $form = wire()->modules->get('InputfieldForm'); $field = wire()->modules->get('InputfieldMarkup'); $field->label = 'Markup Test 1'; $field->value = '<h1>h1</h1><h2>h2</h2><h3>h3</h3><h4>h4</h4>'; $field->columnWidth = 50; $form->add($field); $field = wire()->modules->get('InputfieldMarkup'); $field->label = 'Chart Sample'; $field->value = $this->renderChart(); $field->notes = 'Example code taken from here: http://www.chartjs.org/docs/latest/getting-started/usage.html'; $field->columnWidth = 50; $form->add($field); $out .= $form->render(); return $out; } private function renderChart() { // prepare chart code wire()->config->scripts->add('https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.min.js'); ob_start(); ?> <canvas id="myChart"></canvas> <script> var ctx = document.getElementById("myChart"); var myChart = new Chart(ctx, { type: 'bar', data: { labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], backgroundColor: [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)' ], borderColor: [ 'rgba(255,99,132,1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)' ], borderWidth: 1 }] }, options: { scales: { yAxes: [{ ticks: { beginAtZero:true } }] } } }); </script> <?php return ob_get_clean(); } } I hope you enjoyed reading this and it will open up many new possibilities for you! Updates: permissions: https://processwire.com/talk/topic/17709-how-to-create-custom-admin-pages-aka-processmodules-yes-its-that-simple/?do=findComment&comment=174746 tutorial on file uploads: https://processwire.com/talk/topic/17709-how-to-create-custom-admin-pages-aka-processmodules-yes-its-that-simple/?do=findComment&comment=185261 snippet how to use NavJSON: https://processwire.com/talk/topic/17709-how-to-create-custom-admin-pages-aka-processmodules-yes-its-that-simple/?do=findComment&comment=216412 41 18 Link to comment Share on other sites More sharing options...
SamC Posted November 9, 2017 Share Posted November 9, 2017 The timing of this couldn't have been better. Big thanks 1 Link to comment Share on other sites More sharing options...
mr-fan Posted November 9, 2017 Share Posted November 9, 2017 Thank you very much...very easy entry on this topic....the last years i used AdminCustomPages but this is a little bit outdated since 3.x so this will be the only way to go. Best regards from the neighborhood 1 Link to comment Share on other sites More sharing options...
arjen Posted November 10, 2017 Share Posted November 10, 2017 Thanks @bernhard! This needs to be on the front page 5 Link to comment Share on other sites More sharing options...
3fingers Posted November 10, 2017 Share Posted November 10, 2017 3 hours ago, arjen said: Thanks @bernhard! This needs to be on the front page Straight to the docs! 3 2 Link to comment Share on other sites More sharing options...
dragan Posted November 18, 2017 Share Posted November 18, 2017 Thanks for this great tutorial! I was playing around lately with modules myself. It's really remarkable how easy it can be. Quick question: Is this the only (or just the "recommended") way to add content in a module page? $form = wire()->modules->get('InputfieldForm'); $field = wire()->modules->get('InputfieldMarkup'); What I'd like, is include() a PHP file that resides either in my modules or my site/templates folder. Or - well - any kind of PHP code right in the .module. InputFieldMarkup will not allow PHP. Is is possible to include just about anything I'd like? Or is this some kind of security limitation? Background: I created a simple custom help page that resides under /admin/setup, and also installs a custom role. If I wanted to extend that to not only use HTML/CSS/JS, but also PHP, how would I do that? (using all of PW's methods... $pages / wire() etc.). I'd like to create some kind of dashboard (just as a proof of concept). 1 Link to comment Share on other sites More sharing options...
bernhard Posted November 18, 2017 Author Share Posted November 18, 2017 hi dragan, you don't have any limitation when working with InputfieldMarkup. It just RETURNS markup, but of course you can create this markup via php or whatever you want. For example: $html = '<p>This is a test</p>'; for($i=0; $i<10; $i++) $html .= "<div>Line $i</div>"; $field = modules('InputfieldMarkup'); // using the functionsAPI it gets that short $field->value = $html; $form->add($field); but also in my example you could place any PHP code inside the renderChart method. 2 Link to comment Share on other sites More sharing options...
Karl_T Posted November 19, 2017 Share Posted November 19, 2017 Thanks for this great tutorial! I am impressed by your PW admin UI manipulation skill all time. This tutorial could definitely get someone's hands dirty. On 2017/11/9 at 11:30 PM, bernhard said: i guess that's the reason why so many people out there seem to be afraid of building them... it sounds so hard! Yes it is really quite hard imo because the related information is not easy to find. They do exist but always sit inside various post replies. It just looks like a missing piece to beginners. I long for a more in-depth version of this tutorial, or a complete guide precisely, that shows how to accurately use wiretab, pw-modal, panel, buttons etc. and layout all of them properly. I discovered a bit from reading through the core files and modules by trial and error but I believe I still have a long long way to go. I believe many people, like me a while ago, stuck in the layout phase and then give up their modules development. 4 Link to comment Share on other sites More sharing options...
bernhard Posted November 19, 2017 Author Share Posted November 19, 2017 6 hours ago, Karl_T said: Thanks for this great tutorial! I am impressed by your PW admin UI manipulation skill all time. This tutorial could definitely get someone's hands dirty. glad you like it and thanks for the compliment 6 hours ago, Karl_T said: Yes it is really quite hard imo because the related information is not easy to find. They do exist but always sit inside various post replies. It just looks like a missing piece to beginners. yeah... it's not as easy to find in the beginning (and often i'm still searching a lot around the code). but most of the necessary informations are not too hard to find if you look at the code. Inputfields for example have a baseclass here: https://github.com/processwire/processwire/blob/master/wire/core/Inputfield.php Also see somas tutorial about forms (i updated my initial post with the link: https://processwire.com/talk/topic/2089-create-simple-forms-using-api/ ) 6 hours ago, Karl_T said: I long for a more in-depth version of this tutorial, or a complete guide precisely, that shows how to accurately use wiretab, pw-modal, panel, buttons etc. and layout all of them properly. I discovered a bit from reading through the core files and modules by trial and error but I believe I still have a long long way to go. I believe many people, like me a while ago, stuck in the layout phase and then give up their modules development. I'll see what i can do... 5 1 Link to comment Share on other sites More sharing options...
bernhard Posted November 28, 2017 Author Share Posted November 28, 2017 I'm writing on a processwire.com guest blogpost arriving on friday. any ideas what i should cover? Building a basic custom admin page Hello World Explanations The manual way Building a module with multiple pages and buttons Hello Page2! Add some HTML (eg buttons) Using internal components (modules) Add external styles and scripts (eg charts) Handling user-input (forms & inputfields) adding your first field: inputfieldmarkup creating a custom form to add pages benefits: structure, render only one field in panel, ajax load Organizing your code and your files module info views any ideas? 9 1 Link to comment Share on other sites More sharing options...
rick Posted November 28, 2017 Share Posted November 28, 2017 Hi @bernhard, I like the first two options; Building a custom admin page (your post here, and @abdus tutorial), and Building a module with multiple pages and buttons. They sort of go together from an application point of view. You could incorporate real world examples, such as a help desk ticket system, or polling multiple email providers. I'm thinking more along the lines of how a user would go about creating the components, rather than the actual application itself. For example, let's use a help desk project. Some components would be: a toolbar with options to filter the content listed in an admindatatable by department, assigned person, severity, etc. Currently ProcessWire likes a vertical orientation rather than using the horizontal screen real estate. selecting from the resulting list an item to view greater detail - multiple pages. Abdus touched on this in his tutorial. selecting one or more checkboxes to perform some group action, such as changing the status, or even deleting those entries. periodically polling an endpoint to update the entries in the admindatatable (ajax retrieving new tickets, change of status, etc.) I don't want to make this overly complicated for your article, nor take too much of your time. I just notice that more people are posting about individual parts of similar scenarios and think it would be a great reference for everyone. I certainly appreciate the time you, and others here, are giving to the community. I look forward to whatever article you write on Friday! 2 Link to comment Share on other sites More sharing options...
bernhard Posted November 28, 2017 Author Share Posted November 28, 2017 4 minutes ago, rick said: periodically polling an endpoint to update the entries in the admindatatable (ajax retrieving new tickets, change of status, etc.) This is an interesting point that could fit very well, thank you. I'll try to include that in my post btw, the first two points are already finished. 3 Link to comment Share on other sites More sharing options...
gmclelland Posted November 28, 2017 Share Posted November 28, 2017 For what is worth... This may be to advanced, but I would like to see a tutorial on how to create an administrative page(Import Employees) to import a public Google Spreadsheet with the following inputs: Google Spreadsheet Url (text input) Import Strategy: choose what happens when the import is ran. Create new pages (checkbox) Create new pages and Update existing pages (checkbox) Disable/Unpublish missing pages (checkbox) Delete missing pages (checkbox) This page would be used to create pages of the type (Employee). The Google Spreadsheet would have the following fields: Employee Id Number Employee First Name Employee Last Name Employee Email Employee Phone When the form is submitted, it will display the # of pages created, disabled/unpublished, or trashed/deleted. Bonus: Would even be cool to see it ran in batches with a progress bar to prevent PHP timeouts. Maybe an integration with the new tasker module? No worries if this isn't a good candidate for a tutorial. I also like your suggestions. 1 Link to comment Share on other sites More sharing options...
bernhard Posted November 28, 2017 Author Share Posted November 28, 2017 hi @gmclelland that's definitely too advanced for now thanks for your suggestion! 1 1 Link to comment Share on other sites More sharing options...
rick Posted November 29, 2017 Share Posted November 29, 2017 Under the Code/File organization, it would be helpful to explain ProcessWire best practices for using: A single stand-alone process module. More than one process module (required = array(other modules)). Including a stand-alone class or interface in process modules. ... Just thinking out loud. 2 1 Link to comment Share on other sites More sharing options...
bernhard Posted December 4, 2017 Author Share Posted December 4, 2017 here is the blogpost just for reference https://processwire.com/blog/posts/building-custom-admin-pages-with-process-modules/ 7 2 Link to comment Share on other sites More sharing options...
modifiedcontent Posted December 31, 2017 Share Posted December 31, 2017 bernhard, I appreciate the effort and enthusiasm that has gone into this tutorial, but for me it goes too deep into the weeds too quick after the basic 'hello world' example. If I want to add a custom admin page to post/edit basic content - title, body, image - how would I do that? Would I add the code for that form to the ProcessSimple.module file or somewhere else? The stuff about panels, tables and charts is very confusing to me. If I want to create a custom admin with several pages/functions, would I need several *.module files for each or would there be a *.module folder/directory where I can add different files/processes? Can I start my custom admin area simple and build it out later, add stuff to it? Or should I build it all at once as one module? I am trying to figure this out on a "concierge job", so my brain/concentration operates at below 50%. Link to comment Share on other sites More sharing options...
bernhard Posted December 31, 2017 Author Share Posted December 31, 2017 hi modifiedcontent, 4 minutes ago, modifiedcontent said: If I want to add a custom admin page to post/edit basic content - title, body, image - how would I do that? Would I add the code for that form to the ProcessSimple.module file or somewhere else? this sounds a little strange. the easiest way of editing content is of course the normal pw edit screen. you can do a lot with normal pw features (like hiding fields on several conditions etc). if you really need more customized forms I show how you can do that here: https://processwire.com/blog/posts/building-custom-admin-pages-with-process-modules/#create-our-first-real-inputfields ; that's only one way of doing it. you can also easily modify the page edit forms via hooks. 6 minutes ago, modifiedcontent said: The stuff about panels, tables and charts is very confusing to me. sorry for that. you can also start by using InputfieldRuntimeMarkup - maybe that's easier to begin with... 8 minutes ago, modifiedcontent said: If I want to create a custom admin with several pages/functions, would I need several *.module files for each or would there be a *.module folder/directory where I can add different files/processes? totally up to you. you can create several pages in one module: https://processwire.com/blog/posts/building-custom-admin-pages-with-process-modules/#hello-page2 ; but you could also create one module for each page. It depends on you and your usecase which level of separation makes sense. 9 minutes ago, modifiedcontent said: Can I start my custom admin area simple and build it out later, add stuff to it? Or should I build it all at once as one module? sure, thats what i do throughout the tutorial. start with hello world, end with a custom CRM 1 Link to comment Share on other sites More sharing options...
modifiedcontent Posted December 31, 2017 Share Posted December 31, 2017 Quote this sounds a little strange. the easiest way of editing content is of course the normal pw edit screen Yes, of course it is. Unfortunately I actually have a client who thinks Processwire's admin area is confusing and wants an admin area that looks exactly like the horrible system he is trying to replace. I have to restructure/reorder all the standard admin functionality/edit screens into something he recognizes to gradually lure him over to the PW dark side. But apart from that, I am looking for the most basic proof of concept. Basic stuff that the default admin already does, stuff that everybody understands; how would you replicate that in a custom admin area? I am looking for a guide for the basic principles. Quote ... you can create several pages in one module: https://processwire.com/blog/posts/building-custom-admin-pages-with-process-modules/#hello-page2 ... Most modules seem to come in a folder/dir with other file types like js and css, not a single text file. How that works is basic module writing of course, but I was hoping to see some pointers in your tutorial how to structure that for a custom admin area. Your hello-page2 example still goes in the same single text file? Edit: Quote ... so as long as you don't come up with preciser descriptions of what EXACTLY you are trying to do ... Let's say you want to create a wizard style interface for adding/editing content, that starts with a title + body + images form, followed by steps or dropdowns to put the content in the right page. Instead of the page tree. More content-centric instead of structure-centric. I prefer the Processwire approach, but my client is used to that content-centric approach. But it doesn't matter what exactly I am trying to achieve in this case. I am looking for a general basic recipe how to create an alternative custom admin area or how to completely restructure the admin. Bernhard's tutorial is more about adding advanced features to the existing admin. Link to comment Share on other sites More sharing options...
bernhard Posted December 31, 2017 Author Share Posted December 31, 2017 I'm sorry @modifiedcontent but I put a LOT of effort in the blogpost, so as long as you don't come up with preciser descriptions of what EXACTLY you are trying to do I can not help. Maybe someone else understands your needs better and can therefore help you better. maybe a google search for "dashboard" has some interesting reads for you: https://www.google.at/search?q=site:processwire.com+dashboard Link to comment Share on other sites More sharing options...
arjen Posted December 31, 2017 Share Posted December 31, 2017 6 hours ago, modifiedcontent said: I actually have a client who thinks Processwire's admin area is confusing That's a first 6 hours ago, modifiedcontent said: wants an admin area that looks exactly like the horrible system he is trying to replace What does the system looks like? If you could post some screenshots I'm sure we could help you out. But you should start with some basic stuff like bernhard already described in his tutorial. 2 Link to comment Share on other sites More sharing options...
modifiedcontent Posted December 31, 2017 Share Posted December 31, 2017 Quote What does the system looks like? ... Seriously, you don't want to know. Awful mess. I disagree with my client, but have to try to meet him halfway. See edit in my comment above for more details. Again, I am not asking for a solution for my particular issue. This discussion is probably closer to what I am looking for. Link to comment Share on other sites More sharing options...
dragan Posted January 2, 2018 Share Posted January 2, 2018 @bernhard going through your epic tutorial again and again, I discover stuff I overlooked the first time. e.g. I didn't know it was so easy to add an additional page to a module such as you describe @ https://processwire.com/blog/posts/building-custom-admin-pages-with-process-modules/#hello-page2 Quick question: Do you know if there is a native PW method I can use here to define my own h1 title that looks a bit more human-readable? i.e. being able to display "My Second Page" instead of "Mysecondpage". I tried camel case and underscores for the function-name - didn't work. 1 Link to comment Share on other sites More sharing options...
bernhard Posted January 2, 2018 Author Share Posted January 2, 2018 Quote Method naming tip If you want to use hyhens in your URL segments, simply use camel case for your method name. Any uppercase characters (after the first) translate to hyphens in the URL. The following examples help to clarify: executeMySecondPage translates to my-second-page in the URL executeMysecondpage translates to mysecondpage in the URL Credits to Ryan - I didn't know about that detail and he added it to the blogpost while proofreading it Sorry I think I misunderstood you try $headline = 'Happy ' . date('Y'); $this->headline($headline); $this->wire('processBrowserTitle', $headline); 2 Link to comment Share on other sites More sharing options...
dragan Posted January 2, 2018 Share Posted January 2, 2018 Thanks. However, that sets the html title, not the h1 that users see when visiting the page. Strangely, with code like this there is no h1 output at all: public function ___executeMySecondPage() { $headline = 'Happy ' . date('Y'); $this->headline($headline); $this->wire('processBrowserTitle', $headline); return '<p> Hello Page2 :) </p> <p> <a href="./" class="ui-button ui-state-default"> Go to Page 1 </a> </p>'; } Did Ryan tell you where all these "secret" methods are hidden? Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now