Jump to content

MarkE

Members
  • Posts

    931
  • Joined

  • Last visited

  • Days Won

    10

Posts posted by MarkE

  1. I would pretty much agree with all the above comments. Having built a number of web apps, I would say that PW is by far my favourite tool to turn a conceptual design into a working application, quickly and in a fairly ‘natural’ way. Obviously you need some reasonable php knowledge. Also don’t underestimate the work in getting the look and feel that you want for the front end - it’s not like Wordpress in that regard (but I hate WP for apps). 
    You will need to give some careful thought as to whether you do one or two sites. If there is a lot of interaction between the front end and the admin functions then one site is probably best. Otherwise two interacting sites gives you a ‘cleaner’ CMS for the public site but is slightly more complex to implement. 
    Last, but not least, the PW forum members are really helpful if you get stuck ?

    Ps. Not sure if the op is still interested but that’s my twopennorth anyway. 
     

    • Like 2
  2. 14 hours ago, bernhard said:

    I've modified the behaviour of isActive() so that it treats the homepage different than all other pages. It does now only mark the homepage active if the currently views page is the homepage (id=1).

    The issue is a bit more complex than that, maybe because of the way my menus work. I tend to have (viewable) pages which have (viewable) children, so the top-level menu items can also be pages, in which case they also appear in the dropdown and can be selected either by clicking the top-level item or the one on the dropdown. If you just fix the home page highlighting then, in my case, the parent will be highighted in the dropdown as well as on the top level. See pics below:

    What I want (& my code above gives):

    2110417820_Menu1.jpg.f822eaef8597897c8708a6bcc0526439.jpg

    What isActive() gives me (currently):

    522832155_Menu2.jpg.531857f83bc3648a25d59e117e41e9a8.jpg

    14 hours ago, bernhard said:

    I think you are making things more complicated than they need to be. $page->children() already return the children in the admin sort order. So if you call $page->children() recursively in your menu than the menu perfectly reflects the page tree.

    Aagh! Of course you are right. I changed it to find() so that the home page was also included. Your menu assumed that home was not a menu item (hence also the issue with isActive() ). So now I have changed it to $home->children($selector) and the order is correct and all my complications go away (but I do then need to prepend $first to $items). Never mind it was an interesting exercise and may come in useful one day.

    • Like 1
  3. 7 hours ago, bernhard said:
    16 hours ago, MarkE said:

    and also a menu which mirrors the page hierarchy (for pages matching a given selector) - I can supply an example if anyone is interested.

    Sure!

    I've posted that in the Latte thread since it makes more sense (maybe?) there. 

     

    7 hours ago, bernhard said:

    I don't understand. ALFRED's whole purpose it to have an easy frontend editing interface when inline editing does not work or is not appropriate... What do you mean?

    Maybe I misunderstood. I see now that alfred is a substitute for Option D only.

    7 hours ago, bernhard said:

    But you can customize the toggle of your lightbox

    Thanks for that - works well.

    7 hours ago, bernhard said:

    It's not obvious to me that this does not work. What exactly is wrong? Maybe you are just missing quotes in your alfred call? Or is is the issue with the lightbox that might be solved with the solution I showed above?

    I get an error "Call to a member function hasField() on null" which seems to be generated from Latte (RuntimeChecker.php line 38). I guess it is something to do with $img being a PageImage class and not a Page. "theme_summary" is a custom image field and I'm struggling finding out how to use a front end editor on those. The image is one of a number in an images field within a repeater, which I guess doesn't make it any easier. Before custom image fields came along, I used to put each image on a page and link to them with a multi-value page ref field - I'm sort-of wishing I'd carried on that way. And BTW, I the lightbox fix doesn't work in this context - the fix I use is uk-lightbox="toggle: .gallery-item a" but that catches the figcaption too and trying anything more specific messes up the lightbox.

  4. 55 minutes ago, bernhard said:

    Could you please explain that in detail?

    isActive() selects the parent page as active as well as the current page. I have a structure where the home ('/') page is the landing page and the (immediate) children need to be at the same level as Home. isActive() always shows Home as active whenever one of the other menu items is active.

    55 minutes ago, bernhard said:

    What I also do not understand: What do you mean by reflect the page tree hierarchy?

    I mean that the menu hierarchy (other than Home) looks exactly like the page tree (but just for pages which are menu items). So if the page tree is:

    Home
    - Child 1
    - Child 2
    -- Grandchild 1
    -- Grandchild 2
    - Child 3 
    etc.

    the menu will be:

    Home     Child1     Child2     Child3
                                  - Grandchild 1
                                  - Grandchild 2

    55 minutes ago, bernhard said:

    If I call $page->children() then they are already sorted in the correct order, no?

    Not always. If no sort order is specified, they will be in id order (I think) - which is fine if you created them in the order you want. If you specify "sort=sort" then the top level will be correct, but lower levels will get mixed in - see 

     

    55 minutes ago, bernhard said:

    And what are the custom page class methods for?

    So those give a sort order as it appears in the page tree hierarchy: like 1, 2, 3, 4, 4.33, 4.66, 5 where 4.33 and 4.66 are the grandchildren. That way you don't encounter a child in the list before you have had its parent (which messes up the menu).

    EDIT: BTW, the $shown var is to prevent children being shown subsequently as higher-level items - not sure if that was fixing a problem in the original code or was just needed in my version.

  5. Thanks for the menu suggestion @bernhard. I have done a variation on this to do a hierarchical menu which relects the page tree structure. The code below should be considered illustrative, rather than a recipe. In particular, you will need to adapt it to whatever css framework you are using. Also, my "nav.latte" is in the context of a repeater matrix item (part of my page builder framework), so the called methods live in the custom page class of the getForPage() (custom page classes don't work with repeaters directly).

    {* in nav.latte *}
    
    {var $selector = ($page->theme_selector) ?: "template=ThemeDisplay"} {* specific to my page builder. Define whatever selector you want for menu items here. *}
    
    {* define block that is used for recursion *}
    {define items, $items, $first, $selector, $shown = new ProcessWire\PageArray}
    {do $items = $page->getForPage()->treeSort($items)} // or you could put the function in init.php, suitably modified
        {foreach $items as $item}{* loop all items*}
            {* define variables for inside the loop *}
            {var $subid = "tm-menu-" . $item->id}
            {var $numc = ($item->numChildren($selector) && $item !== $first)}
            {var $active = (($item == $rockfrontend->wire->page) || ($numc && $item->children()->has($rockfrontend->wire->page)))}
            {* I had a problem with $rrockfrontend->isActive() not highlighting what I wanted, hence the above custom code *}
            {* list item markup (NB Bulma css) *}
            <a n:if="!$numc && !($shown->has($item) && $item !== $first)" href="{$item->url}" n:class="navbar-item, $active ? 'is-active'">
                {$item->title}
                {do $shown->add($item)}
            </a>
            <div n:if=$numc class="navbar-item has-dropdown is-hoverable">
                <a n:class="navbar-link, $active ? 'is-active'" href="{$item->url}">{$item->title}
                </a>
                {do $shown->add($item)}
                {* list for child-items *}
                <div class="navbar-dropdown">
                    {var $children = $item->children($selector)}
                    {include items, $children->prepend($item), $item, $selector, $shown}
                    {do $shown->add($children)}
                </div>
            </div>
        {/foreach}
    {/define}
    
    <nav class="navbar is-fixed-top is-transparent" role="navigation" style="{$page->theme_style|noescape}"
         aria-label="main navigation">
        <div class="navbar-brand">
            <a class="navbar-item" href="{$urls->root}">
                <img src="{$logo->url}" alt="{$logo->description}">
            </a>
            <a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false"
               data-target="navbarMain">
                <span aria-hidden="true"></span>
                <span aria-hidden="true"></span>
                <span aria-hidden="true"></span>
            </a>
        </div>
        <div id="navbarMain" class="navbar-menu">
            <div class="navbar-start">
    
                {* now include the block for the first level of items *}
      {include items, $pages->find($selector), $home, $selector}
            </div>
    
        </div>
    </nav>
    /* In the custom page class */
    
    /**
    	 * Sort pages by how they appear in the page tree hierarchy
    	 *
    	 * @param $pages
    	 * @return void
    	 */
    	public function treeSort($pageItems) {
    		foreach($pageItems as $index => $item) {
    			$item->treeSortVal = $this->treeSortVal($item)[0];
    		}
    		$pageItems->sort('treeSortVal');
    		return $pageItems;
    	}
    
    	private function treeSortVal($item) {
    		$val = $item->sort + 1;
    		$increment = 1;
    		if ($item->numParents() > 0 && $item->parent() !== $this->pages()->get('/')) {
    			$siblingNum = max($item->siblings()->explode('sort'));
    			$parentVal = $this->treeSortVal($item->parent());
    			$increment = (1 / ($siblingNum + 2)) * $parentVal[1];
    			// (add 2 because we added 1 to sort to get $val, then we want 1 more than the greatest $val so that the fraction is always less than 1)
    			$val = ($val * $increment) + $parentVal[0];
    		} else {
    		}
    		return [$val, $increment];
    	}

     

    • Like 1
  6. Latte & RockFrontend make a great combination. I have done a couple of variations: indented repeaters - as per above:

    and also a menu which mirrors the page hierarchy (for pages matching a given selector) - I can supply an example if anyone is interested.

    I'm now getting to know Alfred ? and have a few queries:

    1. Is in-line editing possible?
    2. I have a gallery (using Uikit lightbox). When I use alfred with that - <div uk-lightbox {alfred($page, theme_images)}> - the lightbox is opened when I click the edit button and I have to close it before editing - is there any way round that?
    3. Also, in the gallery, I would like to use alfred to edit the indiviual image <figcaption>. Sort of like
      <figcaption {alfred($img, theme_summary)>{$img->theme_summary}</figcaption>

      but obviously that doesn't work. Any way this is possible?

    Many thanks for any suggestions.

  7. On 4/8/2021 at 11:27 AM, kaz said:

    Module is not installable because not all required dependencies are currently met.
    PHP 7.4.14 >= 5.6MarkupPwpswpGallery

    From what I can tell, this is just a problem with the PW module download/install code ( @ryan?), owing to a comment in the array. If you download separately then unzip and install it is OK. However, the lack of ongoing maintenance/support does seem to be an issue.

  8. Looks good @ryan   I’ve already built 2 apps with invoicing as part of them. The approach is pretty similar. I used hanna codes quite a bit for the invoice layout. 
    To my mind, the important thing would be the ability to integrate into a wider app (which might, for example, handle products and stock levels). In some ways I think the profile approach is better than a module for this. However, if someone wants to use it in an existing app (or one already in development) we once again hit the issue of “migrations” about which I know there are various views. Ideally you need a way to incorporate the code and database components into another project. 

    • Like 2
  9. 7 hours ago, bernhard said:

    Does that make sense?

    Yes and no. I couldn't get your code to work. It seems like you need to put the matching <div> in the php file, not the latte file. So, with your example (where<div id="foo"> matches an id in _main.php)

    // home.php
    
    <div id='foo'>
    <?= $rockfrontend->render("sections/home.latte"); ?>
    </div>
    
    // sections/home.latte
    <h1>{$page->title} - foo!</h1>

     

    Afterthought: However, it seems that Latte makes markup regions all rather unnecessary and confusing - easiest just to directly render latte files from _main.php. For flexibility, I have 

    // In _main.php:
    <body>
    <?= $rockfrontend->render("layouts/main.latte"); ?>
    </body>
    
    // In layouts/main.latte:
    {include "$page->template.latte"}
    // plus whatever else you want (sections etc)
    
    // Then whatever in the template latte file

    Unfortunately, it seems you still need the php template file, even if empty. It would be nice to get rid of that...

  10. Just starting to use this and I like what I see ?.

    I have always used markup regions for my front-end rendering and am wondering what is the best way of making these play with RockFrontend and Latte (if at all)?

    I like the renderMatrix method, but it just renders flat html when the repeaters have structure (depth), so I built an analogue - renderMatrixIndented, which renders the structure via <div> tags. Here is some code (which lives in my custom page class) in case it is of any use.

    /**
    	 * Render RepeaterMatrix fields with depth
    	 * Each level receives a div with a class name equal to the item type
    	 * @return string
    	 */
    	public function renderMatrixIndented($items, $vars, $options, $rockfrontend)
    	{
    		$out = '';
    		$depth = -1;
    		$divCount = 0;
    		foreach ($items as $item) {
    			$field = $item->getForField();
    			$type = $item->type;
    			$depthChange = $depth - $item->depth + 1;
    			if ($depthChange > 0) {
    				while($depthChange--) {
    					$out.= '</div>';
    					$divCount--;
    				}
    			}
    			$out.= "<div class={$type} style='{$item->theme_style}'>";
    			$divCount += 1;
    			$file = "fields/$field/$type";
    			$vars = array_merge($vars, ['page' => $item]);
    			$out .= $rockfrontend->render($file, $vars, $options);
    			$depth = $item->depth;
    		}
    		while($divCount--) {
    			$out.= "</div>";
    		}
    		// if renderMatrix was called from a latte file we return HTML instead
    		// of a string so that we don't need to call |noescape filter
    		$trace = Debug::backtrace()[1]['file'];
    		if (strpos($trace, "/site/assets/cache/Latte/") === 0) $out = new Html($out);
    		bd($out, 'OUT');
    		return $out;
    	}

    No doubt this could be generalised somewhat. BTW, it also adds some styling to each item if it has a field 'theme_style' but that could probably live elsewhere. I am using this in a simple page builder where class names can correspond to grid areas.

  11. version 0.0.19 adds 2 new Measurement methods: baseMultiplyBy() & baseDivideBy().

    You can use these instead of multiplyBy() or divideBy(), where it is expected that the result of multiplyBy() or divideBy() would be an unknown quantity. These methods anticipate that the result will be a BaseMeasurement and avoids unnecessary warnings

  12. I was just starting to develop something similar, based on CSS grid, which I think is the right way to go. One thing my design has is “pro-forma” pages - ie pages with pre-defined layout and dummy content that you can use to create similar pages. This is an approach I have taken before for “standard letters” and works well. Not sure if that’s in your module @jploch, but I’m hoping I could easily add it. Anyway, I’ll hold off now and test yours, if I may. I have a project I was going to use which is a WP conversion with a simple theme, which I hope makes a reasonable test bed. I’ll also look into how well my (json-based) DbMigrate module plays with it. 

    • Like 1
  13. 31 minutes ago, orchardheightsdental said:

    I'm definitely not a developer

    If you are a designer not a developer, then I would suggest trying to move a site from one CMS to another is a bit of an ask. If you are happy with the structure and just want to modify content, then you should be able to do that in ProcessWire without any particular technical or coding skills. If you want a new look and feel and don’t want to use a developer, then maybe start from scratch in WP, just copy and paste what content you need. That assumes that you are proficient in WP. I gave up on WP because, while it looks simple, the complexity goes up exponentially the more you try to do. 

    • Like 5
  14. 1 hour ago, pwired said:

    Coming to my point: I hope that what is happening in the Wordpress Pagebuilder scene will never happen with future Processwire Pagebuilders.

    I quite agree. BUT I think ProcessWire would benefit from a larger user group. Many (professional) developers are influenced by the critical mass of an open source solution - below a certain level and they are wary of being tied into a framework that may be going nowhere. For that reason, ProcessWire is often not chosen and an inferior, but more widely used, system is selected instead.

    The advantages that a page builder potentially brings are, to my mind:

    • More users are attracted to PW. Some of these might be 'non-coders'. Equally, they may be people who can code (to some extent) but who just want to implement a simple site quickly (which might be enhanced later).
    • A developer can off-load some of the work to a 'non-coder' who can focus on design aspects (this may be the client)

    However, the crucial point that @pwiredmakes is that the use of a page builder should not restrict the site further. The structure of ProcessWire is such that this ought to be achievable, but only if a page builder makes use of PW components in a transparent and modifiable way.

    There seems to be quite a bit of activity in this area, notably @Jonathan Lahijani's above and @bernhard's RockMatrix (still under wraps, I think), and it would be good to have a bit more visibility of the approaches used and how they meet these objectives.

    I have done a bit of thinking myself about how a page builder should look, but it's early days yet (and I don't want to re-invent the wheel). Ideally it would make use of standard PW components, but it would be opinionated to some extent (CSS grid and Tailwind seem obvious choices). Trouble is, most of the paths I have explored so far end up using RepeaterMatrix. Don't get me wrong, RM is a great field, but I don't think it's a great idea to have a page builder, which is designed to atrract new users, being dependent on a commercial module.

    P.S. Also, I think a page builder should allow for multiple themes, so that developers can easily add a new theme.

  15. Update to the above post. I changed all the name/user details to the defaults:

    	$config->dbName = 'db';
    	$config->dbUser = 'db';
    	$config->dbPass = 'db';
    	$config->dbPort = '3306';

    I realised that ddev assigns a dynamic db port so I added a static host_db_port: "3306" to .ddev/config.yaml.

    I can access the db in phpMyAdmin  - and in the phpStorm database tool (now that it has a static port).

    I added a var_dump of pdoConfig to check what PW is looking for, namely

    array(5) { ["dsn"]=> string(40) "mysql:dbname=db;host=localhost;port=3306" ["user"]=> string(2) "db" ["pass"]=> string(2) "db" ["options"]=> array(2) { [3]=> int(2) [1002]=> string(16) "SET NAMES 'utf8'" } ["reader"]=> array(4) { ["dsn"]=> string(0) "" ["user"]=> string(0) "" ["pass"]=> string(0) "" ["options"]=> string(0) "" } }

    This matches exactly the config data I enetered into phpStorm's database tool (host: localhost, port:3306, user:db, password:db, database:db) which connects sucessfully.

    But I still get this error

    Quote

    Excuse me… Error: Exception: SQLSTATE[HY000] [2002] No such file or directory (in wire/core/WireDatabasePDO.php line 511)

    #0 wire/core/WireDatabasePDO.php (511): PDO->__construct('mysql:dbname=db...', 'db', 'db', Array)

    where the last array is ["options"] in the var_dump above.

    Any ideas? ?

×
×
  • Create New...