Search the Community

Showing results for tags 'tutorial'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Welcome to ProcessWire
    • News & Announcements
    • Showcase
    • Wishlist & Roadmap
  • Community Support
    • Getting Started
    • Tutorials
    • FAQs
    • General Support
    • API & Templates
    • Modules/Plugins
    • Themes and Profiles
    • Multi-Language Support
    • Security
    • Jobs
  • Off Topic
    • Pub
    • Dev Talk

Product Groups

  • ProDrafts
  • ListerPro
  • ProFields
  • ProCache
  • Form Builder
  • Likes
  • ProDevTools
  • Custom Development

Categories

There are no results to display.


Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Website URL


ICQ


Yahoo


Jabber


Skype


Location


Interests

Found 22 results

  1. In this tutorial I will cover how to use clsource's REST Helper classes to create a RESTful API endpoint within a PW-powered site and how to connect to it from the outside world with a REST client. This is a quite lengthy tutorial. If you follow all along and make it through to the end, you should get both, a working REST API with ProcessWire and hopefully some more basic understanding how these APIs work. As always with PW, there are many ways you could do this. My way of implementing it and the code examples are loosely based on a real world project that I am working on. Also, this is the first tutorial I am writing, so please bear with me if my instructions and examples are not that clear to understand. And please let me know if something is missing or could be made more clear. The steps covered: create templates and pages in the PW backend to get an API endpoint (an URL where the API can be accessed at) copy and save the REST Helper classes to your site create a template file and write some logic to receive and process data through our endpoint and send data back to the REST client test the whole setup with a Browser REST Client Addon I will not go into fundamentals and technical details on how RESTful APis are supposed to work. I assume that you have already read up on that and have a basic understanding of the principles behind that technology. Some helpful resources to brush up your knowledge: https://en.wikipedia.org/wiki/Representational_state_transfer http://www.restapitutorial.com/lessons/whatisrest.html The complete pages.php template is attached to this post for copy/paste. Lets get started. 1. create templates and pages in the PW backend to get an API endpoint (an URL where the API can be accessed) First we need to create some templates and pages in the PW backend to make our REST API accessible from the outside world through an URL (API endpoint). In my example this URL will be: https://mysite.dev/api/pages/ Note the "https" part. While this is not mandatory, I strongly recommend having your API endpoint use the https protocol, for security reasons. Further down in step 3 we will use this URL to create new pages / update and get data of existing pages. Go to your PW test site admin and: create 2 new templates: one is called "api", the other one "pages". For a start, they both have only a title field assigned. Just create the templates. We will create the corresponding files later, when we need them. enable "allow URL segments" for the "pages" template. We will need this later to access data sent by the requests from the client. in the Files tab of the "pages" template check "Disable automatic append of file: _main.php" create a new page under the home page with title, name and template "api" and set it to hidden create a child page for the "api" page with title, name and template "pages" The pagetree should look somewhat like this: Ok, now we're all set up for creating our API endpoint. If you browse to https://mysite.dev/api/pages/ you will most likely get a 404 error or will be redirected to your home page as we do not have a template file yet for the "pages" template. We will add that later in step 3. 2. copy and save the REST Helper classes to your site I have the REST Helper class sitting in site/templates/inc/Rest.php and include it from there. You could save it in any other location within your site/templates folder. I forked clsource's original code to add basic HTTP authentication support. Click here to open my raw gist, copy the contents and save them to /site/templates/inc/Rest.php In the next step we will include this file to make the classes "Rest" and "Request" available to our template file. 3. create a template file and write some logic to receive and process data through our endpoint and send data back to the client This will be the longest and most complex part of the tutorial. But I will try to present it in small, easy to follow chunks. Since we access our API at https://mysite.dev/api/pages/, we need to create a template file called "pages.php" for our "pages" template and save it to /site/templates/pages.php. Go ahead and create this file (if you're lazy, copy the attached file). Now right at the top of pages.php, we start with <?php require_once "./inc/Rest.php"; to include the REST Helper classes. Next, we initialize some variables that we will keep using later on // set vars with the default output $statuscode = 200; $response = []; $header = Rest\Header::mimeType('json'); 3.1 retrieve data with a GET request Now that we have the basics set up, we will next create the code for handling the easiest request type, a GET request. With the GET request we will ask the API to return data for an existing page. To let the API know which page it should return data for, we need to send the page id along with our request. I am attaching the page id as an url segment to the API endpoint. So the URL that the client will use to retrieve data for a page will look like: https://mysite.dev/api/pages/1234 where 1234 is the unique page id. Add following code to pages.php // if we have an urlsegment and it is a numeric string we get data from or update an existing page: handle GET and PUT requests if($input->urlSegment1 && is_numeric($input->urlSegment1)) { $pageId = $input->urlSegment1; // GET request: get data from existing page if(Rest\Request::is('get')) { // get the page for given Id $p = $pages->get($pageId); if($p->id) { $pdata = ["id" => $pageId]; // array for storing page data with added page id $p->of(false); // set output formatting to false before retrieving page data // loop through the page fields and add their names and values to $pdata array foreach($p->template->fieldgroup as $field) { if($field->type instanceof FieldtypeFieldsetOpen) continue; $value = $p->get($field->name); $pdata[$field->name] = $field->type->sleepValue($p, $field, $value); } $response = $pdata; } else { //page does not exist $response["error"] = "The page does not exist"; $statuscode = 404; // Not Found (see /site/templates/inc/Rest.php) } } } else { // no url segment: handle POST requests } // render the response and body http_response_code($statuscode); header($header); echo json_encode($response); Lets brake this down: First we check for a numeric url segment which is our $pageId. Then the Rest Request class comes into play and checks what type of request is coming in from the client. For the GET request, we want to return all data that is stored for a page plus the page id. This is all good old PW API code. I am using the $pdata array to store all page data. Then I am handing this array over to the $response variable. This will be used further down to render the JSON response body. If the page does not exist, I am setting an error message for the $response and a status code 404 so the client will know what went wrong. The else statement will later hold our POST request handling. The last 3 lines of code are setting the header and status code for the response and print out the response body that is sent back to the client. You can now browse to https://mysite.dev/api/pages/1 where you should see a JSON string with field names and values of your home page. If you enter a page id which does not exist you should see a JSON string with the error message. Lets move on to updating pages through a PUT request 3.2 update pages with a PUT request Since our API needs to know the id of the page we want to update, we again need to append an id to our endpoint url. In this example we will update the title and name of our homepage. So the request url will be: https://mysite.dev/api/pages/1. For the GET request above, anyone can connect to our API to retrieve page data. For the PUT request this is not a good idea. Thus we will add basic authentication so that only authorized clients can make updates. I use basic HTTP authentication with username and password. In combination with the https protocol this should be fairly safe. To set this up, we need an API key for the password and a username of our choosing. We add the API key in the PW backend: add a new text field "key" and assign it to the "api" template. edit the "api" page, enter your key and save. (I am using 123456 as key for this tutorial) Now add following code right after the if(Rest\Request::is('get')) {...} statement: // PUT request: update data of existing page if(Rest\Request::is('put')) { // get data that was sent from the client in the request body + username and pass for authentication $params = Rest\Request::params(); // verify that this is an authorized request (kept very basic) $apiKey = $pages->get("template=api")->key; $apiUser = "myapiuser"; if($params["uname"] != $apiUser || $params["upass"] != $apiKey) { // unauthorized request $response["error"] = "Authorization failed"; $statuscode = 401; // Unauthorized (see /site/templates/inc/Rest.php) } else { // authorized request // get the page for given Id $p = $pages->get($pageId); if($p->id) { $p->of(false); $p->title = $sanitizer->text($params["title"]); $p->name = $sanitizer->pageName($params["name"]); $p->save(); $response["success"] = "Page updated successfully"; } else { // page does not exist $response["error"] = "The page does not exist"; $statuscode = 404; // Not Found (see /site/templates/inc/Rest.php) } } } Breakdown: We check if the request from the client is a put request. All data that was sent by the client is available through the $params array. The $params array also includes $params["uname"] and $params["upass"] which hold our API user and key. We set API key and user and check if they match with the values that were sent by the client. If they don't match we store an error message to the response body and set the appropriate status code. If authentication went through ok, we get the page via PW API and update the values that were sent in the request body by the client. Then we put out a success message in the response body. If the page does not exist, we send the appropriate response message and status code, just like in the GET request example above. Now you might wonder how the client sends API user/key and new data for updating title and name. This is covered further down in step 4. If you want to test the PUT request right now, head down there and follow the instructions. If not, continue reading on how to setup a POST request for creating new pages. 3.2 create new pages with a POST request Final part of the coding part is creating new pages through our API. For this to work we need to implement a POST request that sends all the data that we need for page creation. We will do this at our endpoint: https://mysite.dev/api/pages/ Paste following code within the else statement that has the comment "// no url segment: handle POST requests": // POST request: create new page if(Rest\Request::is('post')) { // get data that was sent from the client in the request body + username and pass for authentication $params = Rest\Request::params(); // verify that this is an authorized request (kept very basic) $apiKey = $pages->get("template=api")->key; $apiUser = "myapiuser"; if($params["uname"] != $apiUser || $params["upass"] != $apiKey) { // unauthorized request $response["error"] = "Authorization failed"; $statuscode = 401; // Unauthorized (see /site/templates/inc/Rest.php) } else { // authorized request // create the new page $p = new Page(); $p->template = $sanitizer->text($params["template"]); $p->parent = $pages->get($sanitizer->text($params["parent"])); $p->name = $sanitizer->pageName($params["name"]); $p->title = $sanitizer->text($params["title"]); $p->save(); if($p->id) { $response["success"] = "Page created successfully"; $response["url"] = "https://mysite.dev/api/pages/{$p->id}"; } else { // page does not exist $response["error"] = "Something went wrong"; $statuscode = 404; // just as a dummy. Real error code depends on the type of error. } } } You already know what most of this code is doing (checking authorisation etc.). Here's what is new: We create a page through the PW API and assign it a template, a parent and basic content that was sent by the client. We check if the page has been saved and update our response body array with a success message and the URL that this page will be accessible at through the API for future requests. The client can store this URL for making GET or PUT requests to this page. If you're still reading, you have made it through the hard part of this tutorial. Congratulations. Having our code for reading, updating and creating pages, we now need a way to test the whole scenario. Read on to find out how this can be done. 4. test the whole setup with a Browser REST Client Addon The link in the heading will take you to a place from which you can install the very useful RESTClient addon to your favorite browser. I am using it with Firefox which is still the dev browser of my choice. Open a RESTClient session by clicking the little red square icon in the browsers addon bar. The UI is pretty straightforward and intuitive to use. 4.1 test the GET request Choose Method GET and fill in the URL to our endpoint. If you do not have a SSL setup for testing, just use http://yourrealtestdomain.dev/api/pages/1. If you happen to have a SSL test site with a self signed certificate, you need to point your browser to the URL https://yourrealtestdomain.dev/api/pages/ first in your test browser and add the security exception permanently. Otherwise RESTClient addon won't be able to retrieve data. If you have a test site with a 'real' SSL certificate, everything should be fine with using the https://... URL Hit send. In the Response Headers tab you should see a Status Code 200 and in the Response Body tabs a JSON string with data of your page. now change the 1 i the URL to some id that does not exist in your site and hit send again. You should get a 404 Status Code in the Response Headers tab and an error message "{"error":"The page does not exist"}" in the Response Body (Raw) tab. If you get these results, congrats! The GET request is working. For further testing you can save this request through the top menu Favorite Requests->Save Current Request. 4.1 test the PUT request Choose Method PUT and fill in the URL to our endpoint ending with 1 (http://yourrealtestdomain.dev/api/pages/1). In the top left click Headers->Content-Type: application/json to add the right content type to our request. If you miss this step, the request will not work. You will now see a "Headers" panel with all your headers for this request Click on Authentication->Basic Authentication. In the modal window that pops up, fill in user (myapiuser) and password (your API key). Check "Remember me" and hit Okay. You now should see Content-Type and Authorization headers in the "Headers" panel. Next, we need to send some data in the request body for updating our page title and name. Since we're using JSON, we need to create a JSON string that contains the data that we want to send. As I will update the home page for this example, my JSON reads { "title" : "Newhome", "name" : "newhome" } Be careful that you have a well formed string here. Otherwise you will get errors. Paste this into the "Body" panel of the REST Client addon. Hit send. In the Response Headers tab you should see a Status Code 200 and in the Response Body tabs a JSON string "{"success":"Page updated successfully"}". Now go to the PW backend and check if title and name of your page have been updated. If yes, congrats again. 4.2 test the POST request Choose Method POST and fill in the URL to our endpoint without any page id (http://yourrealtestdomain.dev/api/pages/). In the top left click Headers->Content-Type: application/json to add the right content type to our request. If you miss this step, the request will not work. You will now see a "Headers" panel with all your headers for this request Click on Authentication->Basic Authentication. In the modal window that pops up, fill in user (myapiuser) and password (your API key). Check "Remenber me" and hit Okay. You now should see Content-Type and Authorization headers in the "Headers" panel. Next, we need to send some data in the request body for updating our page title and name. Since we're using JSON, we need to create a JSON string that contains the data that we want to send. I will create a new page with template basic-page and parent /about/ for this example, my JSON reads { "template" : "basic-page", "parent" : "/about/", "title" : "New Page created through api", "name" : "newapipage" } Be careful that you have a well formed string here. Otherwise you will get errors. Paste this into the "Body" panel of the REST Client addon. Hit send. In the Response Headers tab you should see a Status Code 200 and in the Response Body tabs a JSON string "{"success":"Page created successfully","url":"https:\/\/mysite.dev\/api\/pages\/1019"}". Now go to the PW backend and check if title and name of your page have been updated. If yes, you're awesome! Summary By now you have learned how to build a simple REST API with ProcessWire for exchanging data with mobile devices or other websites. Notes I tested this on a fresh PW 2.7.2 stable install with the minimal site profile and can confirm the code is working. If you experience any difficulties in getting this to work for you, let me know and I will try to help. There purposely is quite a lot of repetion in the example code to make it easier to digest. In real life code you might not want to use procedural coding style but rather separate repeating logic out into classes/methods. Also, in life applications you should do more sanity checks for the authentication of clients with the API / for the data that is delivered by the client requests and more solid error handling. I skipped these to make the code shorter. RESTful services are by definition stateless (sessionless). My implementation within PW still opens a new session for each request and I haven't found a way around that yet. If anyone can help out this would be much appreciated. And finally big thanks to clsource for putting the Rest.php classes together. pages.php.zip
  2. Simple example for loading template specific CSS file. This example asumes that you have your CSS file in a directory relative to template root. Like: templates/css/my_template_specific.css Also i use in the template a simple text field to hold the name of the CSS file i want to load. I call this field 'css_file' Use what you feel comfortable with. So in your header section of the DOM notice the "page specific CSS" part? Thats were the magic happens. What happens is that we check to see if the file exists in the CSS dir relative to template root. And if it does we load it. Simple and effective. I load all other CSS that is used all over the site in global_styles.css first. And make sure you load template specific last, because then you can easily override CSS in global. DOM header example: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title><?PHP echo($page->title); ?></title> <!-- main CSS --> <link rel="stylesheet" href="<?PHP echo($config->urls->templates); ?>css/global_styles.css"> <!-- page specific CSS --> <?PHP /* Use relative path in file_exists() */ if(file_exists('css/' . $page->css_file)) { echo("<link rel=\"stylesheet\" href=\"{$config->urls->templates}css/{$page->css_file}\">"); } ?> </head> <body> Thats my way of doing it. I am sure there is plenty of more ways to do it. This is for the newbies or anyone that wants more options. Good luck with your CSS out there in Cyberspace. Cheers from EyeDentify
  3. Hello, I am completely new at PW, (and Php) coming from another CMS. I decided to try to understand the beast, before crafting anything. So, I started from the beginning: the simple web site tutorial. I am trying to output the Home page with Head and footer included in. Here is my Home page code: include("./includes/head.inc.php"); echo "<h1>{$page->title}</h1>"; include("./includes/scripts.inc.php"); include("./includes/foot.inc.php"); Here is my Head.inc.php code: <?php require_once("./includes/functions.inc.php"); ?> <!doctype html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="description" content="<?php echo $pages->get("/site-settings/")->site_meta_description; ?>"> <title><?php echo $pages->get("/site-settings/")->site_meta_description;?></title> <link rel="stylesheet" href="<?php echo $config->urls->templates?>css/simplegrid.css" /> <link rel="stylesheet" href="<?php echo $config->urls->templates?>css/site.css" /> </head> <body> And this the message I got, when I try to view my page: Compile Error: require_once(): Failed opening required 'C:/wamp64/www/processwire-master/site/templates/includes/includes/functions.inc.php' (include_path='.;C:\php\pear') (line 1 of C:\wamp64\www\processwire-master\site\assets\cache\FileCompiler\site\templates\includes\head.inc.php) Any advice would be helpful Thank you for your time.
  4. HELLO ALL! Context: I use serverpilot to setup and administrate my server patches for my hosted sites. As with many other serving companies, they write tutorials to setup software on their service. I asked them to provide a PW installation instruction and they have obliged however hitting on the following issue on installation with their default linux user: Issue: Basically at the end of the installation there is a warning to secure your config file which could have been done already by the system, I believe they're saying. Is there anything we can do with this, or should i ask them to carry on with the caveat that they should but in a bit of text saying this warning is normal and can be sorted in teh follow ways etc...? Interested in people's opinion.
  5. Hi guys so currently am writing a detailed tutorial about creating Modules, I have never created a module because i don't know all the classes and interfaces required, so this is like a detailed research for me, this is how i learn things by writing articles. However I might make some mistakes so i decided to make it on Google Docs to get comments and feedback, before posting on my website and Processwire tutorial site, this is going to be one heck of a detailed tutorial. Here is the link I will be updating it https://docs.google.com/document/d/1VA_WK-5qbnq3Ux_EOW3p92IcjbAcVZJ0aewIiFxmv2Q/edit# However I wanted to get a clear picture of the following Process Class and ConfigurableModule i noticed some modules require it and some don't My interpretation is that Modules with admin setting pages uses ConfigurableModule and Process are modules who require access to $this->pages and that sort Thanks all
  6. Hello, In this tutorial I show how to use the wirePopulateStringTags function in order to improve translatable strings. https://medium.com/@clsource/better-translatable-strings-in-processwire-621e9e6b18ee#.tv2u23j4i Basically it will improve how the strings are shown in the translation administration. echo wirePopulateStringTags( __('There are {count} {items} in the {place}'), ['items' => 'apples', 'count' => 32, 'place' => 'basket'] ); Will render There are 32 apples in the basket And the Translator will see There are {count} {items} in the {place}
  7. benbyf

    Hi! I've been making my first modules and I've created three so far to help me learn. I would love so feedback or pull requests for improvements as I hope to write a tutorial about my work soon. In particular the third modules isn't very finished. git: https://github.com/benbyford/PW-starter-modules/ HelloUserYouSaved - adds message {your user name, page saved} in admin when a page is saved. This module shows how to implement a basic module, get and use variables, create a message in the admin RedirectAdminPages - redirect specific user role to a custom page set in the module config. This module shows how to implement module configuration, using variables saved in the admin, redirecting a user using session->redirect() HotSwapUser - Swap user on the fly in the admin or frontend of your site This module shows how users can be used in a module how to set a user permission how to install / uninstall something within your module how to create a function that can be output in the frontend of your site.
  8. Hi there, my problem is to understand how i can create my own fieldtype. I look into the Events Fieldtype Topic but i don't find any tutorial like creating Processwire Modules. A look into the code dose not help me. The field i want to create stores multiple informations like a address field. "IP, Connection, Hardware, Firmware, Lat, Long" For this i need a FieldtypeNode.module and ImputfieldNode.module right? But what do i need insight this two modules? Where to set the database schema? Much things are so easy in ProcessWire but this let me stuck.
  9. Macrura

    This is a very simple way to display some instructions to the admin users. Before starting, you need to write some docs; they can be a hidden branch of your page tree, using basic-page, or a different template of your choosing. You should make each subject it's own page under the docs so you can output each one under an accordion trigger. Required Module: Admin Custom Pages 1.) Follow all instructions to install the module; Also add the ACP_scripts_and_styles field to the admin template. 2.) Make a new page under admin, called Docs or whatever; assign the process as described in the module instructions. 3.) Make a template in your themes directory to generate the output of the docs page. 4.) Select that template from the page select in the admin custom page you created. 5.) also make a folder to keep your admin custom pages scripts and styles; 6.) create a css file to use for the display output and some basic styles (like ol, ul li etc..) 7.) Add the custom css file to your ACP_scripts_and_styles field. You can use any output you want, but i'm using a nested accordion, which is provided here: http://tympanus.net/codrops/2013/03/29/nested-accordion/ this is the content of the admin custom page: <?php $docs = $pages->get(4259); ?> <div id="docs"> <ul id="cbp-ntaccordion" class="cbp-ntaccordion"> <?php foreach($docs->children as $doc) { ?> <li> <h3 class="cbp-nttrigger"><?php echo $doc->title ?></h3> <div class="cbp-ntcontent"> <?php echo $doc->body;?> </div> </li> <?php } ?> </ul> </div> <script src="<?php echo $config->urls->templates ?>_admin_custom/js/jquery.cbpNTAccordion.min.js"></script> <script> $( function() { $( '#cbp-ntaccordion' ).cbpNTAccordion(); } ); </script> you'll also want to add the provided css, js and fonts that come with the Nested Accordion; in the css file you'll need to point the fonts to the actual font directory, for example: /site/templates/_admin_custom/fonts/icomoon_arrows/icomoon.eot it should come out looking something like this: *if you are using Reno theme, you can customize the icon, like for example fa-book, which is used in this example: -- Thanks & Credits to Diogo for originally creating the ACP module, and for Nico for getting it to work with the new admin theme system...
  10. Roych

    Hello I'm totaly new to PW and for now I find it very understanding, all but navigations. I tried to find some videos or tutorials explaining about this but noting helpfull comes up. I read i most of the tutorials on the forum that I could find but stil cant find the right answer. I'm making my first template and need your help on how do I create a menu like this in WP. I'm not a coder ... but understand a little. <ul class="nav navbar-nav"> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Home <i class="fa fa-angle-down"></i></a> <ul class="dropdown-menu"> <li><a href="index-1.html">Masonry</a></li> <li><a href="index-3.html">Masonry v1</a></li> </ul> </li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Pages <i class="fa fa-angle-down"></i></a> <ul class="dropdown-menu"> <li><a href="about-us.html">About Us</a></li> <li><a href="services.html">Services</a></li> </ul> </li> </ul> right now I'm here but it's not working right. <ul class="nav navbar-nav"> <?php $root = $pages->get("/"); function visit(Page $parent, $enter, $exit=null) { foreach ($parent->children() as $child) { call_user_func($enter, $child); if ($child->numChildren > 0) { visit($child, $enter, $exit); } if ($exit) { call_user_func($exit, $child); } } } visit( $pages->get(1) , function(Page $page) { echo '<li class="dropdown"><a href="' . $page->url . '" class="dropdown-toggle" data-toggle="dropdown">' . $page->title; if ($page->numChildren > 0) { echo '<ul class="dropdown-menu"> <li><a href="$page->url"></li> '; } else { echo '</a>'; } } , function(Page $page) { echo '</li>'; if ($page->numChildren > 0) { echo '</ul>'; } } ); ?> And I want my HOME page also to be shown. Any ideas? Thank you in advance R.
  11. I am looking for a multipurpose, high quality and free to use template to build some video tutorials. It should be responsive and have at least a blog/news section and somthing like a gallery. Additional features, especially multiple(or configurable) colorshemes would be nice. I really don't care if it uses Bootstrap or anything else. Almost any templates i found (and that don't look like crap) forbid to republish them as a Processwire profile (or template for any other CMS) or they have an unclear license. A template under GPL or BSD license would be perfect as i whish to publish the results of the tutorials as PW profiles. Hopefully someone can help.
  12. Hi, I'm doing the "But what if I don't know how to code?" tutorial. I'm at the section labeled: Just one image mate. I can't get the image to display. It's showing the small broken image icon instead of my image. Thanks, Thuy
  13. Hi, for german native speaker i found this: http://lukasepple.de/blog/2012/08/grundlagen-processwire/#x - Thanks Lukas
  14. 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! /kongondo
  15. Here is a quickie! If you use repeaters for sections on a page (good use for repeaters that) then you may want to use anchors to help navigation. The most obvious thing to use is the "name" of the repeater, because repeaters are actually pages and the name field has no spaces. Ah! But there is a problem with repeaters! They are stored as pages under admin, in your page tree, and if you go and look at one you will see that its "name" looks something like: 1401972317-1689-1 Which is less than useful. The next thing to use is the "title" field, but that has spaces, uppercase and the rest. So, here is a quick and dirty little function that I found on StackExcahnge function seoUrl($string) { //Lower case everything $string = strtolower($string); //Make alphanumeric (removes all other characters) $string = preg_replace("/[^a-z0-9_\s-]/", "", $string); //Clean up multiple dashes or whitespaces $string = preg_replace("/[\s-]+/", " ", $string); //Convert whitespaces and underscore to dash $string = preg_replace("/[\s_]/", "-", $string); return $string; } Now all you have to do is use it in your foreach loop for your repeater: function myRepeater (){ $repeaters = wire("page")->my_repeater; $out = ""; foreach($repeaters as $repeater){ $anchor = seoUrl($repeater->title); $out .="<a name='{$anchor}'><h3>{$repeater->title}</h3></a>"; } echo $out; } And there you have it. Your anchors are now-like-this and your SEO is just that tiny bit better. Note: There is probably a neater way to do this, but this is nice and clear and does everything, I think.
  16. IMPORTANT - DO NOT USE THIS FOR A PRODUCTION SERVER This is not strictly a ProcessWire tutorial, except it really is very useful for developing ProcessWire websites. I have just rebuilt my little dev server and it was a right pain - basically, I made the mistake of following a couple of bits of really bad advice. I eventually nailed down the right thing to do in the right order from about three different sources and have decided to write it up. This tutorial will take you through installing a pristine, new version of Ubuntu on an old PC, setting it up to work on your local network (this is NOT a publicly facing server), installing Virtualmin, Samba window shares, and setting up your first virtual server. The main problem I found with the help that I followed, is that no one seemed to link all these install processes together - so a standard install of Ubuntu with Apache would completely mess up Virtualmin and make it all a nightmare. This is a PDF file without screenshots, but to be honest, I am not sure how screenshots of command line is particularly helpful to anyone! Feel free to use this and let me know if it actually worked. NOTE: I am not a sysadmin, so if you find strange errors, you are more likely to find the answer through Google than by asking me - this is just the result of me pulling my hair out for a day or so. I certainly cannot guarantee that this is perfect or even the best way. Installing Ubuntu and Webmin.pdf
  17. I am a complete noob in PW and have zero knowledge on how to use bootstrap. Just installed a fresh installation of PW with pwbootstrap3 site profile. GF's dad ask me to make a website on their new company. Pretty basic business website. Tried Wordpress and can't figure out how to make my own themes as GF's dad told me a specific design layout of the front end which is freakin hard to do in WP for a noob like me. Using a theme with bit of css modification in WP makes me feel highly unsatisfied still with the results. Had to finish the site for atleast in 2 months time. Where can I find a complete tutorial step by step guide on how to make a website using just PW or with pwboostrap3 site profile? So I can make the website quick. Preferably, the type of tutorial that will just shove the steps straight on my mouth. GF's dad look up to me like a PRO I.T. Highly Extremely Pressured.
  18. kongondo

    Hi all, I've finally managed to set up my website where I intend to post ProcessWire tutorials. The site (lessons) is very much WIP. I have tried to make the site as responsive as possible. I have only tested in Chrome and FF. I'd rather write more lessons than test in IE to be honest so I won't pursue that... I will try to post regularly but can't make any promises as to the frequency . I intend to randomly post some pre-planned lessons. I will update this forum post everytime I post something new. If you have questions, pointers, etc about any lesson, or a request for a specific lesson, please post them here. This way, other forum members can assist in answering the questions . Thanks. /k ==================================================================== Edit: 28 August 2014 - Fist Tutorial is up (OK, it's Blog Module documentation ) Creating a Blog in ProcessWire (Blog Module how to) - 28 August 2014 [99% done] Next: 'All you ever wanted to know about ProcessWire Modules [and other cool things]' - COMING very SOON
  19. tarang9211

    Hey guys, I am completely new to Processwire and I would like to know how to get started. I am completely overwhelmed with this concept. I am looking to develop websites using Processwire. Please do let me know of any help!
  20. Hello to all Processwire people, i'm from Spain, migrating from drupal to PW, looking for something less PHP memory heavy (yes, still there are servers with less than 32MB of PHP memory). And for now, quite happy with it, flexible, fast, friendly and fun. But one thing a did not found easily was a starting guide or something like that (till now, just discovered wiki.processwire.com), so my question is, ¿why there is no link to it in any of the main pages? and for a basic website tutorial? The videos are nice but they mostly show a couple of functions and characteristics. By no means i'm trying to rant, be picky, annoy or start a flame war; just the thought about newcomers like myself, looking into a new CMS and not finding a direct link to the wiki or basic tutorial. Best regards.
  21. Mark

    Hi, I am just getting started with Processwire. I'm a keen newbie - I've gone through the great tutorials by Ryan and Joss but feel like I could do with a few more to get up and running. I know good tutorials take a lot of time and effort to create, so I was thinking if it would be possible to fund a pro to make a video? I'm not talking http://drupalize.me Maybe 2-4 hour long video just to get new users working with the interface and api. Funding could go something like this: http://kck.st/WLZpDG
  22. Hi, I am web designer and I want to learn PW by create simple e-commerce website. I've been search around to find solution, comparing every option & weight both it's advantage/disadvantage, I think most solutions out there is too complex or they already make lot of assumption, not to mention the more code means heavier page load. That's why I finally get conclusion that PW is the right answer. Well, the solution not answered yet, but I sense PW have the power to be there. Let say example, Ms. Turner is local bakery which have 50 product under 5 category. She don't need complex shipping since order could be pickup at store or using private delivery courier and of course She don't need sophisticated payment system or any other crap feature. Yes, there is customer for that kind solution, but not for Ms. Turner and hundred millions people out there. All she want is just simple website to accept order. I do aware that there's already tutorial out there, but it's just answer for specific solution. Not to mention how hard it's gonna be when this forum already have ton of pages. If You're not mind, I create this thread so everyone could learn from beginning especially for newbie or copy paste guy just like me to feel the power of PW. This thread would be tutorial creating e-commerce from scratch and the final goal is free theme both front page and admin page specially designed for Ms. Turner and hundred millions small business right there. Apeisa already make awesome module for PW and I already tested it, its work so wonderful so let's complement it. For starting point, let's start from designing the homepage. The content would be: Home - Header (logo, cart toolbar, search) Content - 3 Image Main slider - 6 Featured product -Footer - Quick Link - Social Network Link - Twitter Widget - Newsletter Subscribe What is the best practice from code perspective?