Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 07/27/2014 in all areas

  1. Hi everyone, Here's a little module that allows you to force users to change their password on their first login, or at any time if you manually force it. http://modules.processwire.com/modules/password-force-change/ https://github.com/adrianbj/PasswordForceChange Key Features During install it creates a new checkbox field in the user template, "force_passwd_change". Automatic checking of this checkbox when creating a new user is determined by the "Automatic Force Change" module config setting. When a user logs in for the first time (or if you have manually checked that field for an existing user), they will be warned that they have to change their password and they'll be automatically redirected to their profile page. They must change their password to something new - they are not allowed to re-enter their existing password. Bulk "Set All Users" option to at any time, force all users (by selected roles) to change their password. Hopefully some of you will find it useful and please let me know if you have any suggested changes/enhancements. PS I used the new info.json way of defining the module details, so it requires PW 2.4.3+
    2 points
  2. Hi guys, recently, I'm reading Stephen Hay's "Responsive Design Workflow" and am fascinated by its idea of "Content reference workflows". In short: this approach does not use any software like OmniGraffle, MS Visio, etc. but plain HTML. This way the wireframes can be responsive (and be created quickly since one is at home in HTML anyway). The other thing is, that these type of wireframes are very minimalistic and, instead of a detailed graphic-design-like approach, it more or less uses two colors, borders and labels. So the danger of mistaking these wireframes as a design proposal is minimized. And since metaphors are always good I tried to tweak this philosophy with a well known instrument of the "analogue" world: blueprints. This way, at least thats the intention, it becomes even more clear for the customer that this is an abstraction. If you communicate it right, for example with a explainatory popup/modal, no customer ever should misunderstand it and ask: "What? My website is meant to be blue?" Find some screenshots below and a demo of what I'm aiming for here: http://demo.marcus-herrmann.com/blueprint-wireframes/ Before I confront any more customers of mine with this approach I would be very thankfully to hear any feedback on this from fellow developers. What is your (or your employer's) approach on this? Are there any obvious quirks with this one? As usual, you can find the code on GitHub: https://github.com/marcus-herrmann/blueprint-wireframes Have a nice weekend! Marcus
    2 points
  3. Sorry for double posting again. But I set up a small site with better explanation and documentation of this approach: http://blueprint-wireframes.com/
    2 points
  4. You can detect whether the current page was loaded from ajax by checking the value of $config->ajax from your template file: <?php if($config->ajax) { // page was requested from ajax } Following that, you will likely want to render the page differently to accommodate whatever you are doing from the javascript side. For instance, you might want do one of these: 1. Deliver alternate or reduced markup when loaded from ajax 2. Deliver a JSON or XML string for parsing from javascript Below are examples of each of these scenarios. 1. Deliver alternate or reduced markup when loaded from ajax You might find checking for ajax helpful when you want portions of pages to load in your site without re-rendering the entire page for each request. As a simple example, we'll use the default ProcessWire site and make it repopulate it's #bodycopy area when you click a page in the top navigation. (To use this example, you'll need the default ProcessWire site templates, though you can easily adapt the example to another situation.) To accomplish this, we'll update our main page template to only include the header and footer markup if the page is NOT being loaded from ajax: /site/templates/page.php <?php if(!$config->ajax) include("./head.inc"); echo $page->body; if(!$config->ajax) include("./foot.inc"); Next we'll update the top navigation to do ajax loads of the pages when the client has javascript (and leave as-is when they don't). Paste this javascript snippet before the closing </head> tag in the header markup file: /site/templates/head.inc: <script type="text/javascript"> $(document).ready(function() { $("#topnav a").click(function() { $("#topnav a.on").removeClass('on'); // unhighlight selected nav item... $(this).addClass('on'); // ...and highlight new nav item $("#bodycopy").html("<p>Loading...</p>"); $.get($(this).attr('href'), function(data) { $("#bodycopy").html(data); }); return false; }); }); </script> Now when you click on any page in the top navigation, it pops into the bodycopy area without a page load visible from your browser. And all pages remain accessible from their URL as well. Note that this is just a test scenario, and I probably wouldn't use this approach for the entire bodycopy area on a production site (it would make bookmarking difficult). But this approach can be very useful in the right places. 2. Deliver a JSON or XML string for parsing from javascript Lets say that you want pages in your site to return a JSON string with the page's id, title, and number of children when it is requested from ajax. When not requested from ajax, they will return their content as normal. To handle the ajax requests, you'd want to add something like this at the top of your template file before any other output. <?php if($config->ajax) { // this is an ajax request, return basic page information in a JSON string $json = array( 'id' => $page->id, 'title' => $page->title, 'numChildren' => $page->numChildren ); echo json_encode($json); return; } // not ajax, continue with regular page output And here is some markup and inline javascript you might use to test the ajax call on some other page (or the same one if you prefer). You would paste this snippet right in your site's markup where you want that info to appear. <ul id='info'></ul> <script type='text/javascript'> var url = '/'; // this is homepage, so replace '/' with page URL you want to load JSON from $(document).ready(function() { $.getJSON(url, function(data) { $.each(data, function(key, value) { $("#info").append("<li>" + key + ": " + value + "</li>"); }); }); }); </script> The above snippet would output something like this: • id: 1 • title: Home • numChildren: 5 To take this example further, you could build an ajax-driven sitemap or any number of web services. Conclusion Hope this helps you to see how simple it is to use ProcessWire to deliver output for ajax. These are just contrived examples, but hopefully examples that might lead to more ideas. In addition, much of what you see in these examples is also applicable to building web services in ProcessWire.
    1 point
  5. FieldtypeSelectFile & InputfieldSelectFile Inputfield Select File is an Inputfield & Fieldtype to select a single file or folder and stores the name and / or use the selected file as page template. The last option enables the editor to use multiple views for a page, depending on the selected template. Settings The folder containing the files and/or folders.A relative path relative to the /site/templates/ folder. Hide file extensions Hide files Hide folders Natural Sort (Select options)Sort files and folders in natural ordering (PHP >= 5.4.0) Change Page Template Just before the Page::loaded event the selected file is set as template file for the page. This setting can only be applied once per a page and folders are exluded from the select inputfield. Note that a page with no associated template file will render with the selected file. When to use ? Let editors select a file and base your own logic upon this. With the change page template setting you're able to use the selected file as template file. This could reduce the amount of normal templates needed and let editors choose how the page get rendered. There are plenty of use cases for this Inputfield. In the examples I call the field selected_file. // let the editor choose a CSS file $config->styles->append($config->urls->templates . "styles/" . $page->selected_file); /** * advanced usage example * * You need multiple ways to render your markup. Let the site editor choose which * file the page need to render. * */ $tpl = new TemplateFile($config->paths->templates . "includes/" . $page->selected_file); $tpl->set('current', $page); $markup = $tpl->render(); (It could be a real good companion with InputfieldSelector) Download at GitHub Modules directory
    1 point
  6. Template Cache and $page->render($options) If you ever use the $page->render() to render out partials (of another page using its template file) and use template cache for the pages you're going to render and the page where you render it, it will create a cachefile. So if you go to that previously rendered and cached page, it will render that partial. If the page is accessed before a cache is created, it will cache this one and render that in as the partial, so kinda turned around. Funny effect. And many mmms and oaaahhhs To get a better understanding what's happening read on. Simple example code from a list page to render partials of articles (likely) // from the list pages template $markup = ''; foreach($products as $key => $child) { $markup .= "<dl>"; $markup .= $child->render(array('isOverview' => true, 'class' => $class)); $markup .= "</dl>"; } echo $markup; And in the template of the article // in article template file if(isset($options['isOverview']) && $options['isOverview'] == true) { // render small partial $class = $options['class']; $markup = "<dd class='$class'> <h4>$page->title</h4> <p>$page->summary</p> <a href='$page->url'>details</a> </dd>"; } else { // render complete article $markup = "<div class='product-details'> <h1>$page->title</h1> $page->body </div>"; } // output echo $markup; So now the render call $markup .= $child->render( array('isOverview' => true, 'class' => $class) ); in the list template will cache the page it renders (the small view of it). Thus if you access the page directly it will serve the cached small view of it. Ups. Solutions This is without specifying a different template file in the first argument in the render(). The effect doesn't happen when you, let's say create a new template file (ie article-small.php) and use that to render the page. Since this new template file is not connected to the template in PW it also has no cache for that render. To show what I mean is the following with the first argument the file you want the view to render. $markup .= $child->render("product-small.php", array("isOverview" => true, "class" => $class)); Still following me? Ok there's also another method to not allow a cache file to be created. There's a default options set in the render() in PW. Bingo! allowCache is what we can also use. $markup .= $child->render("product-small.php", array( "allowCache" => false, "isOverview" => true, "class" => $class )); And everything's back to normal. Just wanted to write down a little thing, as I stumbled over this recently, to scatter some keywords about this here . I think this isn't really documented somewhere but I thought it was maybe mentioned by Ryan in a thread about when he added this feature: http://processwire.com/talk/topic/3145-multiple-views-for-templates/page-2?hl=%2Brender+%2Bcaller#entry32876. Edit: Zaaakkkk and it's in Google 9 minutes !
    1 point
  7. Today I've created a really simple little module that is configurable and attaches to hooks. So it has more or less everything of a real world module in it. I thought processwire beginners would be interested in reading how to create such a module so I added some comments to the source code in a way the module should explain itself... Here it is: /** * BackgroundChanger module for demonstration purposes * * Demonstrates the Module interface and how to add hooks in a more real world manner... * * ProcessWire 2.x * Copyright (C) 2014 by Domenic Helfenstein * */ class BackgroundChanger extends WireData implements Module, ConfigurableModule { public static function getModuleInfo() { return array( /* * the __("text") methods are used for multilanguage support * see: https://processwire.com/api/multi-language-support/code-i18n/ */ 'title' => __('BackgroundChanger'), 'summary' => __('This is a simple real world module that can change the background color.'), 'version' => 105, /* * autoload must be true if the module depends on hooks * see: http://wiki.processwire.com/index.php/Module_Creation#Details_of_what_the_.22autoload.22_property_means */ 'autoload' => true, /* * it is wise to run modules in singular mode when using hooks * see: http://wiki.processwire.com/index.php/Module_Creation#Details_of_what_the_.22singular.22_property_means */ 'singular' => true, ); } public function __construct() { //set default values $this->backgroundColor = 'yellow'; /* * !!! the value in the db will be automatically injected into this var * because it is named equal to the value of $field->name in * getModuleConfigInputfields !!! */ } public function init() { // add a hook after each page is rendered and modify the output $this->addHookAfter('Page::render', $this, 'changeBackground'); } public function changeBackground($event) { $page = $event->object; //do only modify non-admin pages if($page->template == 'admin') return; $extension = <<< _OUT <style> body {background-color:{$this->backgroundColor};} </style> _OUT; $event->return = str_replace("</head>", $extension."</head>", $event->return); } public static function getModuleConfigInputfields(array $data) { //create a fieldset $inputfields = new InputfieldWrapper(); //create field for background color $field = wire('modules')->get('InputfieldText'); $field->name = 'backgroundColor'; $field->label = __("Enter the hex-code or name of the desired background color. (visit colorpicker.com)"); //if there is already a value stored, set this value to the field if(isset($data['backgroundColor'])) $field->value = $data['backgroundColor']; //add the field to the fieldset $inputfields->add($field); //return the fieldset to display return $inputfields; } } I hope this helps others creating their own modules! BackgroundChanger.module
    1 point
  8. Hi Matthew - thanks - i do take your opinion very seriously and have followed your thread about the outage(s). So right now i'm on Servint, and the site seems to be running well; haven't had any major issues yet, and the support has been responsive. This is my first time ever using anything other than reseller shared hosting, and the performance of the server has been very good, and the scripts i need to run on there have been really running well... As it was quite a bit of work to migrate the client's cpanel account over to Servint from the previous shared host, i have my fingers crossed that I won't need to move again.. but I will post back here some further updates and ratings for this server, specifically the performance and uptime. This one is in the DC datacenter.
    1 point
  9. Btw, if you are on WHM/cPanel, moving accounts (to another WHM/cPanel) setup is really easy. Pretty much a 1-click process. So if whatever change you make involves moving to a server where they can't migrate it for you, just use the migration tool built into WHM which has worked great in my experience. I used to host some clients on my own VPS and when they grew and moved to their own dedicated server, this migration tool made life easy.
    1 point
  10. Thanks Pete for posting back on this. I removed 777 and re-edited point 10 in the list.
    1 point
  11. Another bug fix and enhancement just committed. There is now a batch "Set All Users" option which allows you to easily force existing users to change their password. Selection of users is possible via roles so you can limit the enforcement to just specific roles, or all if needed. If you mess up, there is also a simple way to clear the requirement for everyone as well. This addition was in response to teppo's comment in his ProcessWire Weekly post: "easily forcing periodic password changes for users" - now it really is easy to force periodic changes, so thanks for the suggestion The bug fix is for PW sites installed in a subdirectory - thanks also to teppo for reporting this.
    1 point
  12. What about this: $np = $pages->clone($page); $np->of(false); $np->title = 'New Page'; $np->name = 'newpage'; $np->save();
    1 point
  13. My second website launched with Processwire ( Haven't posted the first one because we're planning to launch the multi language version soon ) This one is german as well, but as there is no planned english version I'm posting it anyways. It's a pretty simple page except the time tables. My head went crazy a couple of time, because I'm in my early PHP stages ^^ Actually it's a relaunch of a Joomla page which was from 1960 or something They created the time tables with a wysiwyg desktop editor and uploaded them separately My personal goal was to simplify this process so I decided to customize FieldtypeEvents module to have easy creation of course schedules and nice automation of the browser and pdf output. PDF creation is already described here How To Create Pdfs With Pw And Mpdf Now they only need their PW type in some course facts hit save and good to go hehe Uhm, my head is still working on the other website, so I stop writing now. Questions, feedback, bugs and anything else are appreciated Oh, the link^^ here you go www.Yoga-Lounge-Berlin.de Update: Got a screenshot from the one. As you can see, we only made some little color adjustments. Update 2: the search engine works like I described here https://processwire.com/talk/topic/6016-capture-user-search-queries/?p=63882 So it spits out results for yoga and joga.
    1 point
  14. CHMOD 777 (on shared hosting at least) could be very bad pwired. If the server is configured badly, like a lot of cheap ones out there probably are, 777 gives everyone on the server the ability to affect your files. There are plenty of posts about this on the internet if you do a quick search - here's one: http://stackoverflow.com/questions/11271596/how-will-a-server-become-vulnerable-with-chmod-777 If you're not on shared hosting then you're safer, but 777 is about the most open permission you can apply to a file or folder. You would need to read up on CHMOD really (I think I need to as well as it's been a while) as what permission you can realistically tighten it up to depends on how PHP is installed (mod_php etc) and I honestly don't know enough about the subject. Your recommendation of 777 just rang alarm bells with me because that's basically "anyone can read, write or execute this file" whereas something like 755 means "owner" can read, write and execute, but "group" and "others" (others being everyone else I believe) can only read and execute the file. Other folks here might be able to tell us if it's even an issue nowadays, but I just remember a lot of scripts a few years back that told you to set certain permissions on certain folders.
    1 point
  15. I have to show another ProcessWire while about 10 000 guest are entering the festival area. We've made this site exactly 125 days ago and while it's not our best page, it has some kind of interesting background story. URL: http://www.openbeatz.de/ This is a website for a german two-day electro festival. Some better-known DJs will be playing there and thousands of guest are expected (They hope to sell the ticket no 10000 this evening). The website features basic information pages, a DJ voting contest with FB integration and a overview of all ticket stores. It's build with ProcessWire 2.4 using FormBuilder and the AIOM module. How we got started Our existing client asked for a "small countdown page". They bought the "rights" of the festival and needed something quick to start the promotion. The problem? We didn't even had access to the domain but they printed the first batch of ads and flyers with the URL on it. The first mail came on Wednesday and the site should go online on friday. Don't we all love those kind of challenges... As expected, the site requirements started to grow. We didn't had time for proper project management or any kind of planing. The whole site was build quick and dirty in under a week. We hired another coder to help us. The site is far from perfect, we know. It's hard to get the best results without proper communication and the lack of time. Anyway, the site was online and features were added quickly. The festival last year had about 2000 attendees. We saw the line up after we build the site and that was the point we realized, that our client had something bigger in mind... The Domain The domain was already printed on thousands of flyers when we first heard of the project. At that time, the old agency deleted the domains without a notice to us. We could get the open-beatz.de one but a domain shark got the name without the - . This stuff can get really expensive so we had to negotiate withe the new, unwanted domain holder. After some mails we got down from 5000€ to a smaller three-digit price. Lesson learned (and paid). The DJ Voting DJs could apply with a sample soundcloud set. The DJ with the most Votes (in form of FB likes) will play at the festival. The whole contest was embedded within a facebook application tab. The page had 406 DJs listed with a sum of around 11k likes. A DJ was represented with a PW pages were we counted the likes on that URI using the FB API. The contest is now hidden but you can see an example page here: www.openbeatz.de/dj-contest/wildchild/ The TV ad and numbers You open Facebook and then you see the status "OpenBeatz TV ad in 5 minutes on RTL". Great, why did nobody tell us? The site was featured in multiple ads on the german RTL and RTL2 (larger) tv stations with the URL at the end. There were even ads at prime times like 19:00 and 20:00. Traffic peaked between 2000-4000 additional unique visitors after each clip. ProcessWire took it like a champ even without ProCache. For the stat nerds: 72% of those visitors in the time after the TV ads were on mobile. In total we had an average of 1700 unique visitors every day with a peak of 11k visitors. The site was also shared on the artists facebook pages which brought another 1000 visitors within a 30 minute time frame. What did we learn? Plan ahead and communication. Make double tripple sure that your client tells you all the details and the size of the project. We started to small. If there is no time don't rush. If I could travel back in time, I would just delay that stupid countdown page for a week and plan a better version of the PW site. Planning for the next OpenBeatz festival website will start in two weeks. Next time we will be prepared and launch a better site with lots of useful and cool features. Again, using ProcessWire Ideas are welcome. One more thing: The whole site isn't a site on its own. It's just part of the Rocking High website using the Multisite module. But I thought a new thread in the showroom was appropriate. Have a nice week end!
    1 point
  16. Agreed - that occurred to me yesterday too. Thank you both for the feedback - changes have been committed to Github and the module has been submitted to the modules directory.
    1 point
  17. You can pass variable via render like: echo $pages->get($child->id)->render(array('mobile' => $mobile)); and then in the template use $options['mobile'] to get the value.
    1 point
  18. @Marty: I do this by using a module. It's a copy from somas PageListShowPageId. the PHP code is public function init() { $this->addHookAfter('ProcessPageListRender::getPageLabel', $this, 'addPageArchivnummerLabel'); } public function addPageArchivnummerLabel($event) { $page = $event->arguments('page'); if('album'==$page->template) { //$event->return = str_pad(count($page->images), 3, '0', STR_PAD_LEFT) . " " . $event->return; $event->return = $event->return . ' <span class="jhpPageListArchivnummer">' . $page->archivnummer . '</span> ' . ' <span class="jhpPageListImageCount">' . count($page->images) . '</span>'; } } and the CSS is .content .PageListItem > a span + span.jhpPageListImageCount:before { content: 'count: ' !important; } .content .PageListItem > a span + span.jhpPageListArchivnummer:before { content: '' !important; } .content .PageListItem > a span + span.jhpPageListImageCount, .content .PageListItem > a span + span.jhpPageListArchivnummer { font-size:0.9em; background-color:#EEE; color: #777; padding: 2px 5px 1px 5px; border: medium none !important; border-radius: 3px 3px 3px 3px; }
    1 point
  19. After Ryan's latest incarnation of Blog Profile I wanted to see if I could learn something from there to my own workflow. It turned out very nicely and this seems like a perfect template approach for me. Wanted to share it with you guys. Folder structure under templates folder: templates/markup/ templates/markup/helpers/ templates/markup/layouts/ templates/scripts/ templates/styles/ And it all begins from here: templates/markup/index.php -this is the "complete" html file, it has doctype, head and starting and ending body. There is very little "logic" here, it's more like a container. There is one very important code snippet there though: <?php if ($page->layout) { include("./markup/layouts/{$page->layout}.php"); } else { include("./markup/layouts/default.php"); } ?> Code above goes between header and footer of your site, that will be the main content. I call it layout, but the better name would be "content layout" or "inner layout" or something like that. Then the templates/markup/layouts/ folder will keep at least default.php file, but probably few others, like "threeColumns.php", "frontpage.php", "gallery.php" etc.. you got the idea. Each of the actual pw template files are then purely "controllers" - no actual markup generated there. All markup are done in files inside templates/markup/ folder and it's subfolders. This is how template file templates/home.php on one site I am building right now looks like: <?php // Carousel items $t = new TemplateFile(wire('config')->paths->templates . 'markup/helpers/carousel.php'); $t->set('carouselPages', $page->carousel); $page->masthead = $t->render(); // Tour themes $t = new TemplateFile(wire('config')->paths->templates . 'markup/helpers/items.php'); $t->set('title', "Get inspired from our <strong>tour themes</strong>"); $t->set('items', $page->featured_themes); $t->set('description', $page->themes_description); $t->set('url', $config->urls->root . "themes/"); $t->set('linkTitle', "All themes"); $page->main .= $t->render(); // National parks $t = new TemplateFile(wire('config')->paths->templates . 'markup/helpers/items.php'); $t->set('title', "Seven beautiful <strong>national parks</strong>"); $t->set('items', $page->featured_parks); $t->set('description', $page->parks_description); $t->set('url', $config->urls->root . "national-parks/"); $t->set('linkTitle', "All national parks"); $page->main .= $t->render(); $page->layout = "frontpage"; include("./markup/index.php"); This uses few "helper" markup files from templates/markup/helpers/ folder (namely carousel.php and items.php). Here is the carousel.php for your reference: <?php /* Generates the markup for the frontpage carousel */ if (count($carouselPages) < 1) return; $styles = ''; echo "<div id='carousel'><ul class='rslides'>"; foreach($carouselPages as $key => $p) { echo "<li class='c-item c-item-$key'>"; echo "<img src='".$p->image->getThumb('carousel') ."' alt='' />"; echo "<p>$p->summary</p>"; echo "<a class='button' href='{$p->link->url}'>$p->headline</a>"; echo "</li>"; } echo "</ul></div>"; Then populates the $page->masthead and $page->main properties and then set's the inner layout to "frontpage". That templates/markup/layouts/frontpage.php file is very simple on this site, but could be much more complicated if needed: <div id="masthead"> <?= $page->masthead; ?> </div> <div id="main" class="wrap"> <?= $page->main; ?> </div> Frontpage is rather unique and I could have done all the markup on the frontpage.php file also. But I do want to re-use those "carousel" and "items" components on other places as well. But if I do have totally unique stuff, where I do want to get "quick and dirty" this approach allows it. Then my template file would be something like this: $page->layout = "campaign2012"; include("./markup/index.php"); And then all the markup would be in that templates/markup/layouts/campaign2012.php Blog profile really gave me a good ideas (cleaner folder structure etc) and using TemplateFile class adds nice possibilities. This is of course just a one way to manage your templates, but hopefully someone of you finds this helpful when thinking about how you like to structure this stuff. PS: If you are just getting started with PW, then I recommend using the head and foot includes method from demo install. There is nothing wrong with that method and only more complicated sites starts to benefit from these methods introduces in this topic.
    1 point
×
×
  • Create New...