Jump to content

Leaderboard

Popular Content

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

  1. To extend upon what LostKobrakai said, by basic understanding of PHP, I would say: how to set variables how to use the if control structure how to loop through an array (foreach) how to output something (echo) Those basic concepts apply for any programming language and will be heavily used in your templates. Master those with PW's easy API and you'll be like 80% of the way there.
    5 points
  2. Hello Everyone. This is not Strictly just about Processwire, but its something i use with a Processwire website that i created. It´s just a simple little Anti-spam protection system i use to make it more difficult for simple bots to mess around with a contact form on the said website. it seems to be working pretty well. The system is very simple, let me explain. Step 1 In the template file for the contact form have this code: <?PHP /* create a random integer.*/ $sendFormInteger = mt_rand(1000,9999); /* save the integer to session var using PW API or just go PHP vanilla */ $session->set('antispam_code', $sendFormInteger); ?> As you can see we just create a 4 digit integer and save it to a session var using Processwire $session API. https://processwire.com/api/variables/session/ Step two Also in your form have for example a label that display the code we created above, so the poster has to manually fill it out in a form field. For example like this: <label for="antispam_code">Anti spam code: <strong><?PHP echo($session->get('antispam_code')); ?></strong></label> <input type="text" name="antispam_code" value="" class="" placeholder="Fill in antispam code here" /> We simply echo out the code we saved in the session var into the label so the user can read it and then fill it out into our form field below the label. Step Three In the file or template that receives the form data put in a simple check like bellow: <?PHP /* sanitize our data and make sure its a integer */ $antispam_code = $sanitizer->int($input->post->antispam_code); /* check if the code we saved in the session var is equal to the one filled in the form and sent to us */ if($session->get('antispam_code') == $antispam_code) { /* if antispam code correct then delete it and go on */ $session->remove('antispam_code'); } else { /* if code is NOT correct then do something else */ } ?> More info on $sanitizer API: https://processwire.com/api/variables/sanitizer/ Just thought i share this technique with you all. I have no doubt that you could easily come up with something more advanced then a 4 digit integer that i use. My anti-spam system is set up so that it creates a new code everytime the form template is loaded. So it should be hard to guess unless they make the bot read the HTML and find the code in the label and make the bot fill out the correct form field before sending it. Happy coding.
    4 points
  3. .. resolved the issue in less than three minutes, yesterday I was too lazy to take a closer look (in other words: my battery was empty). Edit php.ini, to avoid this warning set 'always_populate_raw_post_data' to '-1', restart php and the message is gone ; Always populate the $HTTP_RAW_POST_DATA variable. PHP's default behavior is ; to disable this feature and it will be removed in a future version. ; If post reading is disabled through enable_post_data_reading, ; $HTTP_RAW_POST_DATA is *NOT* populated. ; http://php.net/always-populate-raw-post-data always_populate_raw_post_data = -1 Before: <br /> <b>Deprecated</b>: Automatically populating $HTTP_RAW_POST_DATA is deprecated and will be removed in a future version. To avoid this warning set 'always_populate_raw_post_data' to '-1' in php.ini and use the php://input stream instead. in <b>Unknown</b> on line <b>0</b><br /> <br /> <b>Warning</b>: Cannot modify header information - headers already sent in <b>Unknown</b> on line <b>0</b><br /> [{"error":false,"message":"Added file: body.png","file":"\/site\/assets\/files\/1\/body.png","size":26952,"markup":"\n\t<li id='file_60984d6634e55217fe6424485038dd7d' class='InputfieldFileItem InputfieldImage ui-widget'>\n\t\t<p class='InputfieldFileInfo InputfieldItemHeader ui-widget ui-widget-header ui-helper-clearfix'>\n\t\t\t<span class='HideIfSingle HideIfEmpty InputfieldFileDrag'><i class='fa fa-sort'><\/i> <\/span>\n\t\t\t<i class='fa fa-caret-right InputfieldFileDrag HideIfMultiple'><\/i> \n\t\t\t<label class='InputfieldFileDelete'><input type='checkbox' name='delete_images_60984d6634e55217fe6424485038dd7d' value='1' title='Delete' \/><i class='fa fa-fw fa-trash'><\/i><\/label>\n\t\t\t<a class='InputfieldFileMove InputfieldFileMoveBottom' href='#' title='Move to bottom'><i class='fa fa-fw fa-angle-double-down'><\/i><\/a> \n\t\t\t<a class='InputfieldFileMove InputfieldFileMoveTop' href='#' title='Move to top'><i class='fa fa-fw fa-angle-double-up'><\/i><\/a> \n\t\t\t<a class='InputfieldFileName pw-modal pw-modal-large' title='body.png: body.png (720x101)' href='\/processwire\/page\/image\/edit\/?id=1&file=1,body.png&rte=0&field=images' data-buttons='#non_rte_dialog_buttons button' data-autoclose='1' data-close='#non_rte_cancel'>body.png <i class='fa fa-pencil ui-priority-secondary'><\/i><\/a> \n\t\t\t<span class='InputfieldFileStats'>26 kB, 720x101 <\/span> \n\t\t<\/p>\n\t\t<div class='InputfieldFileData ui-widget ui-widget-content'>\n\t\t\t<div class='InputfieldImagePreview'>\n\t\t\t\t<a class='InputfieldFileLink' target='_blank' href='\/site\/assets\/files\/1\/body.png?nc=10'><img height=\"100\" src=\"\/site\/assets\/files\/1\/body.0x100.png?nc=1455052838\" alt=\"\" data-gridsize=\"100\" \/><\/a>\n\t\t\t\t<div class='InputfieldImageActions'>\n\t\t\t\t\t<a title='body.png (720x101)' href='\/processwire\/page\/image\/edit\/?id=1&file=1,body.png&rte=0&field=images' class='pw-modal pw-modal-large' data-buttons='#non_rte_dialog_buttons button' data-autoclose='1' data-close='#non_rte_cancel'><i class='fa fa-fw fa-crop'><\/i><\/a>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t\t<div class='InputfieldFileDescription'><label for='description_images_60984d6634e55217fe6424485038dd7d' class='detail'>Description<\/label><input type='text' name='description_images_60984d6634e55217fe6424485038dd7d' id='description_images_60984d6634e55217fe6424485038dd7d' value='' \/><\/div>\n\t\t\t<input class='InputfieldFileSort' type='text' name='sort_images_60984d6634e55217fe6424485038dd7d' value='2' \/>\n\t\t<\/div>\n\t<\/li>","replace":false,"overwrite":0}]
    4 points
  4. It would be fantastic if we could set different configurations for CKEditor fields based on template or user roles. Like described on https://weekly.pw/issue/14/ under "More CKEditor upgrades", we can use config files in /site/modules/InputfieldCKEditor/ to store settings per field. E.g. for the body field this would be /site/modules/InputfieldCKEditor/config-body.js. Maybe this logic could be extended to something like /site/modules/InputfieldCKEditor/config--field-body--template-home--role-mycustomrole.js. I was coming over from Joomla to PW couple of years ago and there we had an excellent CKEditor integration called JCE where you could define settings per user role etc. Maybe I am wrong but up to now we need to create additional fields if we need editor config settings per template. If there already is a way to do that I'd be happy to know.
    3 points
  5. I went through the following free course which was easy to follow and didn't take long. It has most areas covered and allowed me to understand the PW API and templates. https://www.codecademy.com/learn/php
    2 points
  6. Also too many premium-rate phone number scams doing the rounds.
    2 points
  7. Just adding my two cents here. Or "kronor" in my case cause i am from sweden. Anyways... I have allways made my own Slider implementation using the excellent Flickity slider from http://flickity.metafizzy.co/ It´s really great and easy to work with. Many config options and great support. I would just render out each image from the image field type and then use the built in crop or resize methods for thumbnails.
    2 points
  8. @EyeDentify, @Videokid is trying to make sure that there is only one count per visit (Your version counts pages refreshes, for instance), but I think his version also falls short because it prevents the following pages on the same session to be counted For @Videokid idea to work, you would have to check a combination of session and page, and not only the session. I don't have time to come up with it now, sorry for that, EDIT: Oh, the solution already accounts for that ($key = "visit_counter".$page->id;). I have to look better at the code before talking
    2 points
  9. 1 Jan 1970 is the start of the Unix epoch. As you are no doubt aware, date/times are stored in the db as seconds after that point. Haven't looked into it too deeply, but I should imagine that refers to UTC (broadly equivalent to GMT), so at 0 seconds UTC your time zone will be sometime on 31 Dec 1969. tldr; the db is returning 0.
    2 points
  10. Hi Zen Welcome to the forums. Since this is a public forum, it is probably not a good idea to share your phone number. Secondly, you are unlikely to get many replies as people typically respond better if you supplied an email address or requested them to PM you for further details. In addition, this is an international community and the phone number you've provided doesn't specify an international dialling code. In case you haven't seen it already, please have a look at this board's posting guidelines for some helpful hints.
    2 points
  11. JqueryFileUpload This module is a ProcessWire implementation of the awesome Blueimp jQuery File Upload plugin. Server-side, the module provides a custom uploads' handler enabling you to perform various tasks with ease. The module is an interface of the feature-rich Ajax File Uploads widget provided by the jQuery File Upload plugin. The module is completely customisable and can be used both in the front- and backend (e.g. in a third-party module). Please read the README carefully and completely before using the module Release Status: Stable. Module Download: http://modules.processwire.com/modules/jquery-file-upload/ Issues tracker Project page: GitHub Security The module has been written with security in mind and makes no assumptions about any client-side validation. Instead, the module provides robust server-side validation of uploaded files. Server-side, no Ajax requests are honoured unless specifically set via configurable options server-side. This means that client-side requests to upload, delete and list files are not executed unless allowed server-side. By default, files are uploaded to a non-web-accessible (system) folder and files previously uploaded on the server are not sent back for display unless that setting is enabled. However, developers are still strongly advised to implement any other feasible measures to guard against malicious uploads, especially if allowing frontend uploading. For instance, developers can use native ProcessWire checks to limit access to the widget (e.g. only allowing uploads by registered/logged-in users). Demo A short video demo can be found here (and below )(CSS is WIP! ). In the backend, you can see it in action within the (upcoming) module Media Manager Features Fast Ajax uploads. Client and server-side validation. Client-side image resizing (highly configurable options). Beautiful touch-responsive image gallery preview. Audio and video previews pre-upload. Chunked and resumable file uploads (currently client-side only; server-side handling planned). Drag and drop support. Copy and paste support (Google Chrome only). Progress bars. Cross-domain uploads. Single or multiple uploads. Delete uploaded files. Documentation On GitHub. Have a look at the long list of available options. License Released under the MIT license @Credits: Sebastian Tschan @Thanks: Pete and BernhardB for the idea. Please test and provide feedback. Thanks!
    1 point
  12. Wire Queue Wire Queue is a module that allows easy creation and usage of Queues in ProcessWire. It is based upon a basic parent module (WireQueue) that should have one or multiple StorageHandler modules installed too. This beta release contains a simple plain text storage module, WireQueueTextfile, and a simple Sqlite3-DB storage module, WireQueueSqlite3. The base module creates the needed: FIELDS (wire_queue_type, wire_queue_state, wire_queue_storage_options) TEMPLATES (wire-queue-container, wire-queue-storage, wire-queue-tools) PAGES (wire-queues = container for all Queuepages, wire-queue-storages = container for StoragetypePages) ROLE (wire-queue-admin) Each storage module creates one page under wire-queue-storages. New Queues can be created in the backend by adding a new page under "Wire Queues". After creation one have to select a Storage type from availables list and publish the page. After that, there are some buttons available to start / pause / and close the queue. Putting and getting data to and from the queue is done via API calls. First you have to get the page that holds the queue object. // get and validate the queue handle if($queue = $pages->get(SELECTOR_TO_DESIRED_PAGE)->wireQueue()) { // wrap your data into an array and pass it into the queue $success = $queue->addItem($data); ... } // get and validate the queue handle if($queue = $pages->get(SELECTOR_TO_DESIRED_PAGE)->wireQueue()) { $data = $queue->getItem(); ... } Thats basically all what you want from a queue. Following are a few conveniences: $queue->getPage()->title gives you the title of the queue, ($queue->getPage() returns the page object) $queue->className() shows the StorageType of the queue $queue->getState() and $queue->getStateStr() returns the current state of a queue: 1 = new / empty 2 = enabled / running 3 = paused 4 = closed / archived $queue->itemCount() gives the total number of all pending items in the queue Here is code that gives an overview of all Queues in the system: $container = $pages->get('template=wire-queue-container'); $bodyContent = "<h1>$container->title</h1>"; $bodyContent .= "<p>There are currently {$container->numChildren} Queues defined:</p>"; $bodyContent .= "<ul>"; foreach($container->children() as $p) { if(! ($queue = $p->wireQueue())) continue; $bodyContent .= "<li>{$queue->getPage()->title}<ul>"; if(!$queue->ready2use()) { $bodyContent .= "<li>{$queue->className}</li>"; $bodyContent .= "<li>This Storagetype is not ready to use! The System seems not to provide all requirements.</li>"; $bodyContent .= "</ul></li>"; continue; } $bodyContent .= "<li>{$queue->className}</li>"; $bodyContent .= "<li>{$queue->getStateStr()} ({$queue->getState()})</li>"; $bodyContent .= "<li>Currently are {$queue->itemCount()} items pending!</li>"; $bodyContent .= "</ul></li>"; } $bodyContent .= "</ul>"; Following is a screenshot of the backend The module is available in the modules directory: http://modules.processwire.com/modules/wire-queue/ Or you get it from Github: https://github.com/horst-n/WireQueue. . . . The Sqlite3 storage handler not only let you push and pull data items to and from it, it also can keep track of the current state of a record. If you use multiple / different workers for pulling and processing the data, you can store an ID for them too. This is how the DB Table looks like: The Wire Queue Sqlite3 storage handler provides the methods addItem($arrayData) // same as WireQueueTextfile getItem($worker = null) // same as WireQueueTextfile, (but the textfile storage cannot support $worker!) updateItemState($id, $state, $worker = null) // this you can use for further processing, if you want . addItem($arrayData) $arrayData is a, maybe associative, array containing all your data for one record. The method stores it under the next free id under data in the Sqlite-DB-file and sets the state to 0. The field worker is empty for new added records. Following is a basic working example for pushing data records into a queue: // you have created a queue in PW, the ID of the page is 1420 for example // here is some skeleton code for an importer that uses this queue // get and validate the queue handle if(! ($queue = $pages->get('id=1420')->wireQueue())) exit(); // we could not get the Queuepage // now start to scan / read data for your imports, wrap each record into an array and put it into the queue foreach($pages->find(YOURSELECTOR) as $p) { $data = array($p->field1, $p->field2); $queue->addItem($data); } . . getItem($worker = null) $worker is an integer that you can define to suite your needs. If you don't use or don't want identify multiple workers, just ommit it. The method pulls one pending record from the queue, changes the state from 0 to 1, and returns an associative array with the keys id and data. array('id' => integer, 'data' => array) You will need the id if you further want to use the queue to keep track of processing steps. You must pull your stored $data from $array['data'] and use the id for further storing the state. . updateItemState($id, $state, $worker = null) $id identifys the record a worker has processed, for $state you can define and use every integer you like, but not 0 or 1. If you also want to store altered data, and not only different states, you can use updateItem($id, $state, $worker = null, $data = null) instead of updateItemState(). . Here is a working example with a bit pseudo code how workers can get a pending record to process it further and store back the result of the process: // you have created a queue in PW, the ID of the page is 1420 for example // here is some skeleton code for an importer that uses this queue // get and validate the queue handle if(! ($queue = $pages->get('id=1420')->wireQueue())) exit(); // we could not get the Queuepage // we do not use different workers here in that example, so we do not pass an worker id here $tmp = $queue->getItem(); // get a record from the queue $record_id = $tmp['id']; // store the record id $data = $tmp['data']; // get the data array // process the $data ... // and get the result of the process, in this example true or false $result = processMyRecord($data); // as new records have a state = 0, fetched records have a state = 1, // you may define a state of 2 for successful processed records, and higher ones for failed records $state = true === $result ? 2 : 3; $queue->updateItemState($record_id, $state); . . getItem4FurtherProcessing($state, $worker = null) The $state you pass to the method is the state you want get the record for. If there is one pending, its state will be set +1 and the id and data is passed back to you in an associative array: array('id' => integer, 'data' => array). --------- Here is a pseudo code example how (multiple) worker scripts may batch process queue records with the sqlite storage handler // on the server in this example, everyscript will timeout / die after 180 seconds // we start a timer $time = Debug::timer(); // we use different instances of workers that pull and process records from the queue, // so additionally to the processings states, we also want to store the worker ids $worker = 2000; // now start to process items by pulling one after the other from the queue while(150 > Debug::timer($time)) { $tmp = $queue->getItem($worker); // get a record from the queue if(!$tmp) continue; // maybe currently are no pending records available $record_id = $tmp['id']; // store the record id $data = $tmp['data']; // get the data array $result = processMyRecord($data); // process the data and get back the result $state = true === $result ? 2 : 3; // define an integer for the new state, according to the result of processing the data $queue->updateItemState($record_id, $state, $worker); } // we are close to the timeout for the script, so finish it with calling it itself to get a fresh run $session->redirect('./');
    1 point
  13. A collection of links and information for front-end development. Front-end forms Create simple forms using the API https://processwire.com/talk/topic/2089-create-simple-forms-using-api/ Gist code for the above link https://gist.github.com/somatonic/4027908 Build and process generic forms from page templates https://gist.github.com/somatonic/5011926 Build and process forms manually with the API https://gist.github.com/somatonic/4027908 Upload images https://gist.github.com/somatonic/4150974 Form with fields rendered in a table https://gist.github.com/somatonic/5415646 Manual form markup with file upload handling https://gist.github.com/somatonic/5233338 Form Builder (module) Building front-end forms on your website has never been so simple. ProcessWire Form Builder lets you create, edit and publish forms with no development necessary. http://modules.processwire.com/modules/form-builder/ Front-end member management FrontendUser: login, logout and register users / members (module) https://processwire.com/talk/topic/9811-frontenduser-login-logout-and-register-users-members/ Member login, logout, password reset https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/?p=15919 Popular front-end UI frameworks UIkit http://getuikit.com/ Semantic UI http://semantic-ui.com/ Foundation http://foundation.zurb.com/ Bootstrap https://getbootstrap.com/ Materialize http://materializecss.com/ Skeleton http://getskeleton.com/
    1 point
  14. Hello, I'm a long time lurker but I'm loving PW so far. I know a little about PHP, but I can follow and understand tutorials. I want to learn the enough PHP to be able to work well and make the most of this incredible CMS. The question is what PHP should I learn, I mean I know PW is OOP based but what patterns, what would be the most appropriate techniques should I focus on. Thank you. PD: please forgive my bad english... I'm still learning this too. Edit: some typos.
    1 point
  15. Thanks for the additional information, that helped me a lot in finding a solution. I will post the code below that i'm using for anyone that might want to achieve the same behavior: If statement at top of _main.php $sidebar_left = $pages->find("template=widget, widget_location.value=left"); $sidebar_left_count = 0; foreach($sidebar_left as $widgets) { if($page->is("$widgets->selector")) { $sidebar_left_count++; } } $sidebar_right = $pages->find("template=widget, widget_location.value=right"); $sidebar_right_count = 0; foreach($sidebar_right as $widgets) { if($page->is("$widgets->selector")) { $sidebar_right_count++; } } if($sidebar_right_count > 0 && $sidebar_left_count > 0) { $body_class = "two-columns"; } elseif($sidebar_right_count > 0) { $body_class = "sidebar-right"; } elseif($sidebar_left_count > 0) { $body_class = "sidebar-left"; } else { $body_class = "one-column"; } Set the class on the body element <body class="<?php echo $body_class; ?>"> Sidebar Left <?php if($sidebar_left_count > 0): ?> <aside class="sidebar-left"> <?php foreach($sidebar_left as $widget) { // check if the selector field is in use and if so, see if this page is supposed to display it: if( $widget->selector) { if( !$page->is("$widget->selector") ) continue; } $widgetType = $widget->widget_type->value; $widgetTemplate = file_exists("./partials/widget_{$widgetType}.php") ? "./partials/widget_{$widgetType}.php" : "./partials/widget_next_race.php"; include($widgetTemplate); } ?> </aside> <?php endif; ?> Sidebar Right <?php if($sidebar_right_count > 0): ?> <aside class="sidebar-right"> <?php foreach($sidebar_right as $widget) { // check if the selector field is in use and if so, see if this page is supposed to display it: if( $widget->selector) { if( !$page->is("$widget->selector") ) continue; } $widgetType = $widget->widget_type->value; $widgetTemplate = file_exists("./partials/widget_{$widgetType}.php") ? "./partials/widget_{$widgetType}.php" : "./partials/widget_next_race.php"; include($widgetTemplate); } ?> </aside> <?php endif; ?>
    1 point
  16. Unfortunately I haven't had the opportunity to play with PW 3 yet, so I don't know what's wrong here. Probably something is different in the way that PW fetches images. I'm quite busy by now, but I'll look into it as soon as possible, hopefully next week.
    1 point
  17. To start out with PW you don't even need to use or understand oop. You just need to understand the api processwire does provide and a basic understanding of using php. You'll learn all the other stuff on the go, which will be much easier with a real use case at your sight.
    1 point
  18. @congomonster, thanks for catching that. Fixed; in dev branch for now. @all Please note that if you want the method MarkupBlog::formatDate() to output your comments date according to the date field in blog_comments, you just need to pass it a second parameter 2 (integer 2). For instance, in the template file 'blog-recent-comments.php', line #30, we had this: $date = $blog->formatDate($comment->created); ...but we now have this: $date = $blog->formatDate($comment->created, 2); Since the second parameter is give a value of 1 by default, this change should be backward compatible. Unless you want the updated feature, you don't need to do anything in your template files.
    1 point
  19. Existing pages always take precedence over urlSegments. You have several options: Use urlSegments that don’t exist as children of /site/teachers/, for example by adding a string, or by using 2 urlSegments. E.g. /site/teachers/selection/teacher1/. Use GET parameters instead: /site/teachers/?teacher=teacher1. You could either process the parameter with PHP or catch it with JavaScript and use your existing AJAX solution. Which would probably be the simplest option. Just add one or two lines of JS. Or, if you don't want the actual page under /site/teachers/teacher1/ to be reachable at all, just display /site/teachers/ in that template. Example below: template of /site/teachers/teacher1/: $options['teacher'] = $page; //pass the teacher to the parent page using options array echo $page->parent->render($options); //render the parent page (/site/teachers/) template of /site/teachers/: if(isset($options['teacher'] && $options['teacher'] instanceof Page) { $aside_teacher = $options['teacher']; } //Now render the page as you normally would, and you can use $aside_teacher to put its contents where you need them This also has the added bonus that you can use standard page caching for the child pages.
    1 point
  20. Thanks for this example. Using thumbnail pictures instead of numbers also works good against bots.
    1 point
  21. Just updated and new tab looks to be working again.
    1 point
  22. and giving the option dateFormat directly to the function, it works for you ? exemple: $page->comments->renderAll(array('dateFormat' => 'm/d/y g:ia',));
    1 point
  23. @Macrura I like where you are going with this. Every user needs a good starting point and a comprehensive Dashboard is a proven and effective way of doing it. Exciting times
    1 point
  24. You could expand this even a little further - mix and match: $page->setOutputFormatting(false); $key = "visit_counter".$page->id; if(!$session->$key) { $page->visit_counter++; $page->save('visit_counter'); $session->$key = 1; } PS: i don't take credit for this, I found this here too Have fun with PW!
    1 point
  25. ------------------------------------------------------------------------------ This is officially released now with some fixes and a second storage handler based on SQLite3. ------------------------------------------------------------------------------ WireQueue WireQueue is a module that allows easy creation and usage of Queues in ProcessWire. It is based upon a basic (parent) module that can or should have one or multiple StorageHandler modules. This alpha pre release contains a basic plain text storage module, WireQueueTextfile. The base module creates the needed: FIELDS (wire_queue_type, wire_queue_state, wire_queue_storage_options) TEMPLATES (wire-queue-container, wire-queue-storage, wire-queue-tools) PAGES (wire-queues = container for all Queuepages, wire-queue-storages = container for StoragetypePages) ROLE (wire-queue-admin) Each storage module creates one page under wire-queue-storages. New Queues can be created in the backend by adding a new page under "Wire Queues". After creation one have to select a Storage type from availables list and publish the page. After that, there are some buttons available to start / pause / and close the queue. Putting and getting data to and from the queue is done via API calls. First you have to get the page that holds the queue object. // get and validate the queue handle if($queue = $pages->get(SELECTOR_TO_DESIRED_PAGE)->WireQueue()) { // wrap your data into an array and pass it into the queue $success = $queue->addItem($data); ... } // get and validate the queue handle if($queue = $pages->get(SELECTOR_TO_DESIRED_PAGE)->WireQueue()) { $data = $queue->getItem(); ... } Thats basically all what you want from a queue. Following are a few conveniences: $queue->getPage()->title gives you the title of the queue, ($queue->getPage() returns the page object) $queue->className() shows the StorageType of the queue $queue->getState() and $queue->getStateStr() returns the current state of a queue: 1 = new / empty 2 = enabled / running 3 = paused 4 = closed / archived $queue->itemCount() gives the total number of all pending items in the queue Here is code that gives an overview of all Queues in the system: $container = $pages->get('template=wire-queue-container'); $bodyContent = "<h1>$container->title</h1>"; $bodyContent .= "<p>There are currently {$container->numChildren} Queues defined:</p>"; $bodyContent .= "<ul>"; foreach($container->children() as $p) { if(! ($queue = $p->wireQueue())) continue; $bodyContent .= "<li>{$queue->getPage()->title}<ul>"; if(!$queue->ready2use()) { $bodyContent .= "<li>{$queue->className}</li>"; $bodyContent .= "<li>This Storagetype is not ready to use! The System seems not to provide all requirements.</li>"; $bodyContent .= "</ul></li>"; continue; } $bodyContent .= "<li>{$queue->className}</li>"; $bodyContent .= "<li>{$queue->getStateStr()} ({$queue->getState()})</li>"; $bodyContent .= "<li>Currently are {$queue->itemCount()} items pending!</li>"; $bodyContent .= "</ul></li>"; } $bodyContent .= "</ul>"; Following are a screenshots of the backend The module is on Github: https://github.com/horst-n/WireQueue Would be nice if someone has time and can test it a bit and report back.
    1 point
  26. I would like to thank all the Nice people giving me likes for this post. It realy gives me encuragement to come up with future tutorials when i have something usefull to share.
    1 point
  27. Please review the following information https://github.com/ryancramerdesign/ProcessWire/tree/devns
    1 point
  28. Update: Version 2.3.7 Following this question, it is now possible to pass MarkupPagerNav options to renderPosts() if you wish to customise your posts' pagination. All the MarkupPagerNav options listed here can be passed as an array within an array to renderPosts() as shown in the example below: $blog = $modules->get("MarkupBlog"); $paginationOptions = array( 'nextItemLabel' => "Forth", 'previousItemLabel' => "Back", 'listMarkup' => "<ul class='MarkupPagerNav Zurb pagination'>{out}</ul>", 'itemMarkup' => "<li class='{class} not necessary class'>{out}</li>", 'numPageLinks' => 5 ); $options = array( 'post_pagination' => $paginationOptions,// array of markup pager nav options 'post_count_text' =>'Article',// other posts options passed as normal ); echo $blog->renderPosts("limit=5", true, $options);
    1 point
  29. Sadly, I wasn't able to do all the mock-ups this weekend as I was away. However I've managed to make a start on the edit page. @LostKobrakai - Thank you for your feedback, I let the sidebar in for this exact reason. I also have some ideas on how to fill out that space when only the Page link is available (due to permissions - editorial role). My idea is to have maybe the recently edited appear as like widgets in the sidebar - or something along those lines. I really need to think about it. This will be just be a theme I'll be building mostly to gain experience on the system but also to use in my personal projects. I will be releasing it for others to download. Anyway, here is the edit page (http://i.imgur.com/kp96yng.jpg):
    1 point
  30. Successfully tested PIA with PW 3.0 and set the version to 1.0.0 stable now.
    1 point
  31. the latest screenshot i use pages for the shortcut widgets as follows; this is a basic setup and will be expanded upon gradually: the widgets are pages this is the template for making shortcuts; the shortcuts are configured first, and then added to the widget; this way shortcuts can be used in any widget this is the page for configuring a shortcut widget this is the shortcut page showing the page select for the shortcuts there is one template file dashboard.php which controls the contents of the dashboard. the shortcut widgets are generated automatically based on being setup in the admin; the lister widgets are currently hardcoded but the plan is to make them configurable using a selector field
    1 point
  32. Update: So I've been using Pete's dashboard module instead of the technique described above; it's quicker to setup, and easier to clone to other installs, and no need to have code in various places like the themes folder and in ready.php The hope/plan is to turn it into a full widget enabled dashboard module that i can install on various installations a) without having to do any hardcoding b) enable control over which widgets are shown on the dashboard (by user/role/permission) c) allow for easy configuration of colors, icons, columns, etc. To achieve this I setup some templates for different widget types, one is a shortcuts widget, another is a page lister widget; these each have pages and fields to configure them; i can set them to appear by user/role. in the future i can add different types of widgets as needed and then include them in the needed user's dashboard. This is using a combination of a free (MIT licensed) admin theme for bootstrap, but instead of using bootstrap as the css layout, it uses a tiny grid called rwdgrid which i s 2KB; it uses the box, and other widget classes from the admin theme.
    1 point
  33. There's now a permission in the core to handle this: https://processwire.com/blog/posts/processwire-2.6.23-2.7-rc2-translation-features-license-discussion/#new-lang-edit-permission-for-file-translators-that-arent-superusers
    1 point
  34. This is because of assignments inside function calls, which should be avoided at all costs, e.g. in line 329 of FormHelper.module (279 is the other one): if (!empty($files = $this->files[$fieldName])) { Strict mode barks on this because assigning to passed variables like this breaks pass-by-reference. Consider these two snippets: $x = 1 byref($x); echo $x . "\n"; function byref(&$val) { $val = 3; } This correctly echoes "3". Now lets do the same and assign $x in the function call: byref($x = 1); echo $x . "\n"; function byref(&$val) { $val = 3; } Now our output is "1", which is of course not what we would have expected after assigning to a variable passed by reference - our assignment has turned the pass-by-reference into a pass-by-value. The original line should be written as: $files = $this->files[$fieldName]; if (!empty($files)) {
    1 point
  35. Hi jckhmmr, Any value that is posted to a page can be fetched with one of the following manners: $input->post->fieldname; $input->post['fieldname']; $input->post('fieldname'); For GET values simply change post to get $input->get->fieldname; See: https://processwire.com/api/variables/input/ Where fieldname is the name of the form input field. So when you have a form <form method="POST" action="<php echo $page->url; ?>"> <input type="text" name="firstname"> <input type="text" name="lastname"> <input type="submit" name="send" value="send"> </form> You can access those fields as follow: $input->post->firstname; $input->post->lastname; A good thing to do always with user input is to sanitize it like this: $firstname = $sanitizer->text($input->post->firstname); $lastname = $sanitizer->text($input->post->lastname); See: https://processwire.com/api/variables/sanitizer/ and welcome to ProcessWire.
    1 point
  36. Hi there, just a small update on this for those who are interested. Finally I've got my script / download proxy up and running. This is the code that generates a list with downloadable files (in this case logos) through a repeater field. <?php foreach($page->logos as $logo) { echo "<p><a href='{$config->urls->root}download.php?pageid={$logo->id}&file={$logo->logo_file}'>{$config->urls->root}download.php?pageid={$logo->id}&file={$logo->logo_file}</a></p>"; } ?> So a download links then looks like this: http://www.domain.com/download.php?pageid=1057&file=hi_res_100_percent_pure_logo.zip Here is the download.php: <?php // bootstrap PW include("./index.php"); // make sure user is logged in if(wire("user")->isLoggedin()){ $fn = wire('input')->get->file; $pid = wire('input')->get->pageid; $filepage = wire("config")->paths->files; // put together the complete path to the file $filename = $filepage.$pid.'/'.$fn; if(!$filename) die("download not found"); // send file to browser wireSendFile($filename, array('exit' => true)); } else { wire("session")->redirect("/"); } ?> Everything works great now. However I still wanted to protect the original path of the files (assets/files/...) allthough nobody would know the exact location. To do this I modified to the .htaccess to suite my needs to block all unwanted access to files with the most common endings for downloads (e.g. zip, rar, pdf, etc.) So the part in my .htaccess which takes care of that is the following: <FilesMatch "(^#.*#|\.(htaccess|htpasswd|ini|phps|bak|config|dist|fla|in[ci]|log|psd|pdf|zip|rar|sh|sql|sw[op])|~)$"> # Apache < 2.3 <IfModule !mod_authz_core.c> Order allow,deny Deny from all Satisfy All </IfModule> # Apache 2.3 <IfModule mod_authz_core.c> Require all denied </IfModule> </FilesMatch> I found that part during my research for .htaccess modifications and finally I ended up with using that part of the HTML5 Boilerplate. I know that might be a bit strict and I don't know yet if there are any issues with that but so far everything seems to work fine. Thanks to all the helpers (especially Horst) for guiding me that way to get my solution to work.
    1 point
  37. If you have a robots.txt, I would use it to specify what directories you want to exclude, not include. In a default ProcessWire installation, you do not need to have a robots.txt at all. It doesn't open up anything to crawlers that isn't public. You don't need to exclude your admin URL because the admin templates already have a robots meta tag telling them to go away. In fact, you usually wouldn't want to have your admin URL in a robots file because that would be revealing something about your site that you may not want people to know. The information in robots.txt IS public and accessible to all. So use a robots.txt only if you have specific things you need to exclude for one reason or another. And consider whether your security might benefit more from a robots <meta> tag in those places instead. As for telling crawlers what to include: just use a good link structure. So long as crawlers can traverse it, you are good. A sitemap.xml might help things along too in some cases, but it's not technically necessary. In most cases, I don't think it matters to the big picture. I don't use a sitemap.xml unless a client specifically asks for it. It's never made any difference one way or the other. Though others may have a different experience.
    1 point
×
×
  • Create New...