Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 11/12/2017 in all areas

  1. Thanks @Samc and @maxf5, you gave me an idea about the future of my AdminOnSteroids module, rewriting it as an admin theme. This has been come up earlier too but there was no Uikit theme then, now it's perhaps more easy to do this.
    5 points
  2. Hello All ... I just added a new Site Profile ... It is important that you use the latest version that supports the new Fields => Fieldset in Tab , Fieldset ( Page ) for this time it is version 3.0.83 DEV A simple profile for quick start new Page ... There are several pages like About Us, Blog, Portfolio, Contact Page ... The profile is not based on any framework, I just used some css, flexbox, grid, font awesome, and added a simple FlexBox Grid called GRIDLEX ... CAN DOWNLOAD FROM THIS LINK: http://modules.processwire.com/modules/site-twilight/ https://github.com/rafaoski/site-twilight Some Screenshots: OPTIONS PAGE: CONTACT PAGE: BLOG PAGE: ABOUT PAGE: PORTFOLIO PAGE: In addition, I added 2 great modules: Tracy Debugger: https://modules.processwire.com/modules/tracy-debugger/ Markup Sitemap: http://modules.processwire.com/modules/markup-sitemap/
    4 points
  3. Sometimes you want to add a specific markup to the values inside a pagetable field. Fe. you want to add a FontAwesome icon in front of the value or you want to add a background-color. In this little tutorial I want to show you how you can do that with only a view lines of code. In the following example I will add the background color red to a specific field inside the page table. This is what i looks like at default: After the manipulation it will looks like this: You can see the difference in the second field of the pagetable. This manipulation makes not really sense and it is only to show you what can be done. You can manipulate it also in other ways. Fe to add different colors to different status of orders and so on. To achive this we use the following type of hook: Fieldtype::markupValue (read more at https://processwire.com/api/ref/fieldtype/markup-value/) In this case we put the code inside the init.php and not in the ready.php. The reason for this is, that if the page table will be updated via Ajax, the default values will be displayed again if the code is in ready.php. So here we go: $this->addHookAfter('Fieldtype::markupValue', function($event) { $page = $event->arguments(0); $field = $event->arguments(1); $value = $event->arguments(2); if($field->name == 'nameofthefield' && $page->template->name == 'childrentemplatename') { $event->return = '<span style="background:red;color:#fff;">'.$value.'</span>'; } }); First we define all the variables needed for the manipulation ($page, $field and $value). $value returns the formatted value of the field. If you need the unformatted value (fe. if it is a date field and you want the timestamp) you get the unformatted value by using this line of code: $value = $page->getUnformatted($field->name); We restrict it to a special field of the pagetable called "nameofthefield" - rename it to the name of your field where you want the manipulation to take place. So this field of the pagetable is a field of a child template. In this case the child template is called "childrentemplatename". You have to rename it to your child template name. Only to clearify: each field inside the pagetable is part of a child page. "$event->return" returns the output of the field (usually the value). In this example the value of the field should be between two <span> elements with a special CSS styling to add a red background and turn the color of black to white. Here is a usecase where I use this technique: You can see that after the end date there is no time (in opposition to the start date). Instead of the time the text "no specific endtime" is displayed. This is because this event has no specific end time (it is open end). Only to mention: The editor can choose if the event is all day long or starts and ends on specific date and time or it is open end. Thats all and happy coding with your own manipulations!
    4 points
  4. It’s certainly a different language, but besides any language/runtime based differences it’s actually not to different to use phoenix compared to using e.g. laravel in php. It’s got routers, controllers, views and behind that some business logic. I also noticed that the functional nature of the language does actually make the latter easier to understand than some oop classes and I found learning a functional (/actor based) language actually made me understand some principles behind oop quite a bit better. Anything which you’d use laravel or similar frameworks for in the php world or rails in ruby. So custom web-applications, json api's, applications which often require things to run longer than the few second web requests. So kinda anything which is not just a website (cms) with a handful of forms and not full on e-commerce. I'd also do websites in elixir if they're supposed to handle a really big number of users / spikes of users. Some early adopters of elixir could reduce their number of servers to a quarter after switching to elixir (most from ruby/rails). For the thing's I'll be using elixir for the client's won't really care. We're not doing very many marketing sites, where the client might want to edit texts or something. We run a SaaS product, where any client interaction is on the frontend anyways and also some web-applications, which we fully manage for our customers. Those also have the most interaction with people using the application on it's frontend and very few to no interaction with the client themselves.
    3 points
  5. Here are a few links to check out for PW calendars. I'm not recommending a solution here, just signposting. These are in the official PW module repository... https://github.com/ffub/MarkupiCalendar (iCalendar feeds anyone?) https://github.com/netcarver/PW-ProcessGcalEmbed (My old module) http://www.99lime.com/modules/recurme/ (Premium) These aren't (a.f.a.i.k.)... https://github.com/plauclair/Calendar https://github.com/ryancramerdesign/MarkupLoadGCal (Ryan's module) https://github.com/decadeofdefeat/church-website-processwire (Has a calendar implementation in it) https://github.com/lindquist/processwire-calendar https://github.com/UF-Asq-Fab-Lab/Scheduler Hope that helps!
    2 points
  6. @cstevensjr the latest version of the prev/next tabs fixes the issue between the help tab and the prev/next tabs. Also the newer version of the Admin Help module has some fixes; i'm still working on further updates to that module but the latest version on GH should fix some oddities.
    2 points
  7. In the past, I've had to delete multiple tens of thousands of records (pages) and did it by pushing the ids of the pages to be deleted into a WireQueue and then, at regular intervals (think cron-driven), pull out small batches of them to delete. To completely empty the queue takes a long time, but the admin interface remains responsive and you simply need to check the number of items remaining in the queue to know how far through the process you are.
    2 points
  8. the only problem with overriding the core pwimage plugin is keeping up with changes to the core, otherwise, if it works, and you are not planning to upgrade the core, then that should be ok... I'd say my first instinct in this situation would be to use a textformatter, and then be able to manipulate the elements in the ck editor field; You could use dom parsing and then should be able to add those attributes, though i haven't tried this yet (but will be doing so soon for a site that needs AMP pages)... i have used image interceptor in the past, (http://modules.processwire.com/modules/textformatter-image-interceptor/ ) Not sure if it works on 3x branch, i think i had to fix some things in that for a site i upgraded to 3x, but never logged my changes, just fixed some errors and let the site work.. This is a new module that manipulates images, so possibly having a look at if you were going to make a textformatter... ( http://modules.processwire.com/modules/textformatter-fluid-images/ )
    2 points
  9. Ok. 1. We need to generate a unique token for a user and store it. The simple way to do that is to add a field to user page (login_token in the example). To make process easier we make a method for that via hook: // site/init.php $wire->addHook("User()::getToken", function(HookEvent $event) { $page = $event->object; if (empty($page->login_token)) { $page->of(false); $page->login_token = generateToken(12); $page->save(); $page->of(true); } return $event->return = $page->login_token; }); The genereateToken() function is yours to implement as you wish. 2. Now we can generate a link: $link = $page->httpUrl . "?user=". $user->id . "&token=". $user->getToken(); 3. Finally we need to handle those parameters and make user autologin: // site/templates/_init.php if ($userToLoginId = $sanitizer->int($input->get->user)) { $url = $page->url; $userToLogin = $users->get($userToLoginId); $tokenToLoginWith = $sanitizer->text($input->get->token); if ($userToLogin->id && $tokenToLoginWith && strcmp($userToLogin->login_token, $tokenToLoginWith) == 0) { $loggedInUser = $session->forceLogin($userToLogin); if ($loggedInUser) { $user = $loggedInUser; }; $session->redirect($url); } } We can then nullify user token if we want it to be only a one-time ticket. I rewrote whole lot of stuff, so might not work straight away, but surely you can fix it @szabesz)) Hope I am not missing something essential.
    2 points
  10. 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
    1 point
  11. Sometimes you need to track changes in certain values of a page to take an action afterwards. In this example I will show you how to show a simple message after changes to inform the user that field values have been changed. Put this piece of code inside your ready.php. //Track changes $pages->addHookAfter('saveReady', function($event) { $page = $event->arguments[0]; if(!in_array($page->template->name, array('template1','template2'))) return; $fields = array('field1','field2','field3','field4'); $changedfieldsarray = array(); foreach($fields as $field) { if ($page->isChanged($field)) { $changedfieldsarray[] = $page->fields->get($field, true)->label; } } $fieldnames = implode(", ", $changedfieldsarray); $this->warning(sprintf(__("Following fields have been changed: %s"), $fieldnames )); }); The first restriction in this example is to run this hook "aftersaveReady" and only on certain templates: in this case template1 and template 2. You need to rename this to your template names. Remove the following line of code if you want it to run on all pages (no restrictions): if(!in_array($page->template->name, array('template1','template2'))) return; Now you have to define the fields where you want to track changes (take a look at this line): $fields = array('field1','field2','field3','field4'); In this case the fields are called "field1 to field4". Rename it to your field names. The API call to track changes is "$page->isChanged('fieldname')". You will find more information at https://processwire.com/api/ref/page/is-changed/. Use a foreach to loop through the fields array and store all changed fields inside an array. In the last step all the changed fields were outputted inside a message to inform the user. In this case I want to show the labels instead of the field names. Only to mention: The changes will keep alive, so you have to delete it manually (http://cheatsheet.processwire.com/pagearray-wirearray/change-tracking/a-resettrackchanges/). This little tutorial should only be a starting point for your own coding.
    1 point
  12. It's mostly a legacy thing, but also functions as a fallback if the other themes aren't loaded for some reason. That said, I am not sure if the css file from that directory is needed if another theme is working as expected.
    1 point
  13. Hi @SamC You can choose in AdminThemeUikit module settings page which location should be used by the module. Also, don't forget to update AdminThemeUikit to the latest version. Take a look at this blog post http://processwire.com/blog/posts/processwire-3.0.83-core-updates/ Sources of CSS could be found in https://github.com/ryancramerdesign/AdminThemeUikit
    1 point
  14. Thanks, figured as much. Will need to rework this on the front end then.
    1 point
  15. PW ultimately calls $user->hasPermission() with the supplied permission info, which does expect a single permission to be used. So you'd use the permissionMethod for multiple ones.
    1 point
  16. The current generator uses an array for “permission”, which doesn’t seem right as the API docs state it needs to be a string… Which is correct? Also, if a permission is created via the “permissions” array, surely they would all need to be in “permission” as an array as well? This how I’m doing it in Jumplinks, anyway (hope I’m not wrong). Or perhaps “permissionMethod” should be used for multiple permissions? Some insight would be appreciated.
    1 point
  17. I think that is because in that example you are adding files to the repeater page. A page has to be saved before you can add files or images to it.
    1 point
  18. This is what i said a while ago, but i could'nt find any time for it to realise until now: I'd love this:- remove masthead- sidebar (left) always visible- change icons to uikit3 icons- breadcrumb on top (with search on the right which i forgot here)- some design fixes
    1 point
  19. Kind of pointing out the obvious here, but that could be asking for trouble. A number of modules (including core ones, such as Repeaters) perform cleanup etc. with hooks. Unless you're really careful, you could easily leave a ton of orphaned data behind with this method.
    1 point
  20. I've just installed 3.0.83, but what happened to the sidebar option? The options I have now are: Masthead only has no sidebar and the other options have the entire page tree in a sidebar. So I go to 'Navigation': And the options are to either click the logo to go back to default tree list page, or click logo for an offcanvas menu, which is just weird. Who would expect a menu when clicking on a logo? I would have liked this sidebar menu positioned to the left and kept there, with the masthead doing a disappearing act. Or having a dumbed down masthead when there is a sidebar present. Modern monitors have a lot of width, why used a masthead and cram everything in vertically? I feel this makes my editing experience worse than using the older reno theme. The design just feels so unbalanced. You can probably tell I'm not a fan of masthead navigation at all, but of course this is all personal opinion. These are the best looking admins IMO so I need to look into how to create a custom admin theme in order to emulate something like these. Of these three, craft is my favourite. I've used it to make a site before and it was extremely nice to use. It's obviously possible with the new uikit so need to find some info on making my own theme. I see in the readme: "To install a new admin theme, you would place it in /site/templates-admin/ and leave the one that is in /wire/templates-admin/." ...so I guess that's my starting point. Looking at the current uikit admin module files though, I may be in a bit over my head here! Not sure whether you need to make a whole new module of just a '/site/templates-admin/' folder. Can't work out how the module AdminThemeUikit relates to the stuff in templates-admin folder.
    1 point
  21. Here is another working method, that only shows changes once after save. It is based on this post from Ryan. //Compare before and after values $pages->addHookAfter('saveReady', function($event) { $page = $event->arguments('page'); if(!in_array($page->template->name, array('template1', 'template2'))) return; //restrict it to these templates only $fields = array('field1','field2'); //check only changes on these fields $this->wire('pages')->uncache($page);//uncache new page $oldPage = $this->wire('pages')->get($page->id);// get old page $changedfieldsarray = array(); foreach($fields as $field) { if (($oldPage->$field) != ($page->$field)) { //this is the comparison between before and after $changedfieldsarray[] = $page->fields->get($field, true)->label; } } if(count($changedfieldsarray) > 0) { $fieldnames = implode(", ", $changedfieldsarray); $this->warning(sprintf(__("Following fields have been changed: %s"), $fieldnames )); } }); It uses the uncache method to compare stored values from the DB and the new ones entered in the form. This informs the editor only once directly after form submission. If the editor push the save button once more and nothing was changed, the message will not be shown again. This is the main difference between this and the previous method. Attention: This method uncaches the page and therefore all entered values will be cleared after pressing the submit button and no sucessfull saving of the page - so use this method with care.
    1 point
  22. Well, he is even more controversial than Jobs. Einstein, the Plagiarist: https://www.bibliotecapleyades.net/esp_einstein.htm I do agree that they do not seem to be the best fathers ever Back to Steve(s). Once I was lucky enough to meet Steve Wozniak in person. Well, he would be a better choice if you had to pick a father...
    1 point
  23. Hey, @szabesz! It was done. Actually It was pretty easy (at least the way we implemented it without much security overthinking). Would be happy to share code if needed. But it is essentually what @LostKobrakai wrote.
    1 point
  24. I have a site that I oftentimes sync the live database to my dev database (I made a bash script to automate the process). I generally like to "clean" the database once it has been copied over to my dev machine, which involves running a script that deletes 15,000 pages (orders in my case), among other things. Doing this using $page->delete() in a script (which I'm running through the command line for added performance), takes about 30 minutes which is painful. I thought it through further and I came up with the following relatively simple script that can achieve the same result in a few seconds! It achieves this speed by running MySQL delete queries directly, bypassing PW's API. Here it is (modify accordingly): <?php namespace ProcessWire; ?> <?php include(dirname(__FILE__).'/index.php'); // bootstrap pw $order_ids = $pages->findIDs('parent=/orders/,template=order'); if(!count($order_ids)) exit; $order_ids = implode(",", $order_ids); $t = $templates->get("order"); foreach($t->fields as $f) { if( $f->type!="FieldtypeFieldsetOpen" && $f->type!="FieldtypeFieldsetClose" ) { $table = "field_".$f->name; $database->query("DELETE FROM $table WHERE pages_id IN ($order_ids)"); } } $database->query("DELETE FROM pages WHERE id IN ($order_ids)");
    1 point
  25. I'll try and fix the css to work on UiKit; in the meantime if the prev/next links make it into AOS that would be great, and 1 less module to install and worry about configuring on new sites...
    1 point
  26. I can confirm this issue with the Uikit theme. Here is an idea for the prev-next edit links placement, next to the page title: And I would use the regular link "title" attribute instead of the tooltip (it just works). In fact I wanted the add this feature to AOS for a long time but I couldn't find a satisfactory place to them. But now I think this is it
    1 point
  27. Easy. See Then have a field in that page for owner, which is the user's $user->id, add ?edit=true to the url (in a link from a user page or whatever) then in the page template something like <?php namespace ProcessWire; // Code to display page contents to guests if($input->get->edit && ($page->owner != $user->id)){ echo 'You are not authorised to edit this page.'; } else { // Your code (edit form etc) here } Very rough, but you should get the gist. If you get stuck, come back here and ask.
    1 point
  28. Hi folks, I published "Simple file downloads with ProcessWire tutorial" today which explains how to make a simple download function with ProcessWire (tested with version 3.0+). Basically this is based on my post here in the forums
    1 point
  29. What sort of field is authors_name? A Page Reference field? If so you should be able to match against the title of the referenced page with: authors.authors_name.title%=$q_word I'm curious about the setup of the authors field. The authors field is a Repeater, and then inside that Repeater is a Page Reference field, and the selectable pages of that field contain name fields for the author? Why so complex? Wouldn't it be possible to remove one of these levels and use either a Repeater or a Page Reference field for author?
    1 point
  30. There is a simpler solution: $this->backendUrl = urls()->httpAdmin;
    1 point
  31. Hi @flydev ! Great plugin, works mostly like a charm! I had 2 issues tough: 1. with google, matching first- and last-name and usernames does not work with our setup (special chars in names that are not reflected in the username etc). I think, this makes the plugin somewhat unflexible. Would be great to have the option configure the matching, or at least an option to only match the users mail (checkbox in the backend). I just saw the "options" "scope" settings in your github json and wonder if this is already implemented but not documented? 2. We run our new page in a subdirectory and the redirect url is wrong (this is more of a process-wire issue since its not easy to get the absolute urls from the api) this results in path being present twice in the redirect url: Problem: urls()->root + urls()->admin = //domain.com/path/ + /path/admin/ > //domain.com/path/path/admin/ This solution would be the following: // inside init() $this->backendUrl = pages()->get('path="'.str_replace(urls()->root, '', urls()->admin).'", include=all')->httpUrl; Keep up the great work!
    1 point
  32. Thanks. Currently, the front end displays basic information about the selected license underneath its drop-down.
    1 point
  33. @flydev: Really I'm not feeling in the right position to give suggestions here. I appreciate all the work and recherche you do here, so you should decide what is lesser work or fits better for you, for what ever reason. - If, at the end, a solution is available that let people login with their twitter account, it would be really great and is much more than there is atm.
    1 point
  34. yeah, so that's a week to everyone/anyone else.
    1 point
  35. Almost crying right now. Or having multiple orgasms. Or both. So awesome.
    1 point
  36. I just watched the video at home (damn mobile won't let me). Amazing feature to have! Watching this I think the "required" need to be more visible or red (asteriks). It can be missed too easily. And the show animation need to be much quicker! (lol) Not can we have also a hideIf() and a makeCoffeeIf()... I already see the forum full of posts "It doesn't show when..."
    1 point
  37. I used Gravity Forms a couple of times. While it is build for front-end forms I really like the way the depencies are build there with multiple conditions aka conditional logic.
    1 point
  38. Are you gone crazy? And even with colors!
    1 point
  39. Hi Michael, I have not seen any fields like that, but as an alternative you could try using a "page" type field. It would create a new page for each tag, but has a nice friendly interface for the user to manage them. 1. Add a new page in your tree called "Tags Collection", and make it hidden. 2. Create a new field called Tags and make it a "page" type. 3. On the input field settings, make the "Parent of selectable page(s)" the Tags Collection page 4. For the "Input field type" try one of : Select Multiple, asmSelect or PageListSelectMultiple (I prefer the asmSelect) 5. Check the “Allow new pages to be created from field?” to allow the user to easily add new tags directly from the field
    1 point
  40. Here's what draws the form for the skyscrapers search: <form id='skyscraper_search' method='get' action='<?php echo $config->urls->root?>search/'> <h3>Skyscraper Search</h3> <p> <label for='search_keywords'>Keywords</label> <input type='text' name='keywords' id='search_keywords' value='<?php if($input->whitelist->keywords) echo htmlentities($input->whitelist->keywords, ENT_QUOTES); ?>' /> </p> <p> <label for='search_city'>City</label> <select id='search_city' name='city'> <option value=''>Any</option> <?php // generate the city options, checking the whitelist to see if any are already selected foreach($pages->get("/cities/")->children() as $city) { $selected = $city->name == $input->whitelist->city ? " selected='selected' " : ''; echo "<option$selected value='{$city->name}'>{$city->title}</option>"; } ?> </select> </p> <p> <label for='search_height'>Height</label> <select id='search_height' name='height'> <option value=''>Any</option> <?php // generate a range of heights, checking our whitelist to see if any are already selected foreach(array('0-250', '250-500', '500-750', '750-1000', '1000+') as $range) { $selected = $range == $input->whitelist->height ? " selected='selected'" : ''; echo "<option$selected value='$range'>$range ft.</option>"; } ?> </select> </p> <p> <label for='search_floors'>Floors</label> <select id='search_floors' name='floors'> <option value=''>Any</option> <?php // generate our range of floors, checking to see if any are already selected foreach(array('1-20', '20-40', '40-60', '60-80', '80+') as $range) { $selected = $range == $input->whitelist->floors ? " selected='selected'" : ''; echo "<option$selected value='$range'>$range floors</option>"; } ?> </select> </p> <p> <label for='search_year'>Year</label> <select id='search_year' name='year'> <option value=''>Any</option> <?php // generate a range of years by decade, checking to see if any are selected for($year = 1850; $year <= 2010; $year += 10){ $endYear = $year+9; $range = "$year-$endYear"; $selected = $input->whitelist->year == $range ? " selected='selected'" : ''; echo "<option$selected value='$range'>{$year}s</option>"; } ?> </select> </p> <p><input type='submit' id='search_submit' name='submit' value='Search' /></p> </form> And here's the code that processes it and performs the search: <?php /** * This template looks for search terms as GET vars and formulates a selector to find matching skyscrapers * */ // most of the code in this template file is here to build this selector string // it will contain the search query that gets sent to $skyscraperList $selector = ''; // we use this to store the info that generates the summary of what was searched for // the summary will appear above the search results $summary = array( "city" => "", "height" => "", "floors" => "", "year" => "", "keywords" => "", ); // if a city is specified, then we limit the results to having that city as their parent if($input->get->city) { $city = $pages->get("/cities/" . $sanitizer->pageName($input->get->city)); if($city) { $selector .= "parent=$city, "; $summary["city"] = $city->title; $input->whitelist('city', $city->name); } } // we are allowing these GET vars in the format of 999, 999-9999, or 999+ // so we're using this loop to parse them into a selector foreach(array('height', 'floors', 'year') as $key) { if(!$value = $input->get->$key) continue; // see if the value is given as a range (i.e. two numbers separated by a dash) if(strpos($value, '-') !== false) { list($min, $max) = explode('-', $value); $min = (int) $min; $max = (int) $max; $selector .= "$key>=$min, $key<=$max, "; $summary[$key] = (substr($max, 0, 3) == '999') ? "$min and above" : "$min to $max"; $input->whitelist($key, "$min-$max"); // see if the value ends with a +, which we used to indicate 'greater than or equal to' } else if(substr($value, -1) == '+') { $value = (int) $value; $selector .= "$key>=$value, "; $summary[$key] = "$value and above"; $input->whitelist($key, "$value+"); // plain value that doesn't need further parsing } else { $value = (int) $value; $selector .= "$key=$value, "; $summary[$key] = $value; $input->whitelist($key, $value); } } // if there are keywords, look in the title and body fields for the words. Note in our selector // we are using the "~=" operator, rather than the "*=" operator, which means that we want to // match all the words, but they don't have to be in a phrase right next to each other. if($input->get->keywords) { $value = $sanitizer->selectorValue($input->get->keywords); $selector .= "title|body~=$value, "; $summary["keywords"] = htmlentities($value); $input->whitelist('keywords', $value); } // display a summary of what was searched for above the search results $content = "<ul id='search_summary'>"; $browserTitle = "Skyscrapers - "; foreach($summary as $key => $value) { if(!$value) continue; $key = ucfirst($key); $content .= "\n\t<li><strong>$key:</strong> $value</li>"; $browserTitle .= "$key: $value, "; } $content .= "\n</ul>"; $skyscrapers = $pages->find($selector); $content .= $skyscrapers->render(); // substitute your own output code $browserTitle = rtrim($browserTitle, ", "); $headline = "Skyscraper Search"; include("./main.php");
    1 point
×
×
  • Create New...