Leaderboard
Popular Content
Showing content with the highest reputation on 10/15/2014 in all areas
-
Overview Mobile Detect uses a lightweight PHP class Mobile_Detect for detecting mobile devices (including tablets). Installation 1a. Clone the module and place MobileDetect in your site/modules/ directory. [OR] 1b. Download it. git clone https://github.com/justonestep/processwire-mobiledetect.git your/path/site/modules/MobileDetect 2. Login to ProcessWire admin and click Modules. 3. Click "Check for new modules". 4. Click "install" next to the new SimpleContactForm module. Usage This Module extends $config and sets the following parameters: $config->mobileDetect = array( 'deviceType' => 'deviceType (phone, tablet or desktop)', 'browser' => 'mobile browser', 'operatingsystem' => 'mobile operatingsystem', 'device' => 'mobile device' ); You can access them where ever you want. See the example below: <body class="devicetype--<?php echo $config->mobileDetect->deviceType?>"> <body class="devicetype--{{config.mobileDetect.deviceType}}"> // twig Results in: <body class="devicetype--phone"> OR<body class="devicetype--tablet"> OR<body class="devicetype--desktop">11 points
-
Hi Macrura, Here's a version for select multiple... <?php class InputfieldSelectMultipleExtended extends InputfieldSelectMultiple { public static function getModuleInfo() { return array( 'title' => __('Select Multiple Extended', __FILE__), 'version' => 1, 'summary' => __('Multiple selection with extended attributes. An enhancement to select multiple', __FILE__), 'permanent' => false, ); } /** * Adds an option with extended attributes */ public function addOption($value, $label = null, array $attributes = null) { if ( is_null($value) || (is_string($value) && !strlen($value)) ) { return $this; } if (null === $attributes) { $attributes = array(); } $extra_atts = $this->extendAttributes($value, $label); $attributes = array_merge($attributes, $extra_atts); return parent::addOption($value, $label, $attributes); } /** * Hook this and return an array with whatever extended attributes you need. * */ public function ___extendAttributes($id, $value) { $atts = array(); /** * Either hook this method to do what you want or implement things directly if this * is the only use of this Inputfield. * For your example you'd grab the fields you want from your page and put into data * attributes... */ $page = wire()->pages->get($id); $atts['data-description'] = $page->description; return $atts; } } Here's how to use it... Save this module as InputfieldSelectMultipleExtended.module in your site/modules directory of a development install of PW. Install it in PW. Edit InputfieldPage's module configuration and add InputfieldSelectMultipleExtended to the inputfields that can represent pages. Create a new Page field and select InputfieldSelectMultipleExtended on the input tab and setup the parent and other fields as required. Add the new page reference field to a template. Add some pages that use this template. Check the HTML of any of the pages using the template and you should see the options for the select have data-description attribute for every page referenced that has a non-empty description field. Hope that helps!6 points
-
Ok, now I got it. It is a bug. For now you can A) set the value for memory_limit to 512M or 1024M or 1G (but not greater than 2G!!) if this is possible for you. or B) If this is not possible for you, you can change this line to be: if($phpMaxMem <= 0) return null; // we couldn't read the MaxMemorySetting, so we do not know if there is enough or not I will file an issue at Github that fixes the setting with -1. Sorry for the inconvenience, I haven't recognized that setting to -1 in the post above:4 points
-
4 points
-
There has definitely been an influx of new very talented coders in the PW world lately. I for one am thankful and am excited about this occurrence. Keep up the good quality work.4 points
-
Thanks for your detailed answers. This leaves me with a really positive impression about the dedication of the Processwire community. Something that is unfortunately missing in the WordPress ecosystem. I will start building my templates and and then step by step incorporate Processwire-functionality. I keep you posted during this process and ask you for advice when I should get stuck. Thanks again. Great support.3 points
-
Hi Macrura, I've just done something similar to this for my current project. I needed to add data-start-time attributes to every option in a select dropdown so I decided to extend the InputfieldSelectMultiple class to provide a replacement addOption() implementation that added the required data attribute as part of the internal attributes array for each option. Here's what I did... public function addOption($value, $label = null, array $attributes = null) { if ( is_null($value) || (is_string($value) && !strlen($value)) ) { return $this; } if (null === $attributes) { $attributes = array(); } $extra_atts = $this->extendAttributes($value, $label); $attributes = array_merge($attributes, $extra_atts); return parent::addOption($value, $label, $attributes); } public function ___extendAttributes($id, $value) { $atts = array(); /** * Either hook this method to do what you want or implement things directly if this * is the only use of this Inputfield. * For your example you'd grab the fields you want from your page and put into data * attributes... */ //$page = wire()->pages->get($id); //$atts['data-description'] = $page->description; return $atts; } I've updated the example above to output data-description. Hope that helps you with some ideas!3 points
-
If you're comfortable building markup, then you should absolutely build your markup first and then convert it into CMS templates. (This is the nice thing about markup-agnostic CMS's like ProcessWire... they do not dictate any sort of structure on you). The general idea is that you will be creating "templates" for your site... so go through your design and figure out which pages are basically the same as each other and which are different. Generally, there will be 1 template for the home page, a few templates for generic interior pages (e.g. "full width", "left sidebar", "3 column"... totally depends on your specific design), then a template for special pages that are related to specific "things"... like individual news articles or individual blog posts or individual portfolio pieces or individual employees, etc. Each "template" consists of your overall site markup, interspersed with editable fields (content areas) -- in general, wherever you see "Lorem Ipsum" text in your design, you'd replace that with a field. Then you will also have some places where you have a little php code to output lists of pages (e.g. "list the 3 most recent news articles on the home page) -- but don't worry, it's not much php code and ProcessWire is very logical and consistent with how you interact with it so it is easier to understand than other systems (in my experience). To speak to your specific requirements: Brochure style / informational sites: Absolutely! This is where CMS's other than Wordpress really shine, because you don't need to shoehorn a brochure site structure into a blogging system. Multiple, editable content areas per page: Absolutely! This is the foundation of ProcessWire... it is entirely up to you to define which fields should be in which page templates (if you've used the "Advanced Custom Fields" plugin in Wordpress, you can think of ProcessWire being an entire CMS based around that concept). Portfolio functionality: Absolutely! Create a template for "portfolio" and set up the fields you want for it (a text field for title, a textarea/CKEditor field for the description, an images field for the photos, see below for "categories"). Latest portfolio items are displayed on the front page (e.g. latest 6): Absolutely! In your "home.php" template file, put some code like this: <?php foreach ($pages->find("template=portfolio,sort=-date,limit=6") as $page) { ?> <a href="<?=$page->url?>"><?=$page->title?></a> <?php } ?> See here for more about querying pages: https://processwire.com/api/variables/page/ Editable slideshow on the front page (text and image): Yep! Create an "image" field, name it "home_slideshow" (for example), and assign it to your "home" template. Then in the home.php template file, put some code like this: <div class="your-slideshow-container-class"> <?php foreach($page->home_slideshow as $image) { ?> <div class="your-slide-class"> <img src="<?=$image->url?>" alt="<?=$image->description?>"> <p><?=$image->description?></p> </div> <?php } ?> </div> <script> //Your slideshow script here... (or include it in your html <head> or down above the closing </body> tag... whatever) </script> See here for more about how to interact with image fields: https://processwire.com/api/fieldtypes/images/ (Also, if you want more complex content in each slideshow slide [more than just an image and a description], you could make it a "Repeater" field and include image, title, description, caption, link to page, etc etc.... as many sub-fields as you need for each slide) News / Blog functionality: Sure... this is where (for better or worse) you will be doing more manual work than in Wordpress. News is rather easy... just create a template for "news", and create a top-level "news" page on your site and have your site editors add new news pages under there. Use the processwire query interface to list out news pages on the top-level index page (like how we did with portfolios on the home page). For "Blog Functionality", what exactly do you mean? Check out Ryan's "blog profile" for a lot of examples on how to structure this kind of thing: http://modules.processwire.com/modules/blog-profile/ Latest news / blog excerpts are displayed on the front page: Oh yeah! Same idea as the portfolios (just change the "template" you're retrieving to "blog" or "news", if that's what you named those templates). Custom contact forms: This one is tricky. There is a paid plugin for forms: http://modules.processwire.com/modules/form-builder/ ... I've not used it myself, I'm sure it's nice (although it seems like it might be difficult to skin it with your own markup... not sure about that though because I haven't used it yet). Doing forms yourself could be possible with more work, for example: https://processwire.com/talk/topic/2089-create-simple-forms-using-api/ . In general, this seems like a problem that has not been solved perfectly yet (outside of the paid plugin of course, which is surely worth the money if building a site for a paying client, but maybe not so much when just experimenting with a system as you and I are right now). One last note about categories and tags: This is a bit different than other systems. It seems that in ProcessWire, when you need custom stuff, you implement it as templates and pages. So you create hidden pages with sub-pages under them, and these act as sort of database records (kind of, I think?). Here is a great explanation of how to create a tags system using this method: https://processwire.com/talk/topic/3942-help-for-creating-tags-please/?p=38605 ...and also check out the aforementioned "blog profile" to see a working example of how this is implemented: http://modules.processwire.com/modules/blog-profile/ . Hope that helps! (Also note that I'm relatively new to ProcessWire myself... although I have a ton of experience with other CMS's... so hopefully others will pipe in with more detailed or accurate info if I've missed anything or gotten anything wrong).3 points
-
TinyMCE as the default RTE ? I'm guessing the new growth is a combination of things...2.5, RenoTheme, ListerPro, ProFields, lull from other CMS progress, friendly community. And in the background, Ryan's constant patience, enthusiasm, productivity and all round genuine positivity and transparency. At least they're my own magnets. Interested to read others interpretation.2 points
-
To get back to the topic of tools we are using: Trello for the general project management. Each customer or projects gets a board. Metanet Webhosting for E-Mails to communicate with customers. Dropbox so share and sync files in a team folder Slack as a tool to combine al possible other channels and to chat together. It's new but we like it. Our custom CRM to track customers and make bills/qutations 2-weekly meetings to discuss and review stuff.2 points
-
Here's a couple of thoughts... https://processwire.com/talk/topic/4602-flexible-downloads-using-pages/ https://processwire.com/talk/topic/5177-download-file-statistics/ https://processwire.com/talk/topic/1323-downloading-file-after-form-submission/ https://processwire.com/talk/topic/5292-proctecting-files-from-non-logged-in-users/2 points
-
Can you bump up the available memory for PHP? It is explained here in detail: https://processwire.com/talk/topic/7749-max-image-dimensions-not-a-recognized-image-bug/ So as the factor setting actually in PW is 2.5, I will ask Ryan to set it to 2.2 by default. Edit: have sent a question to Ryan: https://github.com/ryancramerdesign/ProcessWire/issues/7392 points
-
2 points
-
I would ask Ryan to make the method hookah Le. So no need for extendingm I think it can be useful in cases like this.2 points
-
@netcarver - can't thank you enough -this completely works!! I added a js file to populate my description field above the select, and changed the module name to be select, not multiple.. will have to do a screenshot/screencast; this module should be made available in some form on the directory, as i think it has some great use cases for data- attributes on selects... maybe both versions, select and select multiple2 points
-
The best way to learn (in my opinion) is to carefully break down the default site profile.Everything you mentioned above can easily be done with ProcessWire - even without any special Modules! ANSWERS: 1. - There's a fella around here by the name of Joss. He doesn't know PHP. He isn't a coder, but he's the one responsible for many of the brilliant tutorials here. I too (me neither) I'm not a coder. I always forget how an ifelse statement works, so I spend much of my time Googling things, or reading the documentation on PHP.NET. So to answer your question: very realistic. 2. - Depends how quickly you can grasp the concepts: the API is incredibly powerful Read over it all. Try every code snippet you come across. Same for the Cheatsheet. Then you have establish a workflow. Figure out how the Templates and Pages and Fields all interact and connect with each other. Time frame? Couple days to a few months. ME? Personally? I've been on these forums for over a year and I've barely started working on my first CLIENT website. Your time frame may vary. 3. - That's usually how it's probably best done. Especially if you're still quite new. Use your favorite CSS framework and your favorite jQuery plugins, then copy over yours files, one, by, one ... into the "/site/templates/" folder.2 points
-
@sforsman + kongondo Thanks a lot for your suggestions. I'll have a look at Ryans Event Field type code and get back here if I have questions.2 points
-
Just create a custom Fieldtype (module) that stores the timestamps properly in a table designed for the purpose. Saving and querying them would then be blazing fast and no need for dirty tricks like comma delimited values on a blob field (which wouldn't obviously be very flexible to query on - especially if you need comparison operators - nor would it be very flexible to modify the values). If you need help implementing such Fieldtype, just let me know.2 points
-
2 points
-
1 point
-
Since February 2013 there were some changes with PW and thirdparty modules. Now you can use PageImageManipulator for this.1 point
-
http://stackoverflow.com/questions/46585/when-do-you-use-post-and-when-do-you-use-get i think POST should work.1 point
-
We are dedicated. We are a FANTASTIC community. We look forward to your progress1 point
-
Sounds it's gonna work with wireSendFile you've all possibilties like counting or setting a fieldvalue like mentioned in the comments on soma's original blog.... http://soma.urlich.ch/posts/flexible-downloads-using-pages/ codeexample from soma's comment: $page->of(false); $page->counter += 1; $page->save(); $page->of(true); wireSendFile($page->pdf->filename, $options); even you could create your fields on some sort of downloadstats (username, email, checked terms) under a parent page like: -other pages --download-stat-home ---download1 (fields: username,date,email,checked terms, witch file/page) ---download2 so you've all options to analyse all downloads...and check if the userentry in the "saved" download-stats page = checked terms true - and then deliver the file. This is just a mindgame from me - nothing that i build - someone correct me if this could be done in a better way.... regards mr-fan1 point
-
That may be a great test, however what are the PHP.ini limits set at? The PHP.ini memory settings will have an effect on why you're having your problem, no matter what you may be able to do with on that test. Windows and IIS has it's quirks.1 point
-
can you enable the multilanguage description option an dfill out the default-language with the text you want use for the single-description field? Just for testing?1 point
-
This works for me: $x = $pages->find("template=mytemplate, $myfield=''");1 point
-
Agree with Charles on this. This forum is pushing my learning process in a very positive way from html to php and am very thankful for this.1 point
-
If you need more than the description field to be translated, you can use the Module FieldtypeImageExtra.1 point
-
I felt the same need, that's why I build a little Module to handle multi-language Image Descriptions and further image informations. Have a look at the module FieldtypeImageExtra, maybe it helps you.1 point
-
If the problem is that you're getting too many results, have you tried using other operators, such as *=, instead of %=?1 point
-
some other links Rating Pages https://processwire.com/talk/topic/7871-page-ratings/#entry76186 Flagpages https://processwire.com/talk/topic/7044-release-flagpages/ Bookmark pages https://processwire.com/talk/topic/7886-page-bookmarks/ Add remember - all are pages so Users are pages, too. This means that if i "bookmark" a users page -> i'm a follower of this "page=user". If i remeber right the user bwakad builds some kind of social powered website, may you send him a message. regards mr-fan1 point
-
Here's how it worked for me in CKEditor (in case you persist on this route - but I would go for Hanna Code as Adrian suggested. As usual, the "culprit" is our friend HTML Purifier (read from here up to and including Ryan's comment here about its pros and cons before deciding whether to implement #5 below!) For iframes, the Extra allowed content seems to have no effect - btw, the correct syntax here is for example, div(*) not div[*] Add 'Iframe' (note the spelling) to your CKEditor Toolbar Leave ACF on No need to switch the field's "Content Type" from "Markup/HTML" to "Unknown" Turn HTML Purifier off (gasp! ) Enjoy your embedded video1 point
-
1 point
-
Picking up on sforsman's idea, have a look at Ryan's Event Fieldtype, especially how he stores timestamps. Pretty straightforward: https://processwire.com/talk/topic/5040-events-fieldtype-inputfield-how-to-make-a-table-fieldtypeinputfield/1 point
-
I don't have much free time to do it. I will return soon Thanks nico good idea1 point
-
Hi Neo, welcome. Your requirements should be no problem with ProcessWire. Even with a limited PHP knowledge, you will get used to the API quite fast. To your questions: - Of course it is possible. You need a basic understanding of PHP (loops,ifelse,variables) but nothing more than a usual template language or the WordPress markup would require. Y - A higher time because you will have to learn some stuff before. Maybe start with a smaller page as you suggested and then move forward. - You could do it this way. Build the HTML/CSS/JS and then replace everything with dynamic content from ProcessWire. Did you look at the Cheatsheet already? And maybe this tutorial is interessting to you. Hopefully someone will give you a more detailed answer, I have to leave now.1 point
-
Until I bought Lister Pro, I did not fully realize how much it could increase your productivity. Working with the tree (or using the built-in search engine for quicker access) is intuitive, and I'd say fast enough in most cases, but it's a one-size-fits-all solution. With the tree, there's no easy way to group pages under different parents, or search for pages that fit one or more criteria and view and edit them quickly. Since Lister Pro is a customizable search engine, you can target with precision which criteria you'd like to use to return the pages you'd like to view and/or edit. In a few clicks, I can set up my own results in a easy-to-scan table view. You can save these results, and they show up under the "Pages" dropdown menu for quick access, which for me wasn't clear from Ryan's description of the plugin. This is incredibly powerful. Let's take an example. Let's say I run an Website showing cultural events across the US, organized by cities (New York, Washington, DC, etc.) and categories (Music, Performing arts, etc.). I have various editors. One of them would like to view only the events he's been assigned to, e.g. all music events created this year in Washington, DC. I can easily create a customizable admin view for him: The results look like this (the columns can be adjusted to your needs of course, and the editor can also filter the results even further): The editor has super quick access to his own "admin view" from here (I've called this page "Recent events" in this example): I can go ahead and create various views for each of my editors. If I work alone, I can do the same to gain quick create, view and/or edit access to whatever views I choose. I hope you can see the power of this module, and I'm not even talking about the included actions that let you manipulate the results, such as email users, exporting to CVS (very useful to export results for offline data analysis in Excel), etc.1 point
-
Nico, most of your clients seem to be pretty blurry, but that one fellow is exceptionally bright!1 point
-
The reason that template change is disabled (or rather just hidden) is that when changing template, adminbar doesn't know how to show the confirm page (on template change), because it redirects before that. When creating new page, then I think it's ok to have template select. Not sure which is better/simpler fix: showing it always and handling template confirmation on change situation - or just like now but making sure template select is available when creating new page. Reason this is little bit "non issue" for me personally is that I have 99% time only one template allowed.1 point
-
1 point
-
Just use the wonderful CropImage module. Say, you have a 300x300 image in your template. Define one 300x300 called "thumb" and one 600x600 crop called "thumb2x". Now you can use the picture polyfill like this: <picture> <img srcset="<?= $page->myimage->eq(0)->getThumb('thumb') ?>, <?= $page->eq(0)->myimage->getThumb('thumb2x') ?>, 2x" alt="<?= $page->myimage->eq(0)->description ?>"> </picture> Adding additional breakpoints with <source> is also possible (from the picturefill docs): <picture> <!--[if IE 9]><video style="display: none;"><![endif]--> <source srcset="examples/images/large.jpg, examples/images/extralarge.jpg 2x" media="(min-width: 800px)"> <source srcset="examples/images/small.jpg, examples/images/medium.jpg 2x"> <!--[if IE 9]></video><![endif]--> <img srcset="examples/images/small.jpg, examples/images/medium.jpg 2x" alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia"> </picture> So you can also do some art direction where you output not only different sizes but also different formats (for example 2:1 on mobile, 1:1 on desktop etc)1 point
-
Probably not. The Table ProField is good for repeated tabular information. If your user profile needed to include a links, memberships, family members or something like that (each with multiple properties) then the Table field would be good. But the examples you listed all sound like they would still be best kept as separate fields to me. The only exception would be that I think you might potentially benefit from combining Hobbies, Dislikes, and About Me into a single Textareas field (similar to what @peterfoeng mentioned). This doesn't sound consistent with ProFields, or ProcessWire for that matter. If you are setting up a forum, your best bet us to use a forum software. We use IP.Board here and really like it, but there are plenty of other great forum packages that are smaller in scope too (I've heard good things about Vanilla). Also, I wouldn't worry about having too much power when it comes to forum software. Even if your needs are only basic, having a powerful forum software doesn't necessarily make it harder to implement. It just makes it more likely that it'll do what you need it to, when you need it to. The Page fieldtype won't be part of it, as Table isn't actually using Fieldtypes. But some kind of Page reference field will likely be added to Table.1 point
-
AWStats just reads the access log from the server, so I'm not sure what your free server has or allows. You'd need access to the access log. There's no such script that can just be uploaded and tracks files downloaded. Unless you use this technique I mention with google analytics event tracking using JS. Or if you make a download file "is a page", so you can count on the template side with php. martijn was faster...1 point
-
- AWstats installed on most hosting servers is a server-side statistic "tool" for every visits and file accessed. - Google Event Tracking, make a click script that tracks events.1 point
-
Here is the same thing rewritten to be more verbose. $user = $this->user; // current user $page = $event->object; // page where editable(); function was called $user->editable_pages->has($page)) { // user's editable_pages field has $page in it // so we set the editable(); function's return value to true, // which means: "yes give them edit access" $event->return = true; } I should, but sometimes forget since I don't often use the multi-language features myself. I will update the module.1 point
-
It should be fine to put in a regular array (of non-objects), but I don't think a PageArray will work. Whatever you put in $session is best reduced to a native PHP type, so to stuff a PageArray into $session, I would typecast it to a string: $session->pageArray = (string) $pageArray; And to pull it out in the next request, pass that string to $pages->find(), which will turn it back into a PageArray: $pageArray = $pages->get("id=$session->pageArray");1 point
-
I recently had to setup front-end system to handle logins, password resets and changing passwords, so here's about how it was done. This should be functional code, but consider it pseudocode as you may need to make minor adjustments here and there. Please let me know if anything that doesn't compile and I'll correct it here. The template approach used here is the one I most often use, which is that the templates may generate output, but not echo it. Instead, they stuff any generated output into a variable ($page->body in this case). Then the main.php template is included at the end, and it handles sending the output. This 'main' template approach is preferable to separate head/foot includes when dealing with login stuff, because we can start sessions and do redirects before any output is actually sent. For a simple example of a main template, see the end of this post. 1. In Admin > Setup > Fields, create a new text field called 'tmp_pass' and add it to the 'user' template. This will enable us to keep track of a temporary, randomly generated password for the user, when they request a password reset. 2a. Create a new template file called reset-pass.php that has the following: /site/templates/reset-pass.php $showForm = true; $email = $sanitizer->email($input->post->email); if($email) { $u = $users->get("email=$email"); if($u->id) { // generate a random, temporary password $pass = ''; $chars = 'abcdefghjkmnopqrstuvwxyz23456789'; // add more as you see fit $length = mt_rand(9,12); // password between 9 and 12 characters for($n = 0; $n < $length; $n++) $pass .= $chars[mt_rand(0, strlen($chars)-1)]; $u->of(false); $u->tmp_pass = $pass; // populate a temporary pass to their profile $u->save(); $u->of(true); $message = "Your temporary password on our web site is: $pass\n"; $message .= "Please change it after you login."; mail($u->email, "Password reset", $message, "From: noreply@{$config->httpHost}"); $page->body = "<p>An email has been dispatched to you with further instructions.</p>"; $showForm = false; } else { $page->body = "<p>Sorry, account doesn't exist or doesn't have an email.</p>"; } } if($showForm) $page->body .= " <h2>Reset your password</h2> <form action='./' method='post'> <label>E-Mail <input type='email' name='email'></label> <input type='submit'> </form> "; // include the main HTML/markup template that outputs at least $page->body in an HTML document include('./main.php'); 2b. Create a page called /reset-pass/ that uses the above template. 3a. Create a login.php template. This is identical to other examples you may have seen, but with one major difference: it supports our password reset capability, where the user may login with a temporary password, when present. When successfully logging in with tmp_pass, the real password is changed to tmp_pass. Upon any successful authentication tmp_pass is cleared out for security. /site/templates/login.php if($user->isLoggedin()) $session->redirect('/profile/'); if($input->post->username && $input->post->pass) { $username = $sanitizer->username($input->post->username); $pass = $input->post->pass; $u = $users->get($username); if($u->id && $u->tmp_pass && $u->tmp_pass === $pass) { // user logging in with tmp_pass, so change it to be their real pass $u->of(false); $u->pass = $u->tmp_pass; $u->save(); $u->of(true); } $u = $session->login($username, $pass); if($u) { // user is logged in, get rid of tmp_pass $u->of(false); $u->tmp_pass = ''; $u->save(); // now redirect to the profile edit page $session->redirect('/profile/'); } } // present the login form $headline = $input->post->username ? "Login failed" : "Please login"; $page->body = " <h2>$headline</h2> <form action='./' method='post'> <p> <label>Username <input type='text' name='username'></label> <label>Password <input type='password' name='pass'></label> </p> <input type='submit'> </form> <p><a href='/reset-pass/'>Forgot your password?</a></p> "; include("./main.php"); // main markup template 3b. Create a /login/ page that uses the above template. 4a. Build a profile editing template that at least lets them change their password (but take it further if you want): /site/templates/profile.php // if user isn't logged in, then we pretend this page doesn't exist if(!$user->isLoggedin()) throw new Wire404Exception(); // check if they submitted a password change $pass = $input->post->pass; if($pass) { if(strlen($pass) < 6) { $page->body .= "<p>New password must be 6+ characters</p>"; } else if($pass !== $input->post->pass_confirm) { $page->body .= "<p>Passwords do not match</p>"; } else { $user->of(false); $user->pass = $pass; $user->save(); $user->of(true); $page->body .= "<p>Your password has been changed.</p>"; } } // display a password change form $page->body .= " <h2>Change password</h2> <form action='./' method='post'> <p> <label>New Password <input type='password' name='pass'></label><br> <label>New Password (confirm) <input type='password' name='pass_confirm'></label> </p> <input type='submit'> </form> <p><a href='/logout/'>Logout</a></p> "; include("./main.php"); 4b. Create a page called /profile/ that uses the template above. 5. Just to be complete, make a logout.php template and create a page called /logout/ that uses it. /site/templates/logout.php if($user->isLoggedin()) $session->logout(); $session->redirect('/'); 6. The above templates include main.php at the end. This should just be an HTML document that outputs your site's markup, like a separate head.inc or foot.inc would do, except that it's all in one file and called after the output is generated, and we leave the job of sending the output to main.php. An example of the simplest possible main.php would be: /site/templates/main.php <html> <head> <title><?=$page->title?></title> </head> <body> <?=$page->body?> </body> </html>1 point