Jump to content

How to approach this feat in Processwire


qtguru

Recommended Posts

I don't have an overview on what exactly you're using to render the mentioned _main.php. You can either use a if else statement in the _main.php and dependent on that include 2 different php files for the layouts or you need to take a look at the ProcessModule you're using to render it and see if you can change the file by hooking there. Or at least tell us here, what you're using, so we can help there.

;) I just woke up this morning and that thought crossed my mind while not create a hook to page to render the admin if the page url is member-dashboard but i put that logic in the member-login instead and it works, i guess my issue is am still stuck with the concept of other Framework's way of doing things. Thanks for the response. 

  • Like 1
Link to comment
Share on other sites

UPDATE: So After proper research and couple of beers and some Skyrim gaming, I realized that the previous solution stated was not appropriate, so i took a better approach.

1. I created a module hooking into Template::render

2. then i get the Session using the wire method

3. I also get the pages using the wire method then i check if the page url is member-login and when session has been enabled

4. if so i get the template from the event and i call the setAppendFIleName to my specified layout if not

5. set the main one

However this also affects the admin page

so i ensure that the page is not an admin if it's an admin do not set the main layout, so it seems i underestimated the Hook functionality as this is way intuitive then messing around the _main.php

Link to comment
Share on other sites

This was how i achieved having different layouts for my pages without touching the _main.php

Enjoy

public function init() {
       
        $this->addHookBefore('TemplateFile::render', $this, 'boot');
    }
   
    public function boot($e) {
        $pages = wire('page');

        if ($pages->name === "member-dashboard" && $pages->isPublic()) {
            $TemplateObject = $e->object;
            $TemplateObject->setAppendFilename(dirname(dirname(dirname(__FILE__))) . "/templates/_admin.php");
        }
        else {
            if($pages->template->name !== "admin"):
            $TemplateObject = $e->object;
            $TemplateObject->setAppendFilename(dirname(dirname(dirname(__FILE__))) . "/templates/_main.php");
            endif;
            }
    }
Link to comment
Share on other sites

  • 3 weeks later...

UPDATE:

So after trying to created a backend administrator page I encountered an error , It rendered the template twice apparently it seems my code was the cause of it so i have changed everything to something more cleaner and simple.

public function init() {
       
        $this->addHookBefore('PageRender::renderPage', $this, 'boot');
    }
   
    public function boot($e) {
        $pages = wire('page');
        if ($pages->name === "member-dashboard" && $pages->isPublic()) {
            $TemplateObject = $e->config;
            $TemplateObject->appendTemplateFile="_admin.php";
        }
        else {
            if($pages->template->name !== "admin"){
            $TemplateObject = $e->config;
            $TemplateObject->appendTemplateFile="_main.php";
            }           
    }
Link to comment
Share on other sites

  • 2 weeks later...

Hi just came across another bus stop. I am trying to implement a system, when users can create images and put them in a collection.

e.g Gallery Album A->has 5 images while Gallery Album B -> 2 images however in Processwire if you add a field to a template it adds to all pages making it hard for Members(Pages) to have individual Galleries or not. Thanks all won't mind pointers from experienced minds. 

Link to comment
Share on other sites

  • 3 weeks later...

So today found a new strategy for building processwire website and it's more awesome than all the strategy in place, because it allows you to easy modify codes without bothering about appending to content or pre-pending to content, will write a tutorial about this. ever since i discovered wireRenderFile(), it made things easier for me. Will drop a tutorial soon, please keep this post in mind.  :)

  • Like 3
Link to comment
Share on other sites

My Preferred method of Developing Processwire Templates

If you look at the normal tutorials pitched at developing Processwire website, it's really not flexible, how so you generate alot of content and perform concantenations alot here's an example of my previous styling following the PW standard 

<?phpob_start();
//Get the Slides
$ImageArray=$page->get('images');
$CountImages=count($ImageArray);?>
<?php if($CountImages): ?>
    <div id="carousel-example-generic" class="carousel slide " data-ride="carousel">
        <ol class="carousel-indicators">
            <?php for($i=0; $i < $CountImages; $i++):
            if($i==0):
            ?>
            <li data-target="#carousel-example-generic" data-slide-to="<?php echo $i ?>" class="active"></li>
            <?php else: ?>
                <li data-target="#carousel-example-generic" data-slide-to="<?php echo $i ?>"></li>
            <?php
            endif;
            endfor;
            ?>
        </ol>
        <div class="carousel-inner">
            <?php
            $count=0;
            foreach($ImageArray as $images):
            $thumb=$images->size(600,450);
            ?>
            <div class="item <?php echo ($count === 0) ? "active":"" ?>">
                <img class="" src="<?php echo $thumb->url ?>"
                    style="height: 450px;width: 600px;"
                    alt=""
                    />
                <div class="carousel-caption">                    <p>
                    <div>
                       <?php echo $images->description ?>
                    </div>                    </p>
                </div>
            </div>
            <?php $count++; endforeach; ?>
        </div>        <a class="left carousel-control" href="#carousel-example-generic" data-slide="prev">
            <span class="glyphicon glyphicon-chevron-left"></span>
        </a>
        <a class="right carousel-control" href="#carousel-example-generic" data-slide="next">
            <span class="glyphicon glyphicon-chevron-right"></span>
        </a>
    </div>
   <?php endif; ?>
    <br/>
    <div class="col-md-12 pull-right">
        <a class="pull-right" href="#"><img src="<?php echo $config->urls->templates?>/img/facebook_sarahs_nest.png" alt=""></a>
        <a class="pull-right" href="#"><img src="<?php echo $config->urls->templates?>/img/twitter_sarahs_nest.png" alt=""></a>
        <a class="pull-right" href="#"><img src="<?php echo $config->urls->templates?>/img/youtube_sarahs_nest.png" alt=""></a>
    </div><?php
$homeContent=ob_get_clean();
$content= $homeContent. $content;
?>
<h4>Sarah's Nest in Pictures</h4>
<div class="col-xs-6 col-md-4">
    <a href="#" class="thumbnail">
        <img src="<?php echo $config->urls->templates?>/img/Official-Opening16.jpg" alt="...">
    </a>
</div>
<div class="col-xs-6 col-md-4">
    <a href="#" class="thumbnail">
        <img class="img-responsive" src="<?php echo $config->urls->templates?>/img/Rabbit.jpg" alt="...">
    </a>
</div>
<div class="clearfix"></div>
<br>
<div class="col-md-8">
    <img src="<?php echo $config->urls->templates?>/img/sarahs-nest-object-bg.jpg" alt="">
</div>
<?php
$content.=ob_get_clean();
?>

Now how this works is that we put a content in this page and the _init.php holds global variables to be used e.g $title,$content while this is good it's become difficult to achieve flexibility and really I don't enjoy concatenations that much as I have to ensure it doesn't have any implication on performance.

The dilemma with this, is that you will no doubt have to put alot of logic in the templates which later become ugly, an example of such was when i need a front-page admin it felt hackish to have a logic in the same template to load a seperate css if login and if not. luckily PW is not opinionated that much, meaning you are free to do what you want. This is my preffered style.

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title><?php echo $title; ?></title>
  <meta charset="utf-8">
    <link href="<?php echo $config->urls->templates ?>css/bootstrap.min.css" rel="stylesheet" type="text/css" />
    <link href="<?php echo $config->urls->templates ?>css/helper.css" rel="stylesheet" type="text/css" />
    <link href="<?php echo $config->urls->templates ?>css/font-awesome.min.css" rel="stylesheet" type="text/css" />
    <link href="<?php echo $config->urls->templates ?>css/jquery.fancybox.css" rel="stylesheet" type="text/css" />
    <link href="<?php echo $config->urls->templates ?>css/animate.css" rel="stylesheet" type="text/css" />
    <link href="<?php echo $config->urls->templates ?>css/style.css" rel="stylesheet" type="text/css" />
    <link rel="shortcut icon" href="favicon.ico"/>
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
    <meta name="format-detection" content="telephone=no" />
    <title>Symphony</title>
</head>
<body>
<!--Header goes here-->
<?php echo wireRenderFile("ui/header.php"); ?>
<?php echo $content ?>
<?php echo wireRenderFile("ui/footer.php"); ?>

In this the main loads several fragments of the pages into the layout so you might be curious how does the template look like , well it looks like this 

home.php

<?php
$content=wireRenderFile("ui/fullscreen-slider.php",array(
    "title"=>$title,
    "body"=>$page->body,
    "slideshows"=>$page->sliderImages,
    "middleImage"=>$page->middleImage
)) ?>

This way it's more cleaner and easier to read and you can perform alot of logic easily such as swapping templates based on seperate scenarios, I know this doesn't explain much I will post a tutorial soon enough, as this has increased my speed in PW Development. 

  • Like 1
Link to comment
Share on other sites

URLSegments are awesome so i wanted to build a backend for the users , after cracking my head and losing confidence in my skills, I think at some point I was crying, till it hit me , wait a minute FrontDispatchers in Zend Framework take the route or the url and dispatches the Action to be called right, so I created a Module that alters my template when on a page called member-login and session is set, then it takes the user to the member-dashboard page, now on that page URL Segment has been enabled. 

Here is the source code that takes the url and handles the action:

<?php
$session=wire('session');
if($session->get('currentUserLogged') !== true){
$session->redirect($config->urls->root."/member-login");
}
require (dirname(__FILE__)."/admin_url_segments/SegmentUrlRenderer.php");
//let's get the current page from the session
$StyljunkiPageMember=$pages->get($session->get('SessionMember'));
$segment=new SegmenturlRenderer($input,$StyljunkiPageMember);
//If it is an Ajax Call return the call and nothing else
if($config->ajax){
    echo $segment->dispatch();
    exit();
}else{
    $content=$segment->dispatch();
}

Here is the source code of the SegmentController:

<?php
/**
* This class handles the Url Segment and selects a view to be rendered
*
*/
class SegmentUrlRenderer
{
    private $urlsegment;
    private $context;
    public function __construct($UrlSegment,Page $Context) {
        $this->urlsegment = $UrlSegment;
        $this->context = $Context;
    }
    public function dispatch() {
       
        //first get the controller folder
        return $this->processURL($this->urlsegment);
    }
   
    private function processURL($input) {
       
        //typical rules
        //URL 1: Controller Class
        //URL 2: Controller Class Method
      
        $controller_class = $this->urlsegment->urlSegment(1);
        $controller_action = $this->urlsegment->urlSegment(2);
       
        if ($controller_class === '') {
            $controller_class="Backend";
        }
       
        if ($controller_action === '') {
            $controller_action = "index";
        }
       
        //Get the matching controller
        $matching_controller = ucfirst($controller_class). "Controller.php";
        $matching_controller_prefixless=ucfirst($controller_class)."Controller";
        $controller_folders = dirname(dirname(__FILE__)) . "/controllers/";
        if(!file_exists($controller_folders.$matching_controller)){
          throw new WireException(sprintf('The Specified Controller File [%s] doesn\'t exist',($controller_folders.$matching_controller)));
        }
        require_once ($controller_folders . $matching_controller);
       
        //We need to introspect let's see that the method exists
        $controller = new $matching_controller_prefixless();
        $controller->appContext=$this->context;
        //Add the prehook
        if (method_exists($controller, "prehook")) {
            return $controller->prehook();
        }
  
        //does the method exist in the class
        if (method_exists($controller, $controller_action)) {
            return $controller->$controller_action();
        }
    }
    }

So i have a folder called "controllers" which has one controller class called backend so it the user types 

http://localhost/StyljunkiPW/member-dashboard/backend

It resolves to the default controller which is index as seen in the code here

if ($controller_class === '') {
            $controller_class="Backend";
        }
       
        if ($controller_action === '') {
            $controller_action = "index";
        }

So it works and renders the dashboard this is the profile page which pulls information from the Page Object 

post-2850-0-48851600-1431881685_thumb.pn

  • Like 1
Link to comment
Share on other sites

As seen in this code here:

<?php
class BackendController{
    const REGULAR_MEMBER_IMAGES=20;
    const PREMIUM_MEMBER_IMAGES=40;
 
  public function gallery(){
  
   $view=new TemplateFile(dirname(dirname(__FILE__))."/admin_templates/gallery.php");
        $view->set('images',$this->appContext->images);
   return $view->render();
  }
  public function index(){
   return $this->profile();
   }
  public function profile(){
   $view=new TemplateFile(dirname(dirname(__FILE__))."/admin_templates/default.php");
   $view->set('member_name',$this->appContext->fullname);
   $view->set('twitter',$this->appContext->twitter);
   $view->set('member_workinfo',$this->appContext->works);
   $view->set('country',$this->appContext->country);
   $view->set('member_age',$this->appContext->age);
   $view->set('member_brand',$this->appContext->brand);
   $view->set('member_phone',$this->appContext->phone);
   $view->set('member_address',$this->appContext->address);
   $view->set('member_information',$this->appContext->information);
        $view->set('followers',$this->getFollowers($this->appContext->post_id));
   return $view->render();
  }

The index calls the profile function, now the appContext is the Page Object which was inserted into the property of the class by SegmentUrlController, its kinda hackish but hey it works for me, I could have used wire('pages') but i need the Member details which was saved into the session after a user logs in, but i felt this was easier, this feels like my typical MVC Convention, however I noticed i hadn't test with calling Ajax which was why i added the code $config->ajax to simply exit as not to render a page. 

The gallery /member-dashboard/gallery works well I use DropZone a good JS library for uploading and also WireUpload and it worked smoothly no issues at all 

post-2850-0-39792900-1431882009_thumb.pn

Link to comment
Share on other sites

Uploading code in the BackendController

public function upload(){
         header("Content-type:application/json");
         if($this->appContext->premium == 1){
             if(count($this->appContext->images) >= self::PREMIUM_MEMBER_IMAGES){
                 return json_encode(array(
                     'status'=>'error',
                     'data'=> sprintf("Your Premium account has exceeded the maximum amount [%d]",self::PREMIUM_MEMBER_IMAGES)
                 ));
             }
         } else if(count($this->appContext->images) >= self::REGULAR_MEMBER_IMAGES){
             return json_encode(array(
                 'status'=>'error',
                 'data'=> sprintf("Your Premium account has exceeded the maximum amount [%d]",self::REGULAR_MEMBER_IMAGES)
             ));
         }
        $config=wire('config');
        $file=$_FILES['file'];
        $wireuploader=new WireUpload('file');
        $wireuploader->setDestinationPath($this->appContext->images->path);
        $wireuploader->setMaxFiles(1);
        $wireuploader->setOverwrite(true);
        $wireuploader->setValidExtensions(array('jpg', 'jpeg', 'gif', 'png'));
         $wireuploader->setTargetFilename($file['name']);
         $wireuploader->setAllowAjax(true);
        $resultSet=$wireuploader->execute();
        if(!$wireuploader->getErrors()){
            //Let's save the article to the page
            $this->appContext->of(false);
            $this->appContext->images->add($this->appContext->images->path.$resultSet[0]);
            $this->appContext->save();
            return json_encode(array(
                'status'=>'success',
                'data'=> sprintf("The %s has been saved to your profile successfully",$file['name']),
                "count"=>count($this->appContext->premium)
            ));
        }
         else{
             return json_encode(array(
              'status'=>'error',
              'data'=>$wireuploader->getErrors()
             ));
         }
     }
}

At first i was skeptical about it adding to the pages, because i felt it's too good to be true so checking the Real backend and viola this is the images added to it via the frontend 

post-2850-0-45625700-1431882274_thumb.pn

  • Like 3
Link to comment
Share on other sites

Best Part is that I have a Data used in Wordpress to get subscribers so without breaking changes , I could easily forgo the Page Object Mantra and also pull directly from the database

private function getFollowers($member_id){
         $database=wire('database');
         $statement=$database->prepare("SELECT COUNT( * ) FROM  `member_subscribers` WHERE member_id = :member_id");
         $statement->bindParam(":member_id",$member_id,PDO::PARAM_INT);
         $statement->execute();
         $result=$statement->fetch(PDO::FETCH_NUM);
         return $result[0];
     }

Luckily this is PDO and it's totally awesome, My Client is really happy with the outcome of the Project because she loves the backend of Processwire and also that Google analytics someone created, and really i was skeptical of PW at first (because if something is too good to be true, then something must be wrong secretly) but now i feel more comfortable with it more than ever, I could go the PW "Everything is a Page Model" or go Rogue and cook up some things, but I love the everything is a page in some scenarios, e.g getting Parent of pages and finding Children , in some ways it feels like JCR in Java but not that advanced though.

However i still have much questions ?

1. Having Multiple Albums per User

2. Social Authentication

Seriously guys give Dropzone.js a spin for frontend uploading, it's dead easy, good bye 

  • Like 2
Link to comment
Share on other sites

  • 7 months later...

This thread is great, you are far more technical than me. I'm just a front end developer. So to see someone having such a good time with the advanced part of ProcessWire is really encouraging. I too came from WordPress. It was my main platform for developing everything, and had been for many years. As you can imagine, finding ProcessWire was a breath of fresh air.

I must admit, I look at your code and I have no idea what's going off as I'm not that advanced. But you seem to find everything that is usually really difficult, easy in ProcessWire. I too have this. Only last year was I pulling my eyes out with pagination on WordPress. ProcessWire it's easy.

As for official discussion for PW3, there really isn't one to my knowledge. However, I think something like Gitter would work as we can have trivial discussions without spamming the forum. I was thinking the same for the Brand refresh for PW.

  • Like 2
Link to comment
Share on other sites

I think so having a Gitter is a good idea, thanks for the comment, if there's any part complex in Processwire let me know, it's because my work involves me doing Cordova 24-7 i try to take a break doing Processwire to strike a balance. 

  • Like 1
Link to comment
Share on other sites

There are usually 2 menu types on most sites. Let me generalise here a bit.

  • You've got the top navigation which tends to be global. It's on every page and usually accompanies the company logo.
  • Then you've got the side navigation which is contextual or based on the section the user is currently within.
I'm assuming you're asking how you your client can pick which links / pages are used on the top navigation?
  • Create a field called top_navigation or something meaningful to you and your clients
  • Set it to Type=Page type (Basics Tab)
  • Make it Multiple Pages (Details Tab)
  • Assign it PageListMultipleSelect+ win the Input field type (Input tab)
  • Finally, associate this naviagtion field with a template.

    You can just assign it to the homepage or you could create a new page called Site Settings or Navigation. Just tell your client this is the place to manage their top menu.

Here's a screengrab of how it should look.

navigation.png

with this implementation of menu builder, from the screenshot, it support only top level of navigation. could i add another page as a child of another page in top menu navigation?

Link to comment
Share on other sites

Hmm, I'm not sure what mean. Possibly I've misunderstood what you're trying to do.

Initially I thought you were trying to make a 1-level / linear menu but you may be trying to nest items?

Why don't you create a simple mockup of how you want this to look on the front end of your site? I'd have a better idea then.

It maybe a case that Somas navigation module might be better if you are building a hierarchy instead of a flat nav menu although I don't think that allows you to cherry pick what items are included.

Link to comment
Share on other sites

Hmm, I'm not sure what mean. Possibly I've misunderstood what you're trying to do.

Initially I thought you were trying to make a 1-level / linear menu but you may be trying to nest items?

Why don't you create a simple mockup of how you want this to look on the front end of your site? I'd have a better idea then.

It maybe a case that Somas navigation module might be better if you are building a hierarchy instead of a flat nav menu although I don't think that allows you to cherry pick what items are included.

Is it possible, pw out-of-the-box core modules, able to build something like below mockup screen, drag to intent a page  as a second level of menu navigation.

post-2272-0-80484200-1453089547_thumb.jp

Link to comment
Share on other sites

  • 2 months later...

Just wanted to use this medium to say i am extremely happy and impressed with the community, I have been away from Processwire because of works and pressure, each time i come back here i see something amazing, and honestly Processwire 3.0 is amazing and looking forward to do crazy things with this. 

  • Like 2
Link to comment
Share on other sites

  • 3 weeks later...

So i upgraded myself to Processwire 3.0 didn't want to update client's site without me taking the plunge and really with Processwire it seems Developer version is as good as stable. I totally and 100% love the Preview, blew my mind. 

Sadly I haven't been able to contribute as much as i should to 3.0 due to depression and total burn out. But really if anyone has a nice idea or any module i can contribute to, I don't mind. 

Thanks Ryan,Tom and the community for this awesome release. The preview is just too insane (slang for good) 

Link to comment
Share on other sites

Sadly I haven't been able to contribute as much as i should to 3.0 due to depression and total burn out. But really if anyone has a nice idea or any module i can contribute to, I don't mind. 

Get well soon. Sounds like you need a rest instead of contributing to any modules. Any chance you can take some time off or at least wind down a little?

Link to comment
Share on other sites

  • 2 weeks later...

@Sephiroth

Heads up! If you look for something to design (I mean on specification level), what about a simple newsletter module? This is something I occassionally need and as I know there is no "boxed" solution for it.

What I have in mind:

- integrate with other modules, eg. WireMailGun (to handle statistics)

- newsletter blocks with the ability to include other pages (I use PageTable or Matrix Repeater for this)

- newsletter subscription/unsubscription

- send preview

- css inliner (eg. Emogrifier)

I have these functionalities working but at a very low hand-made level. Anyway, just and idea that may get you electrified :)

  • Like 3
Link to comment
Share on other sites

@Sephiroth

Heads up! If you look for something to design (I mean on specification level), what about a simple newsletter module? This is something I occassionally need and as I know there is no "boxed" solution for it.

What I have in mind:

- integrate with other modules, eg. WireMailGun (to handle statistics)

- newsletter blocks with the ability to include other pages (I use PageTable or Matrix Repeater for this)

- newsletter subscription/unsubscription

- send preview

- css inliner (eg. Emogrifier)

I have these functionalities working but at a very low hand-made level. Anyway, just and idea that may get you electrified :)

Seems good, so this newsletter module, if you can explain how it works and all, i can gain some perspective into it. Thanks that won't be bad though because i remember doing all newsletter by hand too 

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...