Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 10/20/2016 in all areas

  1. In PW you have pages, fields and templates. Each page can have multiple fields (text, textarea, checkboxes etc.), these fields are not assigned directly to the page but rather to a template. So you create the fields, create the template and assign the fields to the template. When you create a page you can choose a template, this way you tell the page to use the fields assigned to that template. The templates you create also need (need only if the template is used in front-end) a template file in /site/templates/ directory, so that when you access a page in the front-end PW uses that template file to display content. Do read some of the tutorials, as they explain this better: https://processwire.com/docs/tutorials/but-what-if-i-dont-know-how-to-code/ Don't know where you read about the bootstrap thing, but it can refer to two things bootstrap the css framework or this bootstrapping. OOP means Object Oriented Programming and PW is written using this way of programming.
    6 points
  2. Hi, We made a little help tool for implementing cron to processwire. Basically the module has two options to run module methods under cron: Lazy method: Just add simple config line to configuration field where you specify module, method and time delay Pro method: Just hook to our method and do everything you want Getting started should be relative easy, just install module and add line to configuration field (MyModule;MyMethdo;+10 minute). Delay accepts strtotime formats. http://modules.processwire.com/modules/pwcron/
    5 points
  3. Hi leegold, I know exactly what you mean: Ive been there ! So from the same experience I can say with Processwire it is like coming home, and can promise you that your search for the perfect cms is over, processwire is simply it, stick with it and you will see for your self. The first thing you should do from here is to make your self familiar with that Processwire is a decoupled system and everything "is a page" ! The back end is really a page tree that can hold anything. Took me a while but once you get your hand on this and start to connect it with the api of processwire you will see that everything makes so much sense. Processwire is unique because with it you dont make websites "the cms way" but your way ! Just start making a couple of websites following processwire tutorials: https://processwire.com/docs/tutorials/ And here are some goodies to start with: https://processwire.com/api/templates/ https://webdesign.tutsplus.com/tutorials/how-to-install-and-setup-processwire-cms--cms-25509 http://processwire-recipes.com/ http://processwire.com/talk/topic/2296-confused-by-pages/ http://processwire.com/talk/topic/5667-help-a-noob-get-started/page-2#entry55820 https://processwire.com/talk/topic/4173-grouped-forum-posts-links-articles-tutorials-code-snippets/ Welcome to Processwire.
    4 points
  4. https://www.mautic.org/blog/developer/mautic-2-2-in-good-company/
    4 points
  5. You nearly had it $results = $pages->find("template=name-of-child-template, sort=parent.field-on-parent-template");
    4 points
  6. Comparing the (ajax) request URL and the value of the Location: header sent back should normally clue you in to what is going wrong. Missing trailing slashes or missing language names in multilanguage URLs have been known culprits for such behavior, but there are probably dozens of possibilities that trigger a 301 redirect. If you pass an absolute, hard coded URL to the ajax request, a missing "www" in the domain name or a protocol mismatch (http vs https) might also lead to a redirect.
    3 points
  7. An article from April describing a strategy for deploying PW using Robo task manager http://antonioandra.de/articles/deploying-processwire-with-robo/
    3 points
  8. Hey everyone, Max from Snipcart here! We just published a full tutorial showing how to use ProcessWire + Snipcart (our dev-first HTML/JS shopping cart platform) to enable e-commerce. It was pretty much my first time playing around with the Apache/MySQL/PHP stack, so I'd love to get some feedback on the demo code. Oh, and also, if you feel like the Snipcart integration could have been done in a different/better way with ProcessWire, let me know! > Blog post tutorial > (Very) simple live demo > GitHub repo Cheers folks.
    2 points
  9. I'm really having a hard time understanding ProcessWire. I should say all CMS's I've tried I have a problem with, so it's mostly my lack. There's tutorials saying a template and a template file is different and then there's like the bootstrap template (?) It's scrambling my brains. So if I stink at design I can't use a template or is that a css framework I need , or? Then there's someone out there trying to make analogies between OOP and PW which made no sense to me. Also, I've yet to see any diagrams showing how all the components ("components" in the generic sense please) relate to each other. Just venting about my apparent lack of ability to comprehend, I'll shutup now.
    2 points
  10. Try: $mail = new \PHPMailer(); The backslash at the front tells it not to use the ProcessWire namespace
    2 points
  11. I wanted to view the contents of a JSON post in a web hook from an external application. In this instance the source application was Stripe posting event info at irregular intervals to a PW page URL. The process had to be unobtrusive. Solution was to send an email to myself. The web hook page template contained: // create a PW mail object using whatever method works for you $mail = wire()->modules('WireMailSmtp'); // Retrieve the request's body and parse it as JSON $stripe_input = @file_get_contents("php://input"); $event_json = json_decode($stripe_input); try { $body = "<pre>" . var_export($event_json, true) . "</pre>"; $mail->to('my@emailaddress.com'); $mail->from('from@emailaddress.com'); $mail->subject('test event_json'); $mail->bodyHTML($body); $mail->send(); } catch (\Exception $e) { $error = "Email not sent: " . $e->getMessage(); $mail->log($error); } Resulting email body contains nicely formatted code, eg: stdClass::__set_state(array( 'id' => 'evt_XXXXXXXXXXXXXXXX', 'object' => 'event', 'api_version' => '2016-07-06', 'created' => 1476900798, 'data' => stdClass::__set_state(array( 'object' => stdClass::__set_state(array( 'id' => 'sub_XXXXXXXXXXXXXXXX', 'object' => 'subscription', 'application_fee_percent' => NULL, 'cancel_at_period_end' => false, 'canceled_at' => NULL, 'created' => 1476900796, 'current_period_end' => 1508436796, 'current_period_start' => 1476900796, 'customer' => 'cus_XXXXXXXXXXXXXXXX', 'discount' => NULL, 'ended_at' => NULL, 'livemode' => true, 'metadata' => stdClass::__set_state(array( )), 'plan' => stdClass::__set_state(array( 'id' => 'annual', 'object' => 'plan', 'amount' => 8000, 'created' => 1474521586, 'currency' => 'usd', 'interval' => 'year', 'interval_count' => 1, 'livemode' => true, 'metadata' => stdClass::__set_state(array( )), 'name' => 'Annual', 'statement_descriptor' => NULL, 'trial_period_days' => NULL, )), 'quantity' => 1, 'start' => 1476900796, 'status' => 'active', 'tax_percent' => NULL, 'trial_end' => NULL, 'trial_start' => NULL, )), )), 'livemode' => true, 'pending_webhooks' => 1, 'request' => 'req_XXXXXXXXXXXXXXXX', 'type' => 'customer.subscription.created', ))
    1 point
  12. This is updated/version of the AdminDocsTab module as was posted here: https://processwire.com/talk/topic/11803-admindocstab/ (that one is now obsolete) https://github.com/outflux3/AdminHelp AdminHelp module for ProcessWire Processwire helper modules for managing site documentation. Currently alpha state - please use with caution and report all errors. Instructions There are 3 modules included with this: the master module holds the settings for the other 2. This is a helper module which expects you to have already setup a hidden part of your page tree* to establish your help documentation, using any template (e.g. 'help-doc') and a body field (ckeditor) (*or you can run the setup and it will create these items). The help-doc template does not need to have an output template, as the module will only echo the body field inside the admin. In addition this 'help-doc' template requires "template select" field (separate module) which should be named template_select. (if you run setup it will create this). To have a global help page, which renders all of the help docs in an accordion view, you can install the ProcessAdminHelp module, which will setup a page to view the help docs, under setup. Help Setup Module (AdminHelp) This is how the setup module looks before setup is completed: If you use the automated setup, it will create the field, templates and pages, and will auto-set the module configuration: Example Help Tab (when using AdminHelpTab) Admin Help page (ProcessAdminHelp) This shows all help docs in accordion. (it is capable of displaying child pages also but this is not currently implemented in the module due to the family settings of the default templates). Accordion opened: Features Summary: Manages settings for the help templates (help-index, and help-doc), which enabled users to add new help docs where applicable; these can already exist and be named whatever, you just specify them in the setting. Getting the help/docs tab to show up in the right place (based on user preference template selected on the help doc). Has it's own scoped CSS styling that makes the documentation readable and engaging; has some @import fonts, and also rules to make text layout look correct in PW admin (paragraphs, lists, headings, blockquotes etc.) Makes it easy for site editors to add their notes, mods/edits/enhancements to the docs (edit button - currently only enabled for Superadmin - this can be made a setting based on user feedback). Using the secondary process module will create a 'Help Docs' page under Setup where you can view all of the docs in 1 place as an accordion. (could be moved somewhere else) There is also an automated setup that can run, where it will create the field, templates, and pages for you to get started. This module is probably optimized to handle no more than 10-15 or so help pages; if you needed more than that, the Process module may need to be changed to work differently. Most sites I do need around 4-5 help pages. *If you don't want to load those extra google fonts in your admin you can modify the CSS to your needs, e.g. remove the @import and then change the few lines of css that reference those; Once there have been a few testers, I can see about adding this to the modules directory in a week or so.
    1 point
  13. Template Latte Replace Latte template engine support for ProcessWire Having wrote about this one for a few times and now here it is. The readme is not complete but should give a solid starting point. Feel free to ask if something's not clear. http://modules.processwire.com/modules/template-latte-replace/ https://github.com/rolandtoth/TemplateLatteReplace
    1 point
  14. Thought I'd show some work in progress modules. Subscribers https://github.com/benbyford/Subscribers has functions for logging in new users, added with new subscriber role bulk export the subscriber users to comma delineated SubscriberList (submodule) module adds an admin page to view your subscribers and page through them, or export WireMailChimp https://github.com/benbyford/WireMailChimp (though I need to change the name on github) Implements https://github.com/drewm/mailchimp-api adds any user save to a mailchimp list settings for API and List id only adds users that have a checked email_subscribe field to true
    1 point
  15. I'm in need of a special inputfield with multiple input form fields. I created a little Inputfield extending InputfieldTextarea and using it for storing the values as json encoded string. Seeing an example of Ryan recently using this technique I went and tried to do a little custom Inputfield. I got it working so far with a little try and error, but wanted to have feedback, if there's anything done wrong or could be done better. I need this to store numeric values for the 12 months. These will be used to render a chart on page. So I first did a simple textarea and having each values on a new line, but wanted something more intuitive and convienient for the client to enter the values. (I know it would also be possible (and maybe better solution) to write a complete new Fieldtype/Inputfield, but I'm not really into it yet and would need some help. But this was kinda simple and does the job, only drawback is that it wouldn't work with selectors as it's stored as json in a text field in db.) Here's my code: <?php /** * ProcessWire Custom InputfieldMonths * * Inputfield that stores numeric values for the 12 months of a year. * */ class InputfieldMonths extends InputfieldTextarea { protected $months = array( "January" => "jan", "February" => "feb", "March" => "mar", "April" => "apr", "May" => "may", "June" => "jun", "July" => "jul", "August" => "aug", "September" => "sep", "October" => "oct", "November" => "nov", "December" => "dec" ); public static function getModuleInfo() { return array( 'title' => 'InputfieldMonths', 'version' => 100, 'summary' => 'Stores 12 integer values for months of a year', 'permanent' => false, ); } public function init() { parent::init(); } public function ___render() { $values = json_decode($this->value,true); $out = ''; foreach($this->months as $label => $name) { $out .= <<< _OUT <p> <label for='$name'>$label</label> <input id='$name' name='$name' value='$values[$name]'/> </p> _OUT; } return $out; } public function ___processInput(WireInputData $input) { foreach($input as $key => $val) { if(!in_array($key, $this->months) or $val === '') continue; if(!is_numeric($val)) return $this->error("Wrong format. Value '$val' is not numeric!"); } $months_values = array(); foreach($this->months as $month) { $months_values[$month] = $input[$month]; } $data = json_encode($months_values); if($this->value != $data) { parent::trackChange('value'); $this->value = $data; } return $this; } }
    1 point
  16. Module: http://modules.processwire.com/modules/ajax-intercooler-js/ Repo: https://bitbucket.org/pwFoo/ajaxintercoolerjs AjaxIntercoolerJS module features integrates IntercoolerJS async CCS ("loadCSS") and JavaScript load / update optional disable async css / js handling for blocks, sidebar, ... Intercooler X-IC response header support support / hook $session->redirect multiple X-IC-Trigger handling multiple X-IC-Script handling Usage Basics It's a autoload module, but you need to enable it inside of your templates, because scripts and dependencies ("JqueryCore") have to be loaded too. You can enable / load it global inside of the TemplateFileHelper controller "_layout.php" $ic->enable(); Some changes are needed to your main template "_layout.tpl". <!-- IntercoolerJS needs a target with ID "pageContent" for (async) page content --> <div id="pageContent"><?=$pageContent?></div> And your navigation links need some IntercoolerJS attributes like that. <a href="..." ic-get-from='/url-to-load' ic-target='#sidebar'>...</a> Your just use and hook MarkupSimpleNavigation. $nav = $modules->get('MarkupSimpleNavigation'); $opts = array( 'show_root' => true, 'item_tpl' => "<a href='{url}' ic-get-from='{url}' ic-target='#pageContent' ic-push-url=true>{title}</a>", 'item_current_tpl' => "<a href='{url}' ic-get-from='{url}' ic-target='#pageContent' ic-push-url=true>{title}</a>", ); // optional modify a specific link to use another target. For example "#sidebar" $nav->addHookAfter('getTagsString', null, function($event) { $link = $event->arguments[1]; if ($link->title == 'sidebar') { $event->return = "<a href='{$link->url}' ic-get-from='{$link->url}' ic-target='#sidebar'>{$link->title} (sidebar)</a>"; } }); // render and set as _layout.tpl template var $layout->set('navigation', $nav->render($opts)); Disable CSS refresh (remove "current" styles and load the new one) The current loaded page css shouldn't removed if the sidebar is updated. So it's possible to disable the asyncHandler inside of the "sidebar" template. $ic->asyncHandler(false); Quick and dirty FrontendUser integration You just need a PW template file like that. $fu = $modules->get('FrontendUser'); $fu->login(); $button = $fu->form->fhSubmitBtn; $button->attr('ic-post-to', $page->url); $button->attr('ic-target', '#pageContent'); if (!empty($_GET['logout'])) { $fu->logout($page->url); } // Workaround until IntercoolerJS 1.0.1 release if ($input->post['ic-trigger-name']) { $input->post[$fu->form->fhSubmitBtn->name] = $input->post['ic-trigger-name']; } $processed = $fu->process($page->url); if ($processed && !$user->isGuest()) { // $processed == false if login failed (not submitted / login successful == true) echo "Hello $user->name!"; echo "<a href='$page->url?logout=1'>Logout</a>"; } else { echo $fu->render(); } X-IC Response Headers /** * Set x-ic-trigger response header * @param array $array One or more events with related data arrays */ public function trigger($array) { $json = json_encode($array); header('x-ic-trigger: ' . $json); } /** * Set x-ic-script response header * @param string $js Valid javaScript code */ public function script($js) { header('X-IC-Script: ' . $js); } /** * Stop current / parent element Intercooler polling */ public function cancelPolling() { header ('x-ic-cancelPolling: true'); } /** * Resume current / parent element Intercooler polling */ public function resumePolling() { header ('x-ic-resumePolling: true'); } /** * Set current / parent element Intercooler polling interval * @param string $interval */ public function setPollInterval($interval) { header ('x-ic-setPollInterval: ' . $interval); } /** * Set x-ic-refresh response header * @param string $pathCsv Comma separated paths to refresh. */ public function refresh($pathCsv) { header('x-ic-refresh: ' . $pathCsv); } /** * Set x-ic-open response header * @param string $url New window / tab address */ public function open($url) { header('x-ic-open: ' . $url); } /** * Set x-ic-redirect response header * @param string $url Redirect destination address */ public function redirect($url) { header('x-ic-redirect: ' .$url); } Wrapper for X-IC-Trigger Add a event trigger with event name ($event) and parameters array ($array). "addTrigger()" method is a wrapper for usage with multiple event triggers. Native method for a single execution is method "trigger()" $ic->addTrigger($event, $array); Wrapper for X-IC-Script String of javascript code for client side execution. "addScript()" method is a wrapper for multiple usage of "script()" method. $ic->addScript($javascript); $session->redirect is hooked! The module hooks $session->redirect() method for ajax calls. It's needed to execute redirects by IntercoolerJS X-IC-Redirect for ajax calls. Used for the FrontendUser integration.
    1 point
  17. Module: http://modules.processwire.com/modules/template-file-helper/ Repo: https://bitbucket.org/pwFoo/templatefilehelper/overview TemplateFileHelper module features add global controller and template to current page by a Page::render hook Manage global ($layout) and current page ($view) styles and scripts with a $config->scripts / $config->styles context mapping. So $config->styles / $config->scripts works fine too load sub-templates with a controller file an array of data to fill template variables just an html template Ajax page load in mind Usage Global layout A global controller / template is added by a Page::render hook. /site/templates/_layout.php // controller /site/templates/_layout.tpl // view / html template Example _layout.tpl <!doctype html> <html lang="de"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TemplateFileHelper Processwire</title> <?=$styles?> <?=$scripts?> </head> <body> <div id="nav"><?=$navigation?></div> <div id="pageContent"><?=$pageContent?></div> </body> </html> Example _layout.php // MarkupSimpleNavigation $nav = $modules->get('MarkupSimpleNavigation'); $layout->set('navigation', $nav->render($opts)); // Global and current page styles $styles = ''; foreach ($layout->styles as $style) { $styles .= "<link href='{$style}' rel='stylesheet' class='global'>"; } foreach ($view->styles as $style) { $styles .= "<link href='{$style}' rel='stylesheet' class='current'>"; } $layout->set('styles', $styles); // Global and current page scripts $scripts = ''; foreach ($layout->scripts as $script) { $scripts .= "<script src='{$script}' type='text/javascript' class='global'></script>"; } foreach ($view->scripts as $script) { $scripts .= "<script src='{$script}' type='text/javascript' class='current'></script>"; } $layout->set('scripts', $scripts); Current page The PW template of current page will rendered inside the global view by Page::render hook. /site/templates/basic-page.php // controller /site/templates/basic-page.tpl // view / html template Example basic-page.tpl <div><?=$contentHome?></div> Example basic-page.php $view->set('contentHome', 'Simple output...'); echo $view->render(); Output (for example to debug) is possible too. echo "My PW template file output..."; $view->set('contentHome', 'Simple output...'); echo $view->render(); Sub-templates It's possible to use sub-templates / chunks inside of a PW template / controller. Sub-template with controller / view files $part = $view->load('parts/test1', 'parts/test1'); // relative to /site/templates (view = .tpl, controller = .php $part = $view->load('parts/test1', true); // same as above. "True" instead of write identical path / file twice $part = $view->load('parts/test1', 'parts/test1_controller'); // view "parts/test1.tpl", controller "parts/test1_controller.php" Sub-template with array data $part = $view->load('chunks/test1', array('variable1' => "value1", 'variable2' => 'value2')); Sub-template just a html chunk $part = $view->load('chunks/test1'); // view file /site/templates/chunks/test1.tpl PW template file as view Because direct output inside a PW template file is possible it also works without a view. Example: PW template without viewTested with the FrontendUser module quick and dirty... $fu = $modules->get('FrontendUser'); $fu->login(); $button = $fu->form->fhSubmitBtn; if (!empty($_GET['logout'])) { $fu->logout($page->url); } $processed = $fu->process($page->url); if ($processed && !$user->isGuest()) { // $processed == false if login failed (not submitted / login successful == true) echo "Hello $user->name!"; echo "<a href='$page->url?logout=1'>Logout</a>"; } else { echo $fu->render(); } Scripts / Styles context The module itself takes care about the global (inside _layout.php) and "current" (inside PW template file). Just use PW $config to set styles and scripts. $config->scripts->add('...'); $config->styles->add('...'); You can also force the context by use the additional global api variables. $layout->scripts->add('...'); // global context $layout->styles->add('...'); // global context $view->scripts->add('...'); // current page context $view->styles->add('...'); // current page context
    1 point
  18. Still very fresh, but I thought... what the hell... spread the PW love and give you guys a first look... https://music-room.com This was a huge project. Still lots of debugging to do, but early feedback most welcome! Don't look at the code (particularly the js)... it's a bit of a garbled mess! Ha ha! Need to, ahem, refine it over the coming weeks and months. Haven't made the jump to PW3 yet as I'm using a few modules which don't work out of the box. Thanks again to Ryan for everything. Also, big thanks to Antti for his wonderful PadLoper module. Cheers and happy browsing! Douglas.
    1 point
  19. Your web server should be configured to have a single canonical domain to avoid fragmentation of SEO and analytics, and your sitemap should use it. If the "www" version of the domain is canonical, requests for sitemap.xml will be redirected to that domain and the generated links should match. The module simply uses the value of $page->httpUrl. ProcessWire's .htaccess file includes directives for Apache to set a canonical domain, but they are commented out by default. Look around line 123: # ----------------------------------------------------------------------------------------------- # 13. OPTIONAL: Redirect users to the 'www.' version of the site (uncomment to enable). # For example: http://processwire.com/ would be redirected to http://www.processwire.com/ # ----------------------------------------------------------------------------------------------- # RewriteCond %{HTTP_HOST} !^www\. [NC] # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    1 point
  20. Yes, we just forget to put tap in place.
    1 point
  21. Hi BitPoet and thank you for your reply. Your suggestion was good, I have found the problem.... first of all, it was because of multilanguage option and second, I did not want to load the entire counter page and I was requesting the page path using $page->getPath(id), which it seems it does not works as I imagined in multilanguage sites, it does not get automatically the url for a particular language....
    1 point
  22. <shameless advertisement>I use PIA with $image->contain("size=200"); It respects upscaling and weighten too.</shameless advertisement>
    1 point
  23. Thanks Robin, exactly what I needed. Works like a charm.
    1 point
  24. Hi @Robin S I can confirm that this method has unexpected behavior. Not sure, but I think that this: public function maxSize($width, $height, $options = array()) { $w = $this->width(); $h = $this->height(); if($w >= $h) { if($w > $width && $h > $height) { return $this->size($width, $height, $options); } else { return $this->maxWidth($width, $options); } } else { if($w > $width && $h > $height) { return $this->size($width, $height, $options); } else { return $this->maxHeight($height, $options); } } } should be public function maxSize($width, $height, $options = array()) { $w = $this->width(); $h = $this->height(); if($w >= $h) { return $this->maxWidth($width, $options); } else { return $this->maxHeight($height, $options); } }
    1 point
  25. Hi Andreas, You'd have to ask Mike Johnston (@cmscritic) of CMS Critic that question. J
    1 point
  26. @gRegor - not sure if you already tried the Admin Help module, which is basically a documentation system that runs inside PW admin; one of the sub-modules is a process module that displays all of the documentation in an accordion page view...
    1 point
  27. http://foundation.zurb.com/emails.html (Formerly Ink) http://tedgoas.github.io/Cerberus/
    1 point
  28. Hi Jan, thanks for passing by and answer the question. Padloper is a great eCommerce platform for PW built by a really talented dev from the forums. Just thought I should let you know
    1 point
  29. It doesn't have a shopping cart--at least not that I'm aware of. Most of the reservation page is custom forms / code and such. We have been expanding and tweaking the reservation form for over 6 years and it is available in English, Spanish, and Portuguese. Also, Ryan gets a ton of email so he doesn't always respond. To get his attention I usually have to send him text messages. Not sure about padlooper...I've never heard that word. I'm happy to answer other questions. Jan CTO Tripsite.com
    1 point
  30. The theory is to call the init fx after the field is rendered, no matter if its Ajax loaded or inside a tab, etc. A script tag appended to a field would run when the field Dom is ready. I haven't tested this in this particular case so it may fail somewhere, but in another module I made (not public) I went on this way and it solved all the timing/loading issues I had.
    1 point
  31. Done did it: public function init() { $this->addHookAfter('Page::render', $this, 'styling'); $this->addHookAfter('Page::render', $this, 'filterFieldFields'); } protected function styling(HookEvent $event) { $page = $event->object; $edid = $this->pages->get($this->input->get->id); if(!($page->process = 'ProcessPageEdit' && $edid->template = 'importupdate')) return; $css = wire('config')->urls->ImportUpdateUltimate . 'ass/edit_importupdate.css'; $event->return = str_replace("</head>", "<link rel='stylesheet' type='text/css' href='{$css}'/>\n</head>", $event->return); } protected function filterFieldFields(Hookevent $event) { $page = $event->object; $edid = $this->pages->get($this->input->get->id); if(!($page->process = 'ProcessPageEdit' && $edid->template = 'importupdate')) return; if($edid->iu_template) $tpl = wire('templates')->get((int) $edid->iu_template[0]); else $tpl = null; $fields = []; if($tpl != null) { foreach ($tpl->fields as $f) { $fields[] = $f->id; } $fstring = '[' . implode(',',$fields) . ']'; } else $fstring = '[]'; $js = <<<EOT <script> $(document).ready(function(){ var arr = $fstring; var def = '<option value=""></option>'; if (arr.length) { $('#Inputfield_iu_match option').each(templateFieldOptions); $('#wrap_Inputfield_iu_fieldmap select option').each(templateFieldOptions); $('#_Inputfield_iu_maptab').click(function() { $('#wrap_Inputfield_iu_fieldmap select option').each(templateFieldOptions); }); } else { clearFieldOptions(); } $('#wrap_Inputfield_iu_template .asmListItemRemove').click(clearFieldOptions); function templateFieldOptions() { var val = parseInt(this.value); //console.log(typeof(val)); if (!arr.includes(val) && val>0) { //console.log(val); $(this).prop('selected',false); $(this).prop('disabled',true).remove(); } } function clearFieldOptions() { $('#Inputfield_iu_match').html(def); $('#wrap_Inputfield_iu_fieldmap select').each(function() { $(this).html(def); }); } }); </script> EOT; $event->return = str_replace("</body>", "{$js}</body>", $event->return); }
    1 point
  32. Glad you like the design. Thank you! You mean publish the PHP? Oh no, I couldn't possibly publish that, not until I cleaned it up.
    1 point
  33. Is /usr/bin/php in fact a client sapi build? Is there a /usr/bin/php-cli (or php5-cli) binary on the live system that you can call from cron instead?
    1 point
  34. $designers_person = $pages->find("parent=/designers/, designers_lastname!=''")->each(function($designer){ $designer->custom_sort = $designer->designers_lastname; }); $designers_group = $pages->find("parent=/designers/, designers_lastname=''")->each(function($collective){ $collective->custom_sort = $collective->title; });; $all = $designers_person->add($designers_group)->sort('custom_sort');
    1 point
  35. First of all I would like to say: Great job @Jonathan Lahijani for bringing CMS Critic back to ProcessWire. I first discovered PW through CMS Critic, so I'm thankful, that they awarded 2014 ProcessWire as Best Free PHP CMS. But I recently wondered, that a so-called "CMS review" site hasn't covered the release of PW3 at all? Is there any particular reason for this or am I just missing something? Regards, Andreas
    1 point
  36. Of course that would be a good idea! I am going to be away for the next two weeks, but I'll add it to my list to do when I get back. Thanks for the suggestion!
    1 point
  37. Thanks @adrian for this module. It would be great if it supports multilanguage depending on the browser language. F.e. if the browser fits one of the installed languages then show the message in this language, otherwise show the default language.
    1 point
  38. Front-end editing works okay for me when using $page->render(). If you are using "Option A" for front-end editing make sure you have selected "Fields editable regardless of page". But a couple of observations: 1. Do you really need to be rendering pages? Can you not just get your pages into a PageArray and iterate over them, echoing the fields you want? $items = $pages->find("template=my_template"); foreach($items as $item) { echo "<h3>$item->title</h3>"; echo $item->body; // etc } If you're sure you need to render you might be better off using $files->render() as it is better documented than $page->render(). 2. In your code... ...you are overwriting the core API $modules variable. You should choose a different name for your variable.
    1 point
  39. Hi! I just pushed a new bunch of updates for PW 3.0.36 and drafted a new release. We are slowly reaching 100 % Any fixes or additions are welcome! Have a nice weekend!
    1 point
  40. I guess what you are saying here is if you set the "Estimated End of Maintenance" to a very short time from now, then the Retry-After timestamp will be changing constantly as soon as that initial timestamp point is reached. Is that what you mean but "without a fixed timestamp"? I see that the Retry-After actually allows specifying a timestamp or a delay in seconds, but a constantly changing timestamp would essentially be the same as the "seconds delayed" approach?
    1 point
  41. Many thanks @adrian, now I'm back again in regular update process with the module. Yep! --------------------- I think only search bots will act according to retry-after. I have read on Googles advices on how they like to see handled maintenance mode for already indexed sites. And it was a 503 with a "retry-after" . If the estimated timestamp is passed, I added 60 minutes to the current time and sends this. Maybe, you can add this to the explanation, that one can check "send retry-after" but without a fixed timestamp too? This way we have enough possibilities, I think.
    1 point
  42. Ok, I have committed the new version. A huge thanks to @horst for contributing this functionality. Here are the key new sections to the module config: @Christophe - just pinging you to make sure you see this new functionality.
    1 point
  43. On a site that is always protected, it simply doesn't matter. But on a site, where I regularly only use some single protected pages but a big part is publicly accessible, there it is better to use SEO friendly headers when closing the whole site. It is important for sites that are already indexed, and temporarily are not accessible. That's why you thought it belongs to Petes module. But when I already have installed ProtectMode and it can close down the whole site, I have maintenance mode already, or not? Maybe best solution would be to offer both methods for the root page? Radio or something else for: protect | maintenance, plus a datetime via showIf for maintenance?
    1 point
  44. I thought I should post my implementation based on Bernhard's code. It tries to work out the length of the first tag and modifies the ->asXML parameters accordingly. The Import Code is as follows : class ImportFromXML { private $file; public function __construct($file) { $this->file = $file; } public function Execute() { $import = true; $xmlFile = $this->file; if ($import) { if (!file_exists($xmlFile)) exit($xmlFile . ' failed to open'); $items = simplexml_load_file($xmlFile); foreach ($items as $xml) { $p = new \Processwire\Page(); //$p = new \Page(); $p->of(false); $p->template = wire(templates)->get("id=" . $xml->template); $p->parent = wire(pages)->get("id=" . $xml->parent); $p->title = $xml->title; //Struggle to call Sanitizer $p->name = wire(sanitizer)->pageNameUTF8($xml->title, true); $p->name = $xml->title; //while ($xmls->find('parent=' . $p->parent . ',name=' . $p->name)->count() > 0) $p->name .= '-1'; //$p->content = $this->PopulateContent($xml->content); $p->content = $this->PopulateMarkup($xml->content); //$p->content_intro = $this->PopulateIntro($xml->content_intro); $p->content_intro = $this->PopulateMarkup($xml->content_intro); $p->author = $xml->author; $p->content_path = $xml->content_path; $p->seo_title = $xml->seo_title; $p->seo_keywords = $xml->seo_keywords; $p->seo_description = $xml->seo_description; $p->seo_image = $xml->seo_image; $p->seo_custom = $xml->seo_custom; $p->image = $xml->seo_custom; $p->image_alt = $xml->image_alt; $p->keywords = $xml->keywords; $p->title_nav = $xml->title_nav; $p->seo_section_title = $xml->seo_section_title; //$p->save(); // try creating PageArray first ???? //$cats = new \PageArray(); $cats = new \Processwire\PageArray(); foreach ($xml->category->id as $id) { //$cat = wire(pages)->get("name='" . $catname . "', parent='/Categories/'"); $pageid = (string) $id; $cat = wire(pages)->get($pageid); if (!IsNullPage($cat)) $cats->add($cat); //$p->categories->add($cat);- } $p->category->import($cats); $p->save(); echo 'new page <a href="' . $p->editUrl . '" target="_blank">' . $p->path . '</a><br>'; } //die(); } } private function PopulateMarkup($node) { $xml = $node->asXML(); //Check for tags if($xml != strip_tags($xml)) { //$startTag = strpos($node,"<"); $endTag = strpos($xml,">"); if ($endTag > 0) return substr($xml, $endTag+1, -1*($endTag+2)); } return $node; } } And the Export : class ExportToXML { private $pages ; public function __construct($pages) { $this->pages=$pages; } public function Execute() { $import = true; if($import) { echo "<?xml version='1.0' ?>"; echo '<pages>'; //$parent = $pages->get('/blog'); $results = $this->pages; //$results = $pages->find('id=3198'); // ohne pic //$results = $pages->find('id=3204'); // mit pic foreach($results as $p): $p->of(false); ?> <page> <name><?= $p->name ?></name> <title><?= $p->title ?></title> <template><?= $p->template->id ?></template> <parent><?= $p->parent ?></parent> <category><?php foreach($p->category as $category) { echo '<id>' . $category->id . '</id>'; } ?></category> <content><?= $p->content ?></content> <content_intro><?= $p->content_intro ?></content_intro> <author><?= $p->author ?></author> <content_path><?= $p->content_path ?></content_path> <seo_title><?= $p->seo_title ?></seo_title> <seo_keywords><?= $p->seo_keywords ?></seo_keywords> <seo_description><?= $p->seo_description ?></seo_description> <seo_image><?= $p->seo_image ?></seo_image> <seo_custom><?= $p->seo_custom ?></seo_custom> <seo_canonical><?= $p->seo_canonical ?></seo_canonical> <image><?= $p->image ?></image> <image_alt><?= $p->image_alt ?></image_alt> <keywords><?= $p->keywords ?></keywords> <title_nav><?= $p->title_nav ?></title_nav> <seo_section_title><?= $p->seo_section_title ?></seo_section_title> </page> <?php endforeach; echo '</pages>'; //die(); /** * <date><?= $p->created ?></date> <featured>1</featured> */ } } } In particular, I had a field that was a PageArray linking to other Pages. <category><?php foreach($p->category as $category) { echo '<id>' . $category->id . '</id>'; } ?></category> Hope it helps some one out!
    1 point
  45. A jquery countdown lib is used. Add a date field of your desired template which want to display a countdown widget. I added following code on a event template <?php // convert a php unix timestamp to a javascript datetime format $js_datetime = $page->end_date * 1000; $today = date("U"); $end_date = date('d M Y', $page->end_date); $out = ''; $out = "{$page->body}<br/>"; $out .= "Event ending date: {$end_date}<br/>"; if ($today > $page->end_date) $out .= "<h3>Event is ended.</h3>"; else { $js = ''; $js .= "<script src='{$config->urls->templates}assets/js/jquery.plugin.js'></script>\r\n"; $js .= "<script src='{$config->urls->templates}assets/js/jquery.countdown.js'></script>\r\n"; $js .= "<script>$(function(){endDay = new Date({$js_datetime});$('#Countdown-widget').countdown({until: endDay});});</script>"; $out .= "<div id='Countdown-widget' class='clearfix'></div>"; } $page->body = $out; include('./main.php'); In the main.php output file, echo the $js variable, something like <?php if ($js) echo $js; ?> Some screenshots Usage: With this minimal bare bone code, you could extend and add your functionality. For example, build a groupon like time limited group order page, an online event registration form
    1 point
  46. As I understand it, you have different items the same editorial (as a text field), and you want to get an array with unique editorils, right? If so, here is the code to get this: $editorials = array(); $lastEditorial = null; foreach ($pages->find("template=item, editorial!='', sort=editorial") as $item) { if ($item->editorial !== $lastEditorial) $editorials[] = $item->editorial; $lastEditorial = $item->editorial; } $a->unique() filters elements using the PHP array_unique function, which compares elements according to their string representation. Since the result of $pages->find() returns a PageArray containing Page objects, and since the string representation of a Page object is its id, $pages->find(...)->unique will return unique pages, without considering the editorial field (two different pages with the same editorial will be different, since they will have different ids). That's why $a->unique isn't usable in your case.
    1 point
  47. Basicly you have one folder for templates by default. This is configured to be in "site root" + templates/ You are able to overrule this setting from the site/config.php as follow $config->urls->templates = $config->urls->site . 'mytemplates/'; $config->paths->templates = $config->paths->site . 'mytemplates/'; A trick i use a lot when developing in a live site is to duplicate the template folder and rename the copy to templates-dev. Then make sure i have an other domain (or subdomain) pointing to the hosting, for example dev.domain.ext and for the live site on www.domain.ext With the following code i can access the development templates while normal visitors keep getting the default templates. /** * Development: Alias for template-dev access * */ if($_SERVER['HTTP_HOST'] == 'dev.domain.ext') { $config->urls->templates = $config->urls->site . 'templates-dev/'; $config->paths->templates = $config->paths->site . 'templates-dev/'; $config->debug = true; } You can make up all kind of 'rules' to go by when overruling the templates folder with php from the config.php file. For example serving the same site with different layout and code for mobile on m.domain.ext /** * Mobile: Alias for template-mobile access * */ if($_SERVER['HTTP_HOST'] == 'm.domain.ext') { $config->urls->templates = $config->urls->site . 'templates-mobile/'; $config->paths->templates = $config->paths->site . 'templates-mobile/'; }
    1 point
  48. Hey, there are a lot of modules using submodules recently which is great in my opinion because it underlines the way Processwire works. Examples are for example: Apeisa's Payment and Shipping modules, netcarver's new ProcessDiagnostic module and Adrian's ProcessMigrator. All of them are using more or less different approaches - abstract classes, etc - and I'm not sure which is best. But I think a core support for submodules could be a nice addition. One way to do it could be a "parent-module" setting in submodule's "module config" and a "getSubmodules" function in parent classes. Maybe you could add an abstract class like done with ConfigurableModule for this reason (e.g. ParentModule). Additionally apeisas way to use a abstract class would stay possible but wouldn't be necessary with this approach. What do you think? -- Nico
    1 point
  49. Table Use this for tabular data, like rate tables or other things that you might typically represent in a spreadsheet. Use it for situations where you don't need the full-blown flexibility of repeaters, as it's technically more efficient with far less overhead than repeaters. Something like the Events Fieldtype could be very easily re-created via a Table field, but the potential uses are far broader. But for the most part, think tabular data when it comes to the Table field. Multipliers This is good for when you need a range of values (whether text, textarea, numbers, dates, etc.). If you are using repeaters with just one field in them, you might be a lot better off with a Multiplier. Like the Table field, Multipliers are very efficient and low overhead relative to something like Repeaters. Use Multipliers when you need to repeat a single input multiple times, optionally with a min and max number of inputs. Lets say you are building an employee directory, and each employee has between 1 and 3 email addresses. Rather than using 3 separate email fields, you would use 1 multiplier field and specify min=1 and max=3. Repeaters These are infinitely flexible in terms of what they represent, but each row of values is technically a page in the system. As a result, with the flexibility comes significant overhead. This is really only an issue when the quantity of repeater items gets high, or when you have lots (thousands) of pages using repeaters. I recommend repeaters for setting up things like homepage carousels. For example, if you go to the Villas of Distinction homepage, there are 3 separate repeaters in use on that page, each holding a photo, title, description, link. The client can have as many items in each of those sections as they want. Currently it looks like the first repeater as 6 items, the 2nd has 2, and the 3rd has 6. The possibilities of what can be represented with repeaters is endless, but look for potential alternatives when dealing with large quantities (whether large quantities of repeater items, or large quantities of pages using repeaters). PageTable This is one of the ProFields that is available for free (thanks to Avoine sponsorship) on the ProcessWire dev branch. Meaning, it'll be available for everyone to use as part of the core in ProcessWire 2.5. And you can use it now if you don't mind running the dev branch. PageTable has all the flexibility of repeaters, but with lower overhead from the admin/input perspective. Rather than trying to bundle all the inputs on one screen, PageTable shows you a table of items and you click on the item to edit it in a modal window. This enables it to be a lot more efficient from the admin UI perspective. It's also more flexible than repeaters are in terms of where you store your items. PageTable lets you choose where they should live, whether as children of the page being edited, or as children of some other parent page you designate. They might be a little more work to setup than repeaters, but I think that most situations where you need the flexibility of repeaters may be better served by PageTable. PageTable still can't compete with the speed and efficiency of Table or Multiplier, but consider using PageTable anywhere that you might have used Repeaters before. Repeaters and PageTable are fundamentally different from the admin UI/input perspective, so you'd want to compare them yourself to see what suits your individual input needs better. PageTable involves more clicking to create and edit items, making Repeaters potentially faster for entering data rapidly. But PageTable will scale much further in the admin UI than Repeaters will, so I would personally favor PageTable in more situations than Repeaters.
    1 point
×
×
  • Create New...