Leaderboard
Popular Content
Showing content with the highest reputation on 12/04/2013 in all areas
-
Here are some API additions to the dev branch, primarily for WireArray/PageArray/etc. I've found these very handy lately, and would have on almost any project I worked on, so decided they'd add value to the core. I'll add these to the cheatsheet once 2.4 replaces 2.3, but for now, here they are. The examples here use PageArray, but note that these API additions apply to any WireArray derived type, not just PageArray. WireArray::implode() Implode all elements to a delimiter-separated string containing the given property from each item. Similar to PHP's implode() function. Usage: $string = $items->implode([$delimiter], $property, [$options]); Arguments: $delimiter - The delimiter to separate each item by (or the glue to tie them together). May be omitted if not needed $property - The property to retrieve from each item (i.e. "title"), or a function that returns the value to store. If a function/closure is provided it is given the $item (argument 1) and the $key (argument 2), and it should return the value (string) to use. [$options] - This argument is optional. When used, it's an array with modifiers to the behavior: skipEmpty: Whether empty items should be skipped (default=true) prepend: String to prepend to result. Ignored if result is blank. append: String to prepend to result. Ignored if result is blank. Examples: $items = $pages->find("template=basic-page"); // render all the titles, each separated by a <br>, for each page in $items echo $items->implode('<br>', 'title'); // render an unordered list of each item's title echo "<ul><li>"; echo $items->implode('</li><li>', 'title'); echo "</li></ul>"; // same as above, but using prepend/append options, // this ensures no list generated when $items is empty echo $items->implode('</li><li>', 'title', array( 'prepend' => '<ul><li>', 'append' => '</li></ul>' )); // same as above, but with all items now presented as links // this demonstrates use of $property as a function. note that // we are also omitting the delimiter here as well, since we don't need it echo $items->implode(function($item) { return "<li><a href='$item->url'>$item->title</a></li>"; }, array('prepend' => '<ul>', 'append' => '</ul>')); WireArray::explode() Return a plain array of the requested property from each item. Similar to PHP's explode() function. The returned PHP array uses the same keys as the original WireArray (if that matters). Usage: $array = $items->explode($property); Arguments: $property - The name of the property (string) to have in each array element (i.e. "title"). You may also provide a function/closure here that should return the value to store. When a function/closure is used it receives the $item as the first argument and the $key (if needed) as the second. Examples: // get an array containing the 'title' of each page $array = $items->explode('title'); // get an array containing the id, url and title of each page $array = $items->explode(function($item) { return array( 'id' => $item->id, 'url' => $item->url, 'title' => $item->title ); }); WireArray::data() Store or retrieve an arbitrary/extra data value in this WireArray. This is exactly the same thing that it is jQuery. I've personally found this useful when building search engines: the search engine can store extra meta data of what was searched for as a data() property. Then any other functions receiving the WireArray/PageArray have access to this additional info. For example, the search engine portion of your site could populate an array of summary data about what was searched for, and the render/output code could render it to the user. Usage: // Setting data $items->data('key', 'value'); // Getting data $value = $items->data('key'); // Get array (indexed by key) of all data $values = $items->data(); Arguments: The above usage section explains all that's needed to know about the arguments. The only additional comments I'd make are that 'key' should always be a string, and 'value' can be anything you want it to be. Example: function findSkyscrapers() { $floors = (int) wire('input')->get->floors; $year = (int) wire('input')->get->year; $items = wire('pages')->find("template=skyscraper, floors=$floors, year=$year"); $items->data('summary', array( 'Number of floors' => $floors, 'Year constructed' => $year )); return $items; } // the render function can focus purely on output function renderSkyscrapers($items) { echo "<h2>You searched for:</h2>"; // render the summary of what was searched for foreach($items->data('summary') as $label => $value) { echo "<p>$label: $value</p>"; } echo "<h3>Skyscrapers found:</h3>"; // note use of new implode() function, though a foreach() would be just as well here echo $items->implode(function($item) { return "<p><a href='$item->url'>$item->title</a></p>"; }); } WireArray::and() WireData::and() Return a new copy of the WireArray with the given item(s) appended. Primarily as a syntax convenience for various situations. This is similar to jQuery's add() and andSelf() functions, but I've always felt "add" implied adding something to the original rather than creating a new combination, so went with "and" in this case. The term "and" is actually a reserved word in PHP, so you can't usually have a function named "and()", but through the magic of hooks, ProcessWire can. This function should reduce the instances in which you'd need to do "$a = new PageArray();" for example. Usage: // create a new WireArray with $items and $item (appended) $myItems = $items->and($item); // create a new WireArray with $items and $moreItems (appended) $myItems = $items->and($moreItems); // create a new WireArray with $items and $item (prepended) $myItems = $item->and($items); // create a new WireArray with $item and $anotherItem (appended) $myItems = $item->and($anotherItem); // create a new WireArray 4 items $family = $pappa->and($mamma)->and($brother)->and($sister); Examples: // generate breadcrumb trail that includes current page foreach($page->parents->and($page) as $item) { echo "<a href='$item->url'>$item->title</a> / "; } // check if page or its children has a featured checkbox if($page->and($page->children)->has("featured=1")) { echo "<p>Featured!</p>"; }15 points
-
Bravo Christophe! I am beginning to wonder whether I should write an article not so much about Processwire, but rather why professional sites should not be made using Wordpress. I have nothing against Wordpress - it is an extremely powerful and well supported blogging platform and it is a really great tool for the hobbiest or small company that wants to create their own website without using a developer - indeed, I use it for a couple of my own blogs (though more recent ones have been built with PW) But the other day, while researching competition for a client, I came across a professional website made by an "award winning developer," built on Wordpress. I will be nice and not post the site here. It was a perfectly acceptable website, except that it used a wordpress installation and a ton and a half of wordpress plugins. The list of style sheets and script that the template was resourcing was huge and there were three different versions of JQuery being accessed, The actual site was very simple, but some of the layout was a bit cock-eyed because the client had been editing his own site with the TInyMCE editor and messed up some of the images. The client's web site requirement had been shoe-horned into Wordpress, whether that was appropriate or not, and for me that is just plain wrong. When I compose music for someone's advert, I don't go through my files trying to find an old piece of music that more or less fits the clients brand, I start from scratch and write something that fits their brand, their name and their campaign properly. In the industry I come from, that is what is expected of me. To stretch an analogy to breaking point, Processwire is a piano that you can use to write any song you like. Wordpress is a pianola that can only play the tune that is punched out on the scroll. (And just in case you don't know what a Pianola is: http://en.wikipedia.org/wiki/Player_piano)3 points
-
2 points
-
I'm always building a static site at first, means only html and css etc. For example creating a start-page, a profile page and so on (depends on what the project needs). After that I'm stripping down the html and bake them all into PW. BTW: there are 2 simple grids..? http://simplegrid.info/ http://thisisdallas.github.io/Simple-Grid/2 points
-
u shuold use.vagination with 10 - 20 concerto/page hundredos of paginas u run out memory soon if u.cannut u may try stop nested foreacher.use $tours->find( "template=concert ") { edit each felds:: date city text fotos podcast checkbox ``auto join`` save dose this help ? it.shuld u.can loook 2 ``markupcache`` modulos too in end u must use paginasnation other wises u site can not scale2 points
-
http://conclurer.com Design + Code Another page I have created with Processwire. This is "our" own portfolio + contact and news. The contact page was created with Ryans experimental Contactmodul. So far, our site has gone through 3 stages. First we had our old Typo3 installation and the first design. You can find the remains here. Then we just migrated the design and content to Processwire(2nd Page). Finally, I've rebuild the site from skretch with Processwire last month. Not perfect but I have the feeling that I'm getting better with every website I make.2 points
-
Hello everyone! I launched yesterday another PW site: http://compab.it The modules that i have used are: • Site wide file manager. • CKeditor • Language Field Tabs • Modules Manager • Site indexer • Ergo ADMIN THEME Enjoy!1 point
-
i see htmls in there sholdunt u.use html as mode ? their is no javascripts here just html script link to javascript tl;dr use.html mode1 point
-
Killed me. Dead. Perhaps you could also list the first 20, then "load more" via ajax on request. Also... Welcome Seb!1 point
-
for your event calendar, you have to consider how many calendar-type features you need; with PW you can sometimes integrate other scripts, for example this is a very full-featured calendar: http://smartphpcalendar.com as far as forum, that's also something that i would integrate from another script; (ip board is nice!) likewise for shopping cart (i use foxycart, but Shopify is also great and Ecwid is a discreet ecommerce system that can 'float' on any site with a few lines of code). you can take apart the blog profile if you want to build your own blog using PW, or use that profile as a starting point1 point
-
One question at a time, I suggest. A good starting point would be to create the fields and template you think you will need to store the information for the event calendar - name of event, postcode, details, website, date start time, date end time, and so on. Once you know what actual information you are dealing with, then it is less of a mountain to climb. The next step will be to work out how you want your calendar displayed - this is the bit that kind of got me twisted up, but anything is possible. That is the bit that might cause you the most grief and will probably see you back here asking questions! Joss1 point
-
I quickly looked at the repo and no it's far from good or standard or how it should be or can be. There's just a site folder with modules folder inside that contains a Fieldtype module that is a separate module from another guy. I'm not sure why this module is in the directory and it also isn't installable by ModulesManager for example. I'm sorry as I mind sound patethic, but I always said that we should have clear guidlines how modules repos should be built and that there must be some quality assurance for modules posted to the official directory. This doesn't happen and makes me a little sad. (just a quick glance $pass = $this->sanitizer->text($this->input->post->pass); Just wrong to sanitize passwords...) /rant1 point
-
@Soma: I had planned to debug this a bit further before posting, but since you've already mentioned it: I've been seeing this same issue for couple of days now. Log entries are very similar to yours. So far I'm guessing that this is somehow related to ProcessWire issue #284, which has since been fixed. At least in my case, where pages just got suddenly unpublished and I'm running dev version just before this fix, this seems to be the culprit. Taking a look at field_publish_until for one particular page for which it should be empty, it looks like this: +----------+---------------------+ | pages_id | data | +----------+---------------------+ | 9224 | 1970-01-01 02:00:00 | +----------+---------------------+ Since SchedulePages first finds pages where publish_until>0 and then checks if publish_from <= current time, this particular page getting unpublished sounds logical This might only be applicable to dev branch, but I haven't tested this a site running older release yet. Soma, what version of PW are you running? If you're using dev, could you update it and see if the issue persists? Edit: Soma, I just realized that you mentioned the issue suddenly going away. Any chance that this was because you updated your PW at some point, applying aforementioned fix?1 point
-
Thanks. I've corrected the home page to verhilft. Sounds better. Copywriting was done by both of us and we think it works. Yesterday, our first client contacted us via the contact form without knowing us from friends/business partners/... .1 point
-
Ok. Coincidence, as there was an dev update just an hour before I posted this thread which seem to fix this cache problem for me. Will test a litte more but definately the cache gets deleted now correctly it seems1 point
-
A way of using columns what I like is: if you allow HorizontalRulers in your WYSIWYG you can spit the text with <hr> Every splitted text becomes a column with the code below: $body = str_replace('<hr />', '<hr>', $page->body); $columns = explode('<hr>', $body); $column_count = count($columns); if(count($columns)) { echo "<div class='grid grid-pad'>"; foreach($columns as $column) { $last = ($key + 1 == $column_count) && $column_count > 1 ? ' last' : null; echo "<div class='col-1-{$column_count}{$last}'>"; echo "<div class='content'>"; echo $column; echo "</div>"; echo "</div>"; } echo "</div>"; }1 point
-
An ajax request needs an URL by nature, so for doing this you will have to have them available via URL. You can however throw a 404 if they are not requested via a post. if(!$input->post->secret) throw new Wire404Exception(); for this, you would have to use a method that sends some post info to the server via JS.1 point
-
I installed this modules as I have a need to a scheduler, thanks for all the work put into it. I have a problem that the scheduler doesn't run then visitors visit the site. It only runs when I am logged in. This doesn't make a lot of sense, and I'm suprised that nobody run into this? Any ideas? Also it would be nice when installing if it would check if fields already exists and only try to create them if not present. I already had them created beforehand with the same names (lucky) without knowing I would install this module. Also when deinstalling the module I'm not sure It should try to remove the fields at all ,even if the fields are not used on any template anymore. Maybe the dev wants to keep them. Thanks1 point
-
I'm not sure what version you got, but the p tag wasn't missing closing tag, but it was wrong and not needed. Thanks for mention. I pushed a little update with other small fixes.1 point
-
Actually, you can do this on the dev branch. Lets assume that cities are children of countries and that is reflected in your page structure (i.e. /countries/france/paris/). Create your 2 page fields (country and city), and configure 'country' as a single page field with "parent" set to "/countries/". Next, for the "city" field configuration, use the "Custom selector to find selectable pages", present on the "input" tab. In that field, enter "parent=page.country". Save and try it out. This works with select, selectMultiple and asmSelect fields (and possibly others), though not yet with checkboxes, radios or PageListSelect.1 point
-
1 point
-
If you need any help, just let us know. Everyone here teaches everyone else something at some point1 point
-
Hi Niklas, i guess maybe when you say 'sites' you mean pages? this is something that can already be done pretty easily. for example i just did a site with 3 distinct types of data, classes (as in like an art class), sessions (as in the actual session that the class runs, start/end dates, instructor etc.) and events. For the classes, we setup a parent page called Class Database, and then a custom admin page for viewing the list of classes, and being able to click on one and edit it. the class database page used a template called class-database which only allows the page type class as a child. for sessions those are relational to classes and output on each class, the class is a page select on the session, and there is no template file for the session, so they won't show or be accessible on the front end. the classes are output using url segments and some url 'rewriting' logic that was demonstrated by Ryan's CMS Critic case study.1 point
-
Setting a class which disables pointer events while scrolling = no more (re)paints when accidentally hovering elements <3 http://www.thecssninja.com/javascript/pointer-events-60fps1 point
-
Files uploaded to pages go in /site/assets/files/. Files uploaded to FormBuilder forms go in /site/assets/cache/form-builder/ (or another directory, which you can define in your FormBuilder module settings). If you've got a file that's going in both, then that would be because you've got FormBuilder publishing entries to pages. I don't recommend automatically publishing entries to pages–better to approve them individually before publishing to pages. But either way, if you are publishing entries to pages, then there's going to be a file associated with the entry and another associated with the page. If form submissions are being used for the purpose of publishing to pages, then typically you'd delete the entry after publishing it to a page (thereby deleting the original copy of the file too). Let me know if I've misunderstood the question?1 point
-
No need to be sorry. That is often made mistake (that still confuses me after 3 years). In my opinion it is bad design decision - probably only one there is in PW Simple and harmless setting that can break your site. Not something I wish changed now, but I think it would be cleaner to always return array. Or maybe $page->images->url return url of the first image even if an array?1 point
-
What you did earlier for table "field_body" was correct - I was trying to say don't apply the same fix blindly to all keys named "data" as they're not all the same. So, for table "field_body" change "KEY `data` ( `data` )" to "FULLTEXT KEY `data` ( `data` )" (as column "data" is of type MEDIUMTEXT in that table). But for table "field_display_specialty_footer" leave the key to what it was ("KEY `data` ( `data` , `pages_id` , `sort` )") as column "data" is not of type TEXT/BLOB there.1 point
-
To delete pages you may use delete. http://cheatsheet.processwire.com/?filter=delete (must have been still in m clipboard ) $pages->delete($page, true); // recursive with children $pages->delete($page); $page->delete(); To get pages from the trash you would need include all $pa = $pages->find("parent=/trash/,include=all"); $pages->get() will give you only 1 page. http://cheatsheet.processwire.com/?filter=pages-%3Eget1 point
-
I recently had to setup front-end system to handle logins, password resets and changing passwords, so here's about how it was done. This should be functional code, but consider it pseudocode as you may need to make minor adjustments here and there. Please let me know if anything that doesn't compile and I'll correct it here. The template approach used here is the one I most often use, which is that the templates may generate output, but not echo it. Instead, they stuff any generated output into a variable ($page->body in this case). Then the main.php template is included at the end, and it handles sending the output. This 'main' template approach is preferable to separate head/foot includes when dealing with login stuff, because we can start sessions and do redirects before any output is actually sent. For a simple example of a main template, see the end of this post. 1. In Admin > Setup > Fields, create a new text field called 'tmp_pass' and add it to the 'user' template. This will enable us to keep track of a temporary, randomly generated password for the user, when they request a password reset. 2a. Create a new template file called reset-pass.php that has the following: /site/templates/reset-pass.php $showForm = true; $email = $sanitizer->email($input->post->email); if($email) { $u = $users->get("email=$email"); if($u->id) { // generate a random, temporary password $pass = ''; $chars = 'abcdefghjkmnopqrstuvwxyz23456789'; // add more as you see fit $length = mt_rand(9,12); // password between 9 and 12 characters for($n = 0; $n < $length; $n++) $pass .= $chars[mt_rand(0, strlen($chars)-1)]; $u->of(false); $u->tmp_pass = $pass; // populate a temporary pass to their profile $u->save(); $u->of(true); $message = "Your temporary password on our web site is: $pass\n"; $message .= "Please change it after you login."; mail($u->email, "Password reset", $message, "From: noreply@{$config->httpHost}"); $page->body = "<p>An email has been dispatched to you with further instructions.</p>"; $showForm = false; } else { $page->body = "<p>Sorry, account doesn't exist or doesn't have an email.</p>"; } } if($showForm) $page->body .= " <h2>Reset your password</h2> <form action='./' method='post'> <label>E-Mail <input type='email' name='email'></label> <input type='submit'> </form> "; // include the main HTML/markup template that outputs at least $page->body in an HTML document include('./main.php'); 2b. Create a page called /reset-pass/ that uses the above template. 3a. Create a login.php template. This is identical to other examples you may have seen, but with one major difference: it supports our password reset capability, where the user may login with a temporary password, when present. When successfully logging in with tmp_pass, the real password is changed to tmp_pass. Upon any successful authentication tmp_pass is cleared out for security. /site/templates/login.php if($user->isLoggedin()) $session->redirect('/profile/'); if($input->post->username && $input->post->pass) { $username = $sanitizer->username($input->post->username); $pass = $input->post->pass; $u = $users->get($username); if($u->id && $u->tmp_pass && $u->tmp_pass === $pass) { // user logging in with tmp_pass, so change it to be their real pass $u->of(false); $u->pass = $u->tmp_pass; $u->save(); $u->of(true); } $u = $session->login($username, $pass); if($u) { // user is logged in, get rid of tmp_pass $u->of(false); $u->tmp_pass = ''; $u->save(); // now redirect to the profile edit page $session->redirect('/profile/'); } } // present the login form $headline = $input->post->username ? "Login failed" : "Please login"; $page->body = " <h2>$headline</h2> <form action='./' method='post'> <p> <label>Username <input type='text' name='username'></label> <label>Password <input type='password' name='pass'></label> </p> <input type='submit'> </form> <p><a href='/reset-pass/'>Forgot your password?</a></p> "; include("./main.php"); // main markup template 3b. Create a /login/ page that uses the above template. 4a. Build a profile editing template that at least lets them change their password (but take it further if you want): /site/templates/profile.php // if user isn't logged in, then we pretend this page doesn't exist if(!$user->isLoggedin()) throw new Wire404Exception(); // check if they submitted a password change $pass = $input->post->pass; if($pass) { if(strlen($pass) < 6) { $page->body .= "<p>New password must be 6+ characters</p>"; } else if($pass !== $input->post->pass_confirm) { $page->body .= "<p>Passwords do not match</p>"; } else { $user->of(false); $user->pass = $pass; $user->save(); $user->of(true); $page->body .= "<p>Your password has been changed.</p>"; } } // display a password change form $page->body .= " <h2>Change password</h2> <form action='./' method='post'> <p> <label>New Password <input type='password' name='pass'></label><br> <label>New Password (confirm) <input type='password' name='pass_confirm'></label> </p> <input type='submit'> </form> <p><a href='/logout/'>Logout</a></p> "; include("./main.php"); 4b. Create a page called /profile/ that uses the template above. 5. Just to be complete, make a logout.php template and create a page called /logout/ that uses it. /site/templates/logout.php if($user->isLoggedin()) $session->logout(); $session->redirect('/'); 6. The above templates include main.php at the end. This should just be an HTML document that outputs your site's markup, like a separate head.inc or foot.inc would do, except that it's all in one file and called after the output is generated, and we leave the job of sending the output to main.php. An example of the simplest possible main.php would be: /site/templates/main.php <html> <head> <title><?=$page->title?></title> </head> <body> <?=$page->body?> </body> </html>1 point