Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 05/28/2016 in all areas

  1. Tutorial now available on Tuts+ here: http://webdesign.tutsplus.com/tutorials/how-to-create-an-ajax-driven-theme-for-processwire--cms-26579
    5 points
  2. This week our focus was on the server side of things rather than on the code side. Sometimes you've got to open the hood and change the oil in order to keep things running smoothly. But rather than just changing the oil, we opted to replace the entire car, moving from our compact family sedan to a turbocharged supercar, so to speak. Basically, we've had some major server upgrades this week! This post covers them in detail: https://processwire.com/blog/posts/web-hosting-changes-and-server-upgrades/
    3 points
  3. @bernhard: exactly the question I've been meaning to ask too! Syncing a site to another location periodically and preparing a failover mechanism for static data is one thing, but I'm also curious about how data gets merged back and forth in a situation like this
    3 points
  4. Hi, I think you might want to combine it with: $config->httpHost
    3 points
  5. For the most part I agree: classes don't have actual semantic meaning, so technically speaking they're fine, and I believe we're pretty much on the same page regarding pseudo elements too. It's just that I've recently started to emphasise pseudo-elements over classes whenever it makes sense. There are many cases where it doesn't make sense, but for something as simple as alternating background colors for predefined elements it fits the bill perfectly. I've also grown tired of trying to guess which classes I should add to my markup in order to make it easy enough to style, and I strongly dislike having to change any aspect of the markup (including generated classes) if I later on decide that I need to do something purely style-related – such as make odd items have a different background color. Pseudo elements are awesome for separation of concerns, and they can reduce the clutter quite a bit. While classes rarely add a considerable amount of extra weight to the document, unless we're talking about a serious case of classitis combined with extremely large scale use, that's another (however minor) argument against them: why add something that isn't required in the first place
    2 points
  6. Very interesting post! I really enjoyed reading about the backup an restore solution, very educational. Everything truly feels blazing fast now! Thanks for the amazing work Jan and Ryan!
    2 points
  7. I've personally never been a fan of VPS hosting outside of AWS or Google. That said, I've moving an ocean of servers and sites into AWS including running on Bitnami. Most of the bitnami AMIs are free to use on AWS so all you do is pay for use of the instance and attached storage so you can make it as big or small (even free) as you want. I've personally found the setup of Bitnami instances confusing and prefer to do this myself but I also work in this space so I'm not exactly an average user.
    2 points
  8. Been getting questions on how to build complex/custom menus. Even with the ability to pass it custom options, some menus are a bit more complex than what Menu Builder offers out of the box. My answer to such questions has, to date, been get the JSON and use that to build your menu. Not very easy for some....but no more...thanks to @Beluga, @Peter and @Webrocker + others for the inspiration/challenges. I've now added a method in MarkupMenuBuilder to make building custom complex menus a breeze. Don't get me wrong, you still have to know your foreach loops or even better grab one of the many recursive list/menu functions in the forums (or StackOverflow) and adapt it to your needs. Don't worry though, below, I provide a couple of complete code examples using recursive functions. For a 2-level deep menu, even a nested foreach would do. Going forward, this new method is what I recommend for building complex menus if using Menu Builder. The new method is called getMenuItems($menu, $type = 2, $options = null) takes 3 arguments. Before I show you the cool things you can do with this method, let's get familiar with the arguments. $menu: This is identical to the first argument in MarkupMenuBuilder's method render(): Use this argument to tell getMenuItems() the menu whose items you want returned. The argument takes a Page, id, title, name or array of menu items $type: Whether to return a normal array or a Menu object (WireArray) of menu items $options: Similar to render() method options but please note that only 3 options (from the list of those applicable to render()) apply to getMenuItems(). These are default_title, default_class and current_class_level. default_class is applied to the item's property $m['ccss_itemclass']. Probably not many know that MarkupMenuBuilder ships with a tiny but useful internal class called Menu. MenuBuilder uses it internally to build Menu objects that are finally used to build menus. Menu objects are WireArrays. If $type == 2, this is what is returned. Array vs WireArray So, which type of output should you return using getMenuItems()? Well, it depends on your needs. Personally, I'd go for the Menu object. Here's why: Although you can still easily build menus by using getMenuItems() to return a normal PHP Array, it's not nearly as powerful as returning and using a WireArray Menu object instead. Whichever type of items you return using getMenuItems(), it means you can manipulate or apply logic before or within a recursive function (or foreach loop) to each of your menu items. For instance, show some parts of the menu only to users who are logged in, or get extra details from a field of the page represented by the menu item, add images to your menu items, etc. Grabbing the Menu object means you can easily add some runtime properties to each Menu object (i.e. each menu item). If you went with a normal array, of course, you can also manipulate it, but not as easily as working with an object. A Menu object also means you have access to the powerful WireArray methods (don't touch sort though!). For instance, $menuItems->find("parentID=$m->id"). With a Menu object, you also get to avoid annoying isset(var) that come with arrays . Here are the properties that come with each Menu object. Use these to control your logic and output menu items values. In that block of code, to the left are the indices you'd get with a normal array. The values (to the right) are the Menu object properties. Below are examples of building the W3Bits 'CSS-only responsive multi-level menu' as illustrated in the tutorial by @Beluga. We use 3 different recursive functions to build the menu using items returned by getMenuItems(). I will eventually expound on and add the examples to my Menu Builder site. Meanwhile, here's a (very colourful) demo. Examples @note: The CSS is the one by @Beluga in the tutorial linked to above. @note: Clearer examples can be found in these gists. First, we grab menu items and feed those to our recursive functions. $mb = $modules->get('MarkupMenuBuilder');// get Menu Builder // get menu raw menu items. $menu can be a Page, an ID, a name, a title or an array #$menu = $pages->get(1299);// pass a Page #$menu = 1299;// pass an ID #$menu = 'main';// pass a name $jsonStr = $pages->get(1299)->menu_items; $arrayFromJSON = json_decode($jsonStr, true); #$menu = $arrayFromJSON;// pass an array $menu = 'Main';// pass a title /** grab menu items as WireArray with Menu objects **/ // for examples 1a, 2 and 3 $menuItems = $mb->getMenuItems($menu, 2, $options);// called with options and 2nd argument = 2 {return Menu (WireArray object)} #$menuItems = $mb->getMenuItems($menu);// called without options; 2nd argument defaults to 2 /** grab menu items as Normal Array with Menu items **/ // only for example 1b below menuItems2 = $mb->getMenuItems($menu, 1);// called without options; 2nd argument is 1 so return array Example 1a: Using some recursive function and a Menu object /** * Builds a nested list (menu items) of a single menu. * * A recursive function to display nested list of menu items. * * @access private * @param Int $parent ID of menu item. * @param Array $menu Object of menu items to display. * @param Int $first Helper variable to designate first menu item. * @return string $out. * */ function buildMenuFromObject($parent = 0, $menu, $first = 0) { $out = ''; $has_child = false; foreach ($menu as $m) { $newtab = $m->newtab ? " target='_blank'" : ''; // if this menu item is a parent; create the sub-items/child-menu-items if ($m->parentID == $parent) {// if this menu item is a parent; create the inner-items/child-menu-items // if this is the first child if ($has_child === false) { $has_child = true;// This is a parent if ($first == 0){ $out .= "<ul class='main-menu cf'>\n"; $first = 1; } else $out .= "\n<ul class='sub-menu'>\n"; } $class = $m->isCurrent ? ' class="current"' : ''; // a menu item $out .= '<li' . $class . '><a href="' . $m->url . '"' . $newtab . '>' . $m->title; // if menu item has children if ($m->isParent) { $out .= '<span class="drop-icon">▼</span>' . '<label title="Toggle Drop-down" class="drop-icon" for="' . wire('sanitizer')->pageName($m->title) . '" onclick>▼</label>' . '</a>' . '<input type="checkbox" id="' . wire('sanitizer')->pageName($m->title) . '">'; } else $out .= '</a>'; // call function again to generate nested list for sub-menu items belonging to this menu item. $out .= buildMenuFromObject($m->id, $menu, $first); $out .= "</li>\n"; }// end if parent }// end foreach if ($has_child === true) $out .= "</ul>\n"; return $out; } Example 1b: Using some recursive function and a Menu array /** * Builds a nested list (menu items) of a single menu from an Array of menu items. * * A recursive function to display nested list of menu items. * * @access private * @param Int $parent ID of menu item. * @param Array $menu Array of menu items to display. * @param Int $first Helper variable to designate first menu item. * @return string $out. * */ function buildMenuFromArray($parent = 0, $menu, $first = 0) { $out = ''; $has_child = false; foreach ($menu as $id => $m) { $parentID = isset($m['parent_id']) ? $m['parent_id'] : 0; $newtab = isset($m['newtab']) && $m['newtab'] ? " target='_blank'" : ''; // if this menu item is a parent; create the sub-items/child-menu-items if ($parentID == $parent) {// if this menu item is a parent; create the inner-items/child-menu-items // if this is the first child if ($has_child === false) { $has_child = true;// This is a parent if ($first == 0){ $out .= "<ul class='main-menu cf'>\n"; $first = 1; } else $out .= "\n<ul class='sub-menu'>\n"; } $class = isset($m['is_current']) && $m['is_current'] ? ' class="current"' : ''; // a menu item $out .= '<li' . $class . '><a href="' . $m['url'] . '"' . $newtab . '>' . $m['title']; // if menu item has children if (isset($m['is_parent']) && $m['is_parent']) { $out .= '<span class="drop-icon">▼</span>' . '<label title="Toggle Drop-down" class="drop-icon" for="' . wire('sanitizer')->pageName($m['title']) . '" onclick>▼</label>' . '</a>' . '<input type="checkbox" id="' . wire('sanitizer')->pageName($m['title']) . '">'; } else $out .= '</a>'; // call function again to generate nested list for sub-menu items belonging to this menu item. $out .= buildMenuFromArray($id, $menu, $first); $out .= "</li>\n"; }// end if parent }// end foreach if ($has_child === true) $out .= "</ul>\n"; return $out; } For example 1a and 1b we call the respective functions to output the menu <div id="content"> <nav id="mainMenu"> <label for='tm' id='toggle-menu' onclick>Navigation <span class='drop-icon'>▼</span></label> <input id='tm' type='checkbox'> <?php // build menu from Menu object (example 1a) echo buildMenuFromObject(0, $menuItems); // OR build menu from array (example 1b) #echo buildMenuFromArray(0, $menuItems2); ?> </nav> </div> Example 2: Using a modified version of @mindplay.dk's recursive function /** * Recursively traverse and visit every child item in an array|object of Menu items. * * @param Menu item parent ID $parent to start traversal from. * @param callable $enter function to call upon visiting a child menu item. * @param callable|null $exit function to call after visiting a child menu item (and all of its children). * @param Menu Object|Array $menuItems to traverse. * * @see Modified From mindplay.dk https://processwire.com/talk/topic/110-recursive-navigation/#entry28241 */ function visit($parent, $enter, $exit=null, $menuItems) { foreach ($menuItems as $m) { if ($m->parentID == $parent) { call_user_func($enter, $m); if ($m->isParent) visit($m->id, $enter, $exit, $menuItems); if ($exit) call_user_func($exit, $m); } } } For example 2, we call the function (@note: a bit different from example 1 and 3) this way to output the menu <div id="content"> <nav id="mainMenu"> <label for='tm' id='toggle-menu' onclick>Navigation <span class='drop-icon'>▼</span></label> <input id='tm' type='checkbox'> <?php echo "<ul class='main-menu cf'>"; visit( 0// start from the top items , // function $enter: <li> for a single menu item function($menuItem) { echo '<li><a href="' . $menuItem->url . '">' . $menuItem->title; if ($menuItem->isParent) { echo '<span class="drop-icon">▼</span>' . #'<label title="Toggle Drop-down" class="drop-icon" for="' . wire('sanitizer')->pageName($menuItem->title) . '" onclick>▼</label>' . '<label title="Toggle Drop-down" class="drop-icon" for="sm' . $menuItem->id . '" onclick>▼</label>' . '</a>' . #'<input type="checkbox" id="' . wire('sanitizer')->pageName($menuItem->title) . '"><ul class="sub-menu">' . '<input type="checkbox" id="sm' . $menuItem->id . '"><ul class="sub-menu">'; } else echo '</a>'; }// end function 1 ($enter) , #function $exit: close menu item <li> and sub-menu <ul> tags function($menuItem) { if ($menuItem->isParent) echo '</ul>'; echo '</li>'; }, $menuItems// the menu items (Menu objects in this example) ); ?> </nav> </div> Example 3: Using a modified version of @slkwrm's recursive function /** * Recursively traverse and visit every child item in an array|object of Menu items. * * @param Menu Object|Array $menuItems to traverse. * @param Int $parent ID to start traversal from. * @param Int $depth Depth of sub-menus. * @param Int $first Helper variable to designate first menu item. * @see Modified From @slkwrm * @return string $out. */ function treeMenu($menuItems, $parent, $depth = 1, $first = 0) { $depth -= 1; if ($first == 0){ $out = "\n<ul class='main-menu cf'>"; $first = 1; } else $out = "\n<ul class='sub-menu'>"; foreach($menuItems as $m) { if ($m->parentID == $parent) { $sub = ''; $out .= "\n\t<li>\n\t\t<a href='" . $m->url . "'>" . $m->title; if($m->isParent && $depth > 0 ) { $sub = str_replace("\n", "\n\t\t", treeMenu($menuItems, $m->id, $depth, $first)); $out .= '<span class="drop-icon">▼</span>' . '<label title="Toggle Drop-down" class="drop-icon" for="sm' . $m->id . '" onclick>▼</label>' . '</a>' . '<input type="checkbox" id="sm' . $m->id . '">' . $sub . "\n\t"; } else $out .= "</a>\n\t"; $out .="\n\t</li>"; } }// end foreach $out .= "\n</ul>"; return $out; } For example 3, we call the function to output the menu <div id="content"> <nav id="mainMenu"> <label for='tm' id='toggle-menu' onclick>Navigation <span class='drop-icon'>▼</span></label> <input id='tm' type='checkbox'> <?php //parameters: menuItems, menu item parent ID, depth, first (helper variable) echo treeMenu($menuItems, 0, 4); ?> </nav> </div>
    2 points
  9. I guess this puts processwire hosting on the same level as processwire
    1 point
  10. viewable() is called as part of fieldViewable() and that one is called at least for each FieldsetTabOpen. They'll just get more and more
    1 point
  11. thank you robin, yes, they do have a template file, because its the same template i use on lots of other pages that have to be viewable on frontend. i fixed it quickly by putting this in my _main.php file: <?php if($page->closest('/tools')->id) throw new Wire404Exception(); pw is so awesome but i would prefer to understand whats going on and why viewable is called for every tab in the page editor ps: 700 posts... i'm getting old
    1 point
  12. Thank you for the insight and thank you for your work (both ryan and jan). Also a noticable boost here in austria the automatic failover is very interesting, though i'm curious what you do, when people post eg forum posts on the failover system while you are doing upgrades on the master system. or are you synching changes back somehow or are you just talking about file changes and synch back the whole database?
    1 point
  13. v007 is up, with a Reno tweak that removes perhaps the biggest frustration the sidebar causes - the inability to single-click on the header links to navigate. The module is featured in PW Weekly Nr 107, thanks! So true, there's a lot of things awaiting to be fixed
    1 point
  14. this is not possible with no existing system on the web..... Actually I believe @JRW-910 was referring to the users not having to know any coding. Please correct me if I'm wrong, though In addition to what @mr-fan said above, I'd suggest taking a closer look at the devns branch of ProcessWire. This is the future 3.0 version, still in development, and among other features it includes a kind of a front-end editing support. Perhaps not exactly what you were looking for, but this could come in handy anyway. Other than that, Fredi provides front-end editing support right out of the box, and you can always embed admin views into the front-end by applying "&modal=1" to the URL of the edit view. This is all good to know in case you don't actually require a fully customised front-end editing experience, but would rather use the one ProcessWire provides out of the box. If it is a fully customised front-end editing feature you're looking for, that's relatively easy to achieve via the API. ProcessWire is awesome for this kind of stuff, but again: unless you really need a fully custom solution, I would suggest looking into the existing solutions first. For an example the FrontendUser module mentioned above is definitely a viable solution for the user registration part For managing permissions ProcessWire makes use of a simple role-based approach, but if you need something more specific, here are a couple of alternatives: Dynamic Roles provides a very flexible method of defining new "dynamic roles" in addition to the real ones based on various factors. There's very little in terms of permissions you can't achieve with this module. User Groups allows you to define page-specific or branch-specific permissions, and adds the new concept of "user groups" for grouping users together, regardless of roles they might have. Page Edit Per User does what the name says: assign edit access to individual users on a per-page basis. This module is a bit older already, so not entirely sure how it works with the latest versions of ProcessWire, but it's also a relatively simple one, so if it doesn't work it's easy to cook up something similar.
    1 point
  15. Thank you Ryan for sharing this with us. It is really interesting to see the challenges in scaling and how you solved it. Thank you so much for all your work, and big thanks to Jan for helping you making the PW infrastructure even more performant and reliable.
    1 point
  16. Hi @BitPoet, I just created a GitHub pull request with a fix for this. Cheers.
    1 point
  17. v006 is up - there are some new Reno theme tweaks plus LoadCollapsedModuleInfos. This auto-collapses module info fields on module configuration pages, saving space.
    1 point
  18. v003 is uploaded with some "before-the-weekend" Reno theme updates: Make header sticky: stick the header to the top of the browser window so it stays in place when scrolling down Make sidebar sticky: stick the sidebar to the top to make it always visible Auto hide sidebar on left: auto hide the sidebar so it's accessible by moving the mouse to the left side of the screen Always show sidebar items (disable accordion): make sidebar submenus more compact and do not hide them Place header button next to the main title: moves the top (cloned) main button next to the title to make it easier to reach Move notice close buttons to the left: put the close button of the notice message to the left for easier access
    1 point
  19. I am guessing that what Ivan is after is a Menu Builder MSN combo....as per the conversation we had....starting from here...and culminating with a PageArray here..If there was a possibility to do an in-memory $page->child = myOtherPage...(without saving)...hence assign non-native/natural children to parent menu items....that would probably solve his problem (the multidimensional bit) ...but that is not possible, If it were, don't know if getting in-memory children would work though...
    1 point
  20. I'd really like to see a PageTree object, which can hold a (whole or partial) page tree in memory. This would allow for testing stubs and similar or the api creation of a whole tree branch at once. But sadly the PageFinder class is often dependent on mysql functionality, which by now does not have feature parity with the in memory selector engine. Also a page tree object is not really like a multidimensional array, but rather a array of pages, which optionally hold another array of children. The concept this is more like e.g. the pw form api does work with it's fieldgroups. I could imagine something like this: class Tree extends WireArray{ public function isValidItem($item) { return $item instanceof Branch; } […] } class Branch extends Wire{ protected $page; /** @var Tree $children */ protected $children; function hasChildren(){}; function getChildren(){}; function addChild(){}; […] } Edit: Really nice could also be a base Tree class, which both a PageTree as well as e.g. the Forms API could inherit from. This would also allow for easy implementation of other (custom?) tree based constructs. Nested comments for example just came to my mind.
    1 point
  21. there's already this moduly by bitpoet for allowed parent pages: https://processwire.com/talk/topic/12793-template-parents/ i think it would be awesome to be able to select the allowed children on a per page basis. for example one could create a page "tools" on the tree. that page could be of template "item", like many other pages (just a title field). now it would be great to have the possibility to configure the allowed child templates somehow. - tools (item) - tools A (item) - foo X (foo) - foo Y (foo) - foo Z (foo) - tools B (item) - bar 1 (bar) - bar 2 (bar) - bar 3 (bar) at the moment this would need a template setup like this: - tools (items) -> allowing foos and bars - tools A (foos) - foo X (foo) - foo Y (foo) - foo Z (foo) - tools B (bars) - bar 1 (bar) - bar 2 (bar) - bar 3 (bar) i would be interested to hear your thoughts on this
    1 point
  22. Alternatevely if($page->parent->numChildren(true) > 1){ // true = only visible ones } This doesn't load the children/siblings pages just count.
    1 point
×
×
  • Create New...