Leaderboard
Popular Content
Showing content with the highest reputation on 01/13/2016 in all areas
-
6 points
-
Hi Sradesign, Finally could look at the implementation, turned out that you must enable tracking by values explicitly like this: $p = $pages->get('/'); $p->setTrackChanges(Wire::trackChangesOn | Wire::trackChangesValues); $p->title = 'new value'; var_dump($p->getChanges(true)); die(); Worked for me then, hope it helps! Cheers4 points
-
Woohoo! They're definitely on a drive to get people updated across the board even if this announcement didn't specify OS. It's got to be expensive to keep supporting old stuff. Now can Apple just end support for Safari next? All versions? Found a load of Safari-only quirks in a site I'm working on at the moment and it's doing nothing for my mood4 points
-
Finally, our site is live. It's a quite small, straightforward site with not much use for a CMS as of yet. However, as we will grow we might need easy ways to easily add or exchange content. Comments welcome. If you see anything strange, please let me know. I didn't optimize the hell out of it, but a 98/100/97 in PageSpeed is not too bad. Oh, I didn't use any front end framework or npm module. I thought this might be a little too much overhead for a site like this. I still need to minify my stuff, and there is room for optimization - but I really tried to keep my CSS lean. Don't look at the selectors though Modules used: * MarkupSEO * ProcessHannaCode * WireMailSMTP * SimpleContactForm * MarkupSitemapXML * TextformatterVideoEmbed On the technical side, this site runs on a small DigitalOcean VPS (1 CPU, 1GB RAM) with nginx and PHP 7. This is the first site I made that uses HTTP/2. And here it is: https://studio8.productions3 points
-
Languages Try this in a template: <?php setlocale(LC_TIME, 'NL_nl'); echo strftime('%e %B %Y om %H:%M', time()); The function time() creates a timestamp. If you formatted the date you might want to get the date unformatted like: <?php $page->getUnformatted('FIELDNAMEHERE'); So: <?php setlocale(LC_TIME, 'NL_nl'); echo strftime('%e %B %Y om %H:%M', $page->getUnformatted('FIELDNAMEHERE')); Should produce the time in the Dutch language. Place it at the top of your file. You can also get the current locale with: <?php echo locale_get_default();2 points
-
I'm close to the finish line on this latest update. I've added support for ALL types of inputfields as well as automatic selection of a new page when it's added. I'm still working on the autocomplete inputfield and a few optimizations and then I will push the changes to GitHub.2 points
-
I managed to successfully change my default language Everything went quite smoothly, except for some strange errors that I desribed above and which might be related to my particular environment. Here my complete function for swapping a language with the default language. Instructions for necessary steps after swapping languages are included. <?php function swapLanguages($pages, $lang) { $startTime = microtime(true); $langDefault = "default"; $log = ["languages" => "Swap field values for language {$langDefault} with {$lang}", "pages" =>[]]; $languages = wire("languages"); // get languages $l1 = $languages->get($langDefault); $l2 = $languages->get($lang); foreach ($pages as $p) { $log["pages"][$p->id] = ""; $fieldlog = " name"; $p->of(false); // swap page names $nameDefault = $p->localName($l1); $name = $p->localName($l2); if($nameDefault != $name && !empty($name)) { $p->set("name",$name); $p->set("status$l2",1); $p->set("name$l2",$nameDefault); } elseif($nameDefault != $name && empty($name)) { $p->set("status$l2",1); $p->set("name$l2",$nameDefault); } // iterate through all fields and swap multi language field values foreach ($p->template->fieldgroup as $field) { if($field->type instanceof FieldtypePageTitleLanguage || $field->type instanceof FieldtypeTextareaLanguage || $field->type instanceof TextLanguage) { $fieldlog .= " {$field->name}"; // var_dump($p->$field); // needed this for some pages otherwise they threw an error // $p->of(false); // needed this for some pages otherwise they threw an error $langDefault = $p->$field->getLanguageValue($l1); $lang = $p->$field->getLanguageValue($l2); if( $langDefault != $lang && !empty($lang) && !empty($langDefault) ) { $p->$field->setLanguageValue($l1, $lang); $p->$field->setLanguageValue($l2, $langDefault); } elseif( $langDefault != $lang && empty($lang) ) { $p->$field->setLanguageValue($l2, $langDefault); } elseif( $langDefault != $lang && empty($langDefault) ) { // only needed this for pages that got created through API and had no default lang value set $p->$field->setLanguageValue($l1, $lang); } } } try { $p->save(); $log["pages"][$p->id] = "Swapped values in fields: {$fieldlog}"; } catch (Exception $e) { $log["pages"][$p->id] = 'Error: ' . $e->getMessage(); } $p->of(true); } // write logfile $logfile = fopen(wire("config")->paths->logs . "swaplanguage-log.txt", "w") or die("Unable to open file!"); $iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($log)); foreach($iterator as $key => $value) { fwrite($logfile, "$key => $value\n"); } fclose($logfile); $time_elapsed = microtime(true) - $startTime; echo "Finished after {$time_elapsed} seconds"; } /* Usage: // swapLanguages($pages->find("template=basic-page, parent=1, include=all"), "de"); // argument 1: pages array // argument 2: language name that you want to swap with the default language // A log file will be written to site/assets/logs/swaplanguage-log.txt. // It contains page IDs and fields that were swapped for each page */ /* // After executing this function for all required pages, following steps are needed: // 1. load core translation files for the language that is now your default (e.g. german translation files) to Setup->languages->default // 2. change titles of the default Language to your language (e.g. Deutsch) and the language that got swapped (e.g. English) // 3. if default language was English before swapping: delete core translation files for the language that you swapped // 4. if default language was not English before swapping: load the core translation files for that language // 4. in settings for home page, change the URL for your default language and the language that you have swapped. // Example: // Before swapping: default was en, swap language was de // After swapping: default is now de, swapped language is now en */ The function will swap page names and the contents of multi-language fields TextAreaLanguage and PageTitleLanguage. If any of you know a more generic way of checking whether a field is multi language, other than if($field->type instanceof FieldtypePageTitleLanguage || $field->type instanceof FieldtypeTextareaLanguage) that would be great. The function is also available as swap-languages.php gist. EDIT: Added field type TextLanguage to the fields that will be processed.2 points
-
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
-
A simple module that'll automatically obfuscate all emails found on the page. Emailobfuscator.zip1 point
-
Greetings Everyone, ************************************************* ************************************************* EDIT NOTE: This post started as a work-in-progress discussion as I was working out the elements of a successful form. After contributions from participants in this discussion, the code below has been tested and works well. You can use the code as shown below in your ProcessWire templates! Feel free to follow up with additional quesations/comments! ************************************************* ************************************************* I have successfully built front-end forms with ProcessWire to add pages via the API. It works great -- until I had to include image uploads along with the "regular" form fields. Then it temporarily got a bit complicated. In this discussion, I show how to handle front-end submissions in ProcessWire with the goal of allowing us to create pages from custom forms. I then go a step further and show how to use the same form to upload files (images and other files). I'm hoping this discussion can illustrate the whole process. I know a lot of people are interested in using ProcessWire to do front-end submissions, and my goal for this discussion is to benefit others as well as myself! First, here's my original contact form (no file uploads): <form action="/customer-service/contact/contact-success/" method="post"> <p><label for="contactname">Name:</label></p> <p><input type="text" name="contactname"></p> <p><label for="email">E-Mail:</label></p> <p><input type="email" name="email"></p> <p><label for="comments">Comments:</label></p> <p><textarea name="comments" cols="25" rows="6"></textarea></p> <button type="submit">Submit</button></form> And here's the "contact-success" page that picks up the form entry to create ProcessWire pages: <?php // First, confirm that a submission has been made if ($input->post->contactname) { // Save in the ProcessWire page tree; map submission to the template fields $np = new Page(); // create new page object $np->template = $templates->get("contact_submission"); $np->parent = $pages->get("/customer-service/contact-us/contact-submission-listing/"); // Send all form submissions through ProcessWire sanitization $title = $sanitizer->text($input->post->contactname); $name = $sanitizer->text($input->post->contactname); $contactname = $sanitizer->text($input->post->contactname); $email = $sanitizer->email($input->post->email); $comments = $sanitizer->textarea($input->post->comments); // Match up the sanitized inputs we just got with the template fields $np->of(false); $np->title = $contactname; $np->name = $contactname; $np->contactname = $contactname; $np->email = $email; $np->comments = $comments; // Save/create the page $np->save(); } ?> This works great! After submitting the form, we go to the "Success" page, and new submissions show up in the ProcessWire page tree right away. Excellent! Now I need to add a photo field. I altered the above form so it looks like this: <form action="/customer-service/contact/contact-success/" method="post" enctype="multipart/form-data"> <p><label for="contactname">Name:</label></p> <p><input type="text" name="contactname"></p> <p><label for="email">E-Mail:</label></p> <p><input type="email" name="email"></p> <p><label for="comments">Comments:</label></p> <p><textarea name="comments" cols="25" rows="6"></textarea></p> <p>Click the "Select Files" button below to upload your photo.</p> <input type="file" name="contact_photo" /> <button type="submit">Submit</button> </form> And here's the updated "contact-success" page: <?php // First, confirm that a submission has been made if($input->post->contactname) { // Set a temporary upload location where the submitted files are stored during form processing $upload_path = $config->paths->assets . "files/contact_files/"; // New wire upload $contact_photo = new WireUpload('contact_photo'); // References the name of the field in the HTML form that uploads the photo $contact_photo->setMaxFiles(5); $contact_photo->setOverwrite(false); $contact_photo->setDestinationPath($upload_path); $contact_photo->setValidExtensions(array('jpg', 'jpeg', 'png', 'gif')); // execute upload and check for errors $files = $contact_photo->execute(); // Run a count($files) test to make sure there are actually files; if so, proceed; if not, generate getErrors() if(!count($files)) { $contact_photo->error("Sorry, but you need to add a photo!"); return false; } // Do an initial save in the ProcessWire page tree; set the necessary information (template, parent, title, and name) $np = new Page(); // create new page object $np->template = $templates->get("contact_submission"); // set the template that applies to pages created from form submissions $np->parent = $pages->get("/customer-service/contact-us/contact-submission-listing/"); // set the parent for the page being created here // Send all the form's $_POST submissions through ProcessWire's sanitization and/or map to a variable with the same name as the template fields we'll be populating $np->title = $sanitizer->text($input->post->contactname); $np->name = $np->title; $np->contactname = $sanitizer->text($input->post->contactname); $np->email = $sanitizer->email($input->post->email); $np->comments = $sanitizer->textarea($input->post->comments); $np->save(); // Run photo upload foreach($files as $filename) { $pathname = $upload_path . $filename; $np->contact_photo->add($pathname); $np->message("Added file: $filename"); unlink($pathname); } // Save page again $np->save(); ?> <p>Thank you for your contact information.</p> <?php return true; } else { ?> <p> Sorry, your photo upload was not successful...</P> <?php } ?> Replace the field references with your own field names, make sure to change the various paths to match yours, and change the various messages to be what you need for your project. Read the entire discussion to see how we worked through getting to the solution shown above. Thanks, Matthew1 point
-
Hi everybody, I'd like to share with you another new module. It helps you to manage user ratings for pages in a very simple way. You can add a user rating to a certain page with a line of code: $page->ratings->add(4) If the user is logged in, the module remembers which page the user has rated for. For non-logged-in visitors, the module stores the pages, the user has rated, in the session. You can get a page's rating and its total amount of votes in a similar way: $page->ratings->average; // => 3.2 $page->ratings->count; // => 5 For more information about this module, please check out its GitHub repository. You can check out a working version of the module here: http://curium-cte.lightningpw.com Edit: The module is now available in the ProcessWire modules directory. Update: Ratings has been updated to version 1.1, including a new, simpler API accessor. As always - please comment for bugs or feature wishes. Thanks in advance, Marvin1 point
-
Just came across this interesting video https://vimeo.com/86719782. At 53 seconds into the video you can see how the Wagtail cms (https://wagtail.io/) admin theme is able to show their site's page tree just by hovering a global link. Maybe that is something that can be done for Processwire? Just a thought1 point
-
You will be assimilated. Resistance is futile. or We only wish to raise quality of life for all species.1 point
-
Hurumph! I actually have my original Creator disc, sent in the post to me by Gehard Langling (I think that was his name) with a hand written label. This eventually became Logic, and is now rubbish. But back then was amazing. I now use Cubase 8.5 with things like Hollywood Strings and so on, but back then, I had an Emulator 1, and Atari ST (which I replaced with the Mega 4 shown above). My first hard disc was 10 mb, I think. Something stupid like that. But I thought it made me really cool. Other stuff, a little later, were Lynn drums, Jupiter 8 keyboard, Emu 2 (I upgraded), Oberheim and Prophet 10, which was a 2 keyboard version of the Prophet 5. Gaud - this is all a long time ago! Mind you, despite all the computer stuff, I was still recording on 24 track analogue, and George Peckham (who had the office next to mine) was still cutting vinyls for everyone: https://en.wikipedia.org/wiki/George_Peckham Now I feel old, I am going to have my dinner and put on my slippers.1 point
-
Wowee. I admit, though: young as I am, I have seen much of the old days.1 point
-
Er, not totally sure what you mean here. But there are several routes. You could use Repeaters, especially the updated repeaters on the PW 3 branch (and look out for the forthcoming matrix repeaters which would be very powerful) You could use page table, which is similar, but you get to choose where the pages are stored - eg, under the parent that holds all the tabs, or under another parent that is, perhaps, hidden so that that part of the tree does not appear on navigation. You could use a page field so that the client is free to choose pages from wherever you stipulate on the tree. I am not sure what you mean about the ckeditor, but I haven't used repeaters for a while as I have been using page table. When it comes to creating tabs or accordions, then surely you only create them out of the available published and un-hidden pages? So, there will be not tab available to be clicked on, if you see what I mean.1 point
-
1 point
-
Thank you for the input and I know, that "Hamburger Menu" is an anti pattern. However, it was an active decision. I will explain why. First, I'm expecting more traffic from mobile than from desktop devices. It's about 2/3 to 1/3 at the moment. Considering the traffic sources and the market we're operating in, this is probably not going to change. Second: it looks ugly. I played around with a couple of options beforehand and considered various design approaches. Always when I came to the desktop part, I didn't want the menu there. I could just not figure a way to make it look right. Right as in: I am convinced. Maybe I can't design menus. This assumption is therefore right If we had more traffic, we could do some A/B-testing and see what performs better. But this is not the intention as of yet. Performance-driven (as in: maximum conversion rate) sites look different, and this is not one of them. I'd rather set up various campaigns with dedicated landing pages living outside this website.1 point
-
Must say, I'm still quite a fan of 7 - very efficient system. Never really got used to the whole start screen concept, and can't say I'm too fond of the win10 start menu. As much as I use both 8 and 10, I'll always regard 7 as one of the best releases of Windows.1 point
-
Exactly. Meanwhile, I will test out your script on a test-install and see how it goes. Thanks for posting.1 point
-
1 point
-
1 point
-
Well, Internet Explorer 11 runs fine on Windows 7, 8, 8.1 and 10. It's not that they are pushing the Edge browser, which is only available on Win10. I'm not saying that Microsoft isn't pushing Windows 10 but this news is not part of that.1 point
-
I'm talking about InputfieldSelector.module. Also AJAX is only needed if the filters do contain something dynamically changing, which I suspected to not be the case, but you're certainly right, that you'd need jquery or at least javascript.1 point
-
DId you install the Language Support modules and create a new language beforehand? This is just the last step.1 point
-
This is interesting https://www.wordfence.com/learn/2015-wordpress-security-survey/ It is an annual survey of 7000 plus members of the Wordfence community. I was particularly drawn to this line in the conclusion at the bottom: Since many clients coming to PW might well be coming from WordPress, this survey might be useful in client presentations.1 point
-
The homepage does work because apache does simply call the index.php without arguments, whereas the .htaccess does convert urls to something like index.php?it=/path/ which is still the same file.1 point
-
Maybe the admin themes could feature a hook in that place so it could be edited without modifying core files.1 point
-
Currently working on an update with bug fixes, translatable links, and (hopefully) ajax refresh when new pages are added. I should have something ready tomorrow. Edit: Made a lot of progress this weekend but will need a bit more time to iron things out. I was able to get the field to refresh when the Add New modal dialog is closed, which works great for single item selects and allows you to select the new item without refreshing the page. However, for asm-style multi-selects, the refresh wipes out your existing selection when it reloads. Because of this I think that another approach will be required.1 point
-
Video clip showing latest development...(note: previews of other types other than images are still a work in progress...)1 point
-
Yes, but HHVM is also a JIT compiler to PHP like V8 for JavaScript. Yes, in fact it does. I'll make a tutorial the next days.1 point
-
1 point
-
You've been using MODX but now you've found ProcessWire. It’s totally amazed you and you can’t wait to get started. But…you are wondering where everything is. If this is you, read on… This guide is primarily aimed at those who are coming in from MODX and wish to know how to accomplish “MODX things” the “ProcessWire (PW) way”. This is not meant to be a full blown PW tutorial. It will focus on some key MODX concepts/tasks and how to accomplish those in PW. It will cover, whenever possible, both versions of MODX - Evolution and Revolution. The guide assumes that you’ve at least logged into a PW site and/or viewed a demo. The Table of Contents mostly reflects MODX terminology. Table of Contents 1. Manager 2. File System 3. Resources 4. Templates 5. Template Variables (TVs) 6. Template Files 7. Snippets 8. Modules 9. Plugins 10. Chunks 11. Miscellaneous 12. Examples - the PW way… a. Template Variables b. Snippets c. Modules d. Plugins e. Chunks 1. Manager In PW, the “manager” is referred to as the “Admin”. The default location of the Admin is www.yoursite.com/processwire. As of PW 2.3, you can rename the Admin to anything you wish during install. Just be careful to remember the name you use or you will be locked out! (If that happens, there are ways to get around it though). Logging into Admin, you will notice a tree just like in MODX. The Admin runs on jQuery UI and as you’ve seen, it is insanely fast! Don’t be fooled by its simple facade. PW is a really powerful CMS, highly extensible and very easy to use. Customising the PW admin is very easy. There are a number of custom themes available. It is also trivial to make yours. Custom Admin themes go into the folder site/templates-admin/. You can have only one theme at a time. On a related matter, if you wish to create a custom Admin page, it is easy to do so. See this thread for more info. 2. File System After installing PW, you will see two main folders; “site” and “wire” in your file system. Site is where all things related to your site reside. This is your playground and will survive an upgrade. Wire houses the Core. You will never have to go into that folder. 3. Resources In MODX, Resources can be many things (documents, etc.). There is no such term in PW. However, the most important “resources” you need to know about in PW are page and pages. Pages are a very powerful concept in PW. Page can refer to your website’s frontend pages, i.e. what can be viewable by your website users. I say can be for a reason. There are many uses for Pages in PW. This can be confusing to newbies but once you get the concept, you will appreciate the power of the system. Just because something is a Page does not mean it has to be viewable. It can have other uses such as a container that holds data for use by other Pages - in this case the Pages do not have to be displayed on the frontend. In fact, everything you see on the PW tree is a Page. That’s right; even the Admin and its components (Users, Roles, etc.) are all Pages! Still confused by Pages? Have a read here. Pages reside in the PW tree - you may have noticed . You can drag and drop pages to move them around. If drag and drop doesn’t work you probably have MySQL 5.0.5.1 installed. Upgrade your MySQL and you are sorted. The root of your site is the uppermost Page in the tree. In the default PW install this is called Home. You can change the name to something else. The default PW install comes with a number of Pages pre-installed. Try editing a Page. All those Fields you see on that Page when under the “CONTENT” tab? They are not default Fields. They are all Custom Fields! Yes, not even the Title! The only required Field for a Page is “name”. You find this under the “SETTINGS” tab on the page edit screen. More about Fields below… Other related stuff: Menuindex: As an aside, if outputting something like a menu, unless you state otherwise, it will reflect the tree hierarchy. Show in Menu: This functionality is covered by the Page status, whether hidden or not. Hidden pages do not get output on menus (more about menus later) unless explicitly stated so using PW API selectors (see below). Menu Title: No such term in PW. You can name your menu items what you wish to name them. Very important: All Pages must be assigned a Template. 4. Templates In PW, Templates mean something slightly different compared to MODX and many other CMS. MODX describes templates as: That is not entirely true of PW Templates. In PW, the term Template is used in the sense of the English definition of the term: PW Templates serve as a pattern for the foundation of your Pages. By foundation, I do not mean the HTML or CSS. Rather, the Template servers as blueprint for your Pages. What is available to the Template is available to the Page that uses it. Templates establish a pattern for the Pages by the inclusion of Fields to the Template. A Template can have as many or as few Fields as you wish. You can create as many or as few Templates as you wish. You can easily change the Template a Page uses when editing the Page. See under SETTINGS. Note that if you have Fields on that Page that are not in the Template you are switching to, those Page Fields will be lost! PW will warn you about this when switching Templates though. OK, so how do you show “Resources to the world”? That will be the work of Template Files which we’ll look at in section 6. 5. Template Variables A powerful feature of MODX is Template Variables (TVs). If you loved MODX TVs you will absolutely adore the PW equivalent. In PW, TVs are known as Fields. You can define your own Custom Fields. In fact, you will need to create your own in most cases. This is because PW does not have any required Field except for “name”. It is perfectly reasonable to have a Page with only the name Field! Many people do add at least a Title Field for such Pages. In the default PW install, the reason you see the Title Field in all Templates is because it has been set as a “Global” Field under the ADVANCED settings of the Field (edit the Field to see this setting). There are many types of Fields to hold all sorts of data - images, texts, urls, passwords, reference to Pages, etc. You can call your Fields anything you wish. You can call the Field for your main content “body”, or “stuff”, or “content” or whatever you wish as long as you follow the naming convention, i.e. “[a-z], numbers [0-9], or underscores (no dashes or spaces)”. Fields are reusable across different Templates. The order in which they appear on your Page follows the order in which they are arranged on your Template. However, it is important to note that: The order in which Fields appear on your page and/or the inclusion of a Field on your Page does not mean that: The Field will be output on the Frontend. The inclusion of a Field on a Page does not automatically mean it will be output; PW does not make that decision for you. It only makes the Field available to you to use as you require. You can output all or none or few of the Fields on your Page. The order in which Fields appear on a Page does not mean the same order will be reflected when you output the Page. You make that decision. Also note that you are able to arrange Fields side-by-side on your Page (via settings on the Page’s Template) to mimic your site’s layout or for other visual/ease-of-use purposes as you edit the Page in the Admin. You can also give each Field a label and a description. These will appear above each Field when editing a Page. In most cases, the content of Fields will be saved directly to the database. In the case of file related Fields, the path to the file will be stored in the database. There are no direct equivalents of MODX TVs “@Bindings” (data sources). These are inherently built into the different types of Fields. Note that you cannot run PHP code within Fields (so no @Eval). This is by design. Fields are a very powerful and much loved concept in PW. Just Google "custom fields cms" and you’ll see what comes up tops. 6. Template Files So far, we've seen that you create Fields, add them to a Template you've created and edit a Page using that Template to input your content into that Page’s Fields. So far so good but how do you output the content to the world? You do this via Template Files. Template Files live in /site/templates/. You have to create your own Template Files. In MODX, a Template will have both system fields, e.g. body, title, etc. and custom fields (TVs). Rendering a Template is achieved by adding MODX tags to your Template. In PW, in order for the content of your Page to be seen by the world, its Template must have a Template File (or there must be some other Template File associated with a different Template that is dynamically pulling and outputting elsewhere the content of a Page whose Template does not have a Template File). This does not mean that all content within a Page will be automatically output by the Template File. No; in the Template File you can choose to render all or some Fields present in the Pages using that Template or none at all! You tell the Template about the associated Template File when you create/edit the Template. PW assumes that there is a Template File with the same name as the Template in /site/templates/ and will tell you if it does not find one. However, you have two other choices. You can either enter an alternative name for your Template File or tell PW you do not wish to have a Template File for that Template. This means that a Template does not require a Template File. Obviously, in such a case, you will not be able to directly output the content of the Pages using that Template. In some cases, that is exactly what you want . As you get to know more about the system, you will find out how powerful and flexible the PW Template system can be. For instance, you can use your Template as a controller. That’s beyond this guide but feel free to search the forums for more info. Template Files are typically PHP files with logic to dynamically output your content. In most cases, Template Files are HTML with PHP tags inserted to output your content. The PHP in the Template File will in most cases be PW API. Hence, you will see things like $page and $pages in Template Files. The former always refers to the current Page and the latter to any other Pages in the system. These are very powerful variables in PW and give you access to ALL information about ALL pages including their Fields and whether those are empty or not, etc. See below for more info about these variables and have a look the docs too. Note that Templates do not care about what’s in your Template Files. In fact, they won’t even check. All they want is for you to tell them if and how you wish your Pages' contents to be rendered. Your Template Files can even contain pure HTML (although that won’t be dynamic!)! Your Template Files can have references to other things related (or not related!) to the Page using that Template File. For instance, within your Template File, you can pull in the 10 latest “posts” from your Blog or the Children Pages of that Page. There are just too many possibilities to list them all here. Don’t let the PHP in Template Files scare you if you are no coder. I am no coder but I am able to use PW. You will only need to know at least some very basic PHP to use PW. The most important are: echo; foreach; and if… Anything else is a bonus in most cases. In addition, you will need to know how to use the two most important PW variables - $page and $pages. With these two, most of what you would have done in vanilla PHP is covered. They are easy to use and to understand and very much follow the jQuery concept. Check out the docs to learn more. 7. Snippets In MODX, Snippets are the method by which MODX allows you to run dynamic PHP code in any of your pages. In PW, the term Snippets does not exist. What!?! Not to worry; in PW MODX-like Snippet functionality can be achieved in two ways: Template Files: Most PW Template Files are essentially dynamic PHP code. That’s Snippets for you right there. PW Modules: PW Modules do what MODX Snippets do and more (see below). It’s just an issue of terminology. For instance, the popular MODX Snippet WayFinder has a Module counterpart in PW. This is the Module Markup Simple Navigation. However, you do not need to use the Module to create a menu in PW. You can do the same thing using PHP in your Template File. See the default PW install for a simple example. Check out section 12 of this guide for example “popular-MODX-Snippets-to-PW-how-tos”. 8. Modules MODX Evolution defines Modules as “a program that can only be executed from within the manager.” There are PW Modules that fit this definition, for instance, the Module Batcher which is equivalent to the MODX Revolution add-on Batcher. However, there are other PW Modules that are executed in the frontend, e.g. Markup Simple Navigation previously mentioned. In fact, in PW, a Module is PHP that extends the functionality of PW. Modules contain PHP classes that adhere to PW’s Module interface. 9. Plugins In MODX Plugins are PHP code that are set to execute during certain system events. In PW, although the term Plugin does not exist (except maybe in reference to Modules), MODX Plugin functionality is easily doable in PW. This is achieved via Hooks. There is one difference though. In MODX, Plugins are standalone code you can download and install. You cannot download and install PW Hooks. Instead, PW contains many methods that you may hook into in order to modify the behaviour of the method. In other words, PW offers the ability to hook into its processes/events and manipulate them before or after the event or even replace them, etc. Hooks are usually invoked inside Modules. However, Hooks may be attached from anywhere that you use PW's API, for instance in Template Files. The average PW user will not need to use Hooks. For more info about Hooks check the documentation. 10. Chunks MODX defines Chunks as “bits of static text which you can reuse across your site”. There is no equivalent term in PW. You can, however, easily create Chunks in PW. You can create Chunks as a Page that contains various Fields each of which can act as a Chunk. This means you can have Chunks of all sorts of data. You can then set the Page you create to hold your Chunks as hidden (not available to searches). The Page can also be assigned a Template without a Template File to further limit frontend access. It can also be created as a child/grandchild of the page Admin. That will limit access by User (e.g. login required to view it in Admin). Accessing the Fields of that Page as your Chunks using PW API is quite trivial really. Since you can use labels and descriptions to further define each of your Pages’ Fields, this makes it quite easy to describe what each Chunk is for and/or give instructions on how to use the Chunks. See this example for more info. You can also simply use text files to pull into your content as Chunks. Personally I prefer using Pages as Chunks when I need to. In MODX, it is usual for many Snippets to use Chunks (HTML + placeholders) to structure their output (i.e. tpl Chunks). You do not need to do this in PW. Code output can be wrapped in HTML right within the Template File. The important thing to remember is that any Field in any PW Page is available to any other Page and any Template File. Cross-referencing Fields and Pages is child’s play. Seriously; it is that easy. 11. Miscellaneous Tag Syntax: PW does not use a templating language (tagging syntax) like MODX does. See this article why this decision was taken. I agree 100% with the approach and have come to realise its many benefits over using a templating language. However, there are two Modules that allow you to use template language tags in PW. I have never used them so cannot comment further. They are here and here. Settings Page: PW has no settings page like MODX. Many settings are set in the /site/config.php. Other MODX settings equivalents are interspersed in various places including caching content on a Template by Template basis and in Modules. You can also store custom settings needed for your site in the /site/config.php. You can even use Pages to store your settings as mentioned in section 10 (Chunks). Modularity: PW is a very modular system. The whole of PW is made up of Modules (Core Modules) that accomplish different tasks. 12. Examples - the PW way… In this section I will show you equivalent MODX versus PW add-ons as well as how to accomplish various task using PW “Snippets” equivalent. a. Template Variables As previously mentioned, MODX TVs are PW Fields (although PW Fields are more versatile). Outputting the contents of your Fields is very simple. echo $page->name_of_your_field; This gives you the contents of the Field in the current page. Works slightly different for image fields though. For other pages echo: One page $pages->get(ID or PATH or NAME, etc.)->name_of_your_field; //note replace ID with ID of the Page you want, etc. Many pages $pages->find("selectors"); //this will return an array. You can then go through the array using foreach as shown in the examples below to output the field(s) contents MODX - output main content of Page //MODX Evolution[*content*] //MODX Revolution[[*content]] ProcessWire - output main content of Page //ProcessWire echo $page->content;//note; this assumes you have a Field called content in the Template of the current page. In ProcessWire you can find Fields of other pages like so $fruits = $pages->find("template=yumyum, limit=10"); foreach($fruits as $fruit) { echo "<li><a href='{$fruit->url}'>{$fruit->title}</a></li>"; } //find 10 Pages that use the Template yumyum and echo their url and titles in a list. From these examples, you can see the elegance and flexibility of TVs done the PW way. Since there is separation between a Template and a Template File, you can conditionally echo out the contents of Fields found in Pages. b. Snippets Common MODX Snippets and PW equivalent Modules 1. WayFinder: Markup Simple Navigation or code in Template File (see head.inc in default PW installation for a simple menu). 2. Ditto (Evolution) and getResources (Revolution): Functionality inbuilt in PW. Use $page and $pages variables + selectors to find anything, anywhere. 3. Jot (Evolution) and Quip (Revolution): Comments Module is part of the PW Core. It is not enabled by default. You will have to enable it in the Admin. See also the related Comments Manager Module. 4. eForm (Evolution) and FormIt and FormItBuilder (Revolution): There are various Form parser codes in the Forums. There is also a commercial Form Builder Module. It’s not expensive, is developed by PW’s lead developer and proceeds support the PW project. 5. MaxiGallery (Evolution) and Gallery (Revolution): Presently, there is no equivalent. However, it is quite easy to build a photo album. See this tutorial in the wiki. There is also an Images Manager Module (still in alpha though). 6. AjaxSearch: Ajax Page Search Module. 7. Breadcrumbs: Quite easy to accomplish using PW API. See default PW install for an example. 8. FirstChildRedirect: Very easy to do using PW API like this: $session->redirect($page->children->first()->url); in a Template File. 9. getField (Evolution) and getResourceField (Revolution): Inbuilt in PW $page and $pages variables as shown above. 10. GetParent: Inbuilt in PW $page and $pages variables. E.g. $page->parent. 11. getPage: PW has inbuilt pagination as part of the Core (Pagination Markup Module). See this article for a quick tutorial. 12. UltimateParent: Inbuilt in PW API as rootParent. 13. if (Revolution): Use vanilla PHP with PW variable and selectors in Template Files. 14. VersionX (Revolution): Versioning for text-based fields is coming in PW 2.4 (release date summer 2013). Support for maintaining separate draft and live versions coming in PW 2.5 (Winter 2013/2014). Currently, there is also the Module Version Control for Text Fields. 15. getRelated (Revolution): No out-of-the-box Module for this. Has been previously accomplished using PW API in various ways. Have a look in the forums. 16. importX (Revolution): Import Pages CSV Module. 17. phpThumbOf: Thumbnail functionality is inbuilt in PW. There is also the Module Thumbnails that further extends this functionality. 18. getValue and getValues (Revolution): Inbuilt in PW. You can get the value of any Page using PW API - $page and $pages. 19. getFeed (Revolution): RSS Feed Loader Module. 20. MIGX (Revolution): Repeater Module which is part of the PW Core. It is not installed by default. You will need to do that yourself. For more info see this tutorial. 21. Articles (Revolution): See the Blog Profile Module. 22. NewsPublisher (Revolution): See below under Plugins. Examples MODX Ditto [!Ditto? &parents=`5`&extenders=`summary` &tpl=`tplBlog` &orderBy=`createdon ASC`&display=`6` &truncText=`Continue Reading This Article` !] PW equivalent $items = $pages->get(5)->children("sort=date,limit=6"); foreach ($items as $item) { echo $item->title; echo $item->summary;//etc. } //this assumes you have a Field called summary on that Page The first line in the above gives you all information about the 6 child Pages of the Page with ID #5. It returns an array. In other words, a basket of various documents containing all the info about those documents. Next, you traverse the array using foreach. In layman terms, you rummage through the basket picking goodies! In order to wrap HTML around the code output, we do it like this instead (there’s other ways to do it as well!) echo "<ul class='articles'>"; foreach($pages->get(5)->children("sort=date,limit=6") as $item) { echo "<li><p><a href='{$item->url}'>{$item->title}</a><br /> <span class='summary'>{$item->summary}</span></p></li>"; } echo "</ul>"; In this example, we have asked PW to grab the child Pages directly within the foreach rather than creating a variable $items first. MODX getResources // Output a list of child Resources of the current Resource, using the 'myRowTpl' chunk: [[!getResources? &parents=`[[*id]]` &tpl=`myRowTpl`]] PW equivalent echo "<ul>"; foreach ($page->children as $child) { echo "<li><a href='{$child->url}'>{$child->title}</a></li>"; } echo "</ul>"; //You might want to limit the number of child Pages you are getting if they are many! MODX getResources // Output the top 5 latest published Resources beneath the Resource with ID '5', with tpl 'blogPost': [[!getResources? &parents=`5` &limit=`5` &tpl=`blogPost` &includeContent=`1`]] PW equivalent echo "<h3>Latest Posts</h3>"; $posts = $pages->get(5)->children("limit=5"); foreach ($posts as $post) { echo $post->body; } c. Modules 1. Batcher and Docmanager (Revolution): Batcher Module (covers most equivalent functions). 2. DocFinder (Evolution): Inbuilt in PW default install. d. Plugins 1. QuickManager (Evolution): Several Modules can do this, i.e., Fredi, Page Frontend Edit and Inline Editor Modules. 2. ManagerManager (Evolution): Same functionality can be achieved using Templates, Access Control and the Modules Page Edit Field Permission, Page Edit Per User and Page Edit Per Role. e. Chunks See this example. Btw, the PW Cheat Sheet is you best friend... Hope this has been helpful! /kongondo1 point