GithubHelp home page GithubHelp logo

soberwp / controller Goto Github PK

View Code? Open in Web Editor NEW
366.0 26.0 42.0 225 KB

Composer package to enable a controller when using Blade with Sage 9

License: MIT License

PHP 100.00%
wordpress-plugin blade-template blade controller php sage wordpress

controller's Introduction

Controller

WordPress package to enable a controller when using Blade with Sage 9 (Please note, Sage 10 uses Composers and not this package.)


Installation

Composer:

Sage ships with Controller. However, should you need to install, browse into the Sage theme directory and run;

$ composer require soberwp/controller:2.1.2

Upgrading to 2.x.x:

Please note that versions 2.x.x are newer releases than 9.x.x-beta. The 9 was used to match Sage 9 versioning at the time.

Controller 2.x.x uses PSR4 autoloading to load Controller classes. This is considered best practice. You will need to update the following files from 9.0.0-beta versions.

Folder controllers/ changes to Controllers/, class file names changes to camelcase App.php and FrontPage.php. Controller namespaces changes to namespace App\Controllers;

Requirements:

Setup

By default Controller uses namespace Controllers.

Controller takes advantage of PSR-4 autoloading. To change the namespace, use the filter below within functions.php

add_filter('sober/controller/namespace', function () {
    return 'Data';
});

Usage

Overview:

  • Controller class names follow the same hierarchy as WordPress.
  • The Controller class name should match the filename
    • For example App.php should define class as class App extends Controller
  • Create methods within the Controller Class;
    • Use public function to return data to the Blade views/s
      • The method name becomes the variable name in Blade
      • Camel case is converted to snake case. public function ExampleForUser in the Controller becomes $example_for_user in the Blade template
      • If the same method name is declared twice, the latest instance will override the previous
    • Use public static function to use run the method from your Blade template which returns data. This is useful for loops
      • The method name is not converted to snake case
      • You access the method using the class name, followed by the method. public static function Example in App.php can be run in Blade using App::Example()
      • If the same method name is declared twice, the latest instance will override the previous
    • Use protected function for internal methods. These will not be exposed to Blade. You can run them within __construct
      • Dependency injection with type hinting is available through __construct

The above may sound complicated on first read, so let's take a look at some examples to see how simple Controller is to use.

Basic Controller;

The following example will expose $images to resources/views/single.blade.php

app/Controllers/Single.php

<?php

namespace App\Controllers;

use Sober\Controller\Controller;

class Single extends Controller
{
    /**
     * Return images from Advanced Custom Fields
     *
     * @return array
     */
    public function images()
    {
        return get_field('images');
    }
}

resources/views/single.blade.php

@if($images)
  <ul>
    @foreach($images as $image)
      <li><img src="{{$image['sizes']['thumbnail']}}" alt="{{$image['alt']}}"></li>
    @endforeach
  </ul>
@endif

Using Functions;

You can use static methods to run a function from within your view.

This is useful if you are within the loop and want to return data for each post item.

app/Controllers/Archive.php

<?php

namespace App\Controllers;

use Sober\Controller\Controller;

class Archive extends Controller
{
    public static function title()
    {
        return get_post()->post_title;
    }
}

resources/views/archive.php

@extends('layouts.app')

@section('content')

  @while (have_posts()) @php the_post() @endphp
    {{ Archive::title() }}
  @endwhile

@endsection

Using Components;

You can also create reusable components and include them in any Controller class using PHP traits.

app/Controllers/Partials/Images.php

<?php

namespace App\Controllers\Partials;

trait Images
{
    public function images()
    {
        return get_field('images');
    }
}

You can now include the Images trait into any view to pass on variable $images;

app/Controllers/Single.php

<?php

namespace App\Controllers;

use Sober\Controller\Controller;

class Single extends Controller
{
    use Partials\Images;
}

Inheriting the Tree/Hierarchy;

By default, each Controller overrides its template hierarchy depending on the specificity of the Controller (the same way WordPress templates work).

You can inherit the data from less specific Controllers in the hierarchy by implementing the Tree.

For example, the following app/Controllers/Single.php example will inherit methods from app/Controllers/Singular.php;

app/Controllers/Single.php

<?php

namespace App\Controllers;

use Sober\Controller\Controller;
use Sober\Controller\Module\Tree;

class Single extends Controller implements Tree
{

}

If you prefer you can also do this;

<?php

namespace App\Controllers;

use Sober\Controller\Controller;

class Single extends Controller
{
    protected $tree = true;
}

You can override a app/Controllers/Singular.php method by declaring the same method name in app/Controllers/Single.php;

Creating Global Properties;

Methods created in app/Controllers/App.php will be inherited by all views and can not be disabled as resources/views/layouts/app.php extends all views.

app/Controllers/App.php

<?php

namespace App\Controllers;

use Sober\Controller\Controller;

class App extends Controller
{
    public function siteName()
    {
        return get_bloginfo('name');
    }
}

Advanced Custom Fields Module;

Controller has an useful Advanced Custom Fields helper module to automate passing on fields.

The automated fields will use the variable names from Advanced Custom Fields and pass them onto the view. Controller also passes on options values by default.

<?php

namespace App\Controllers;

use Sober\Controller\Controller;

class Single extends Controller
{
    // Pass on all fields from Advanced Custom Fields to the view
    protected $acf = true;

    // Pass on only field_1 from Advanced Custom Fields to the view
    protected $acf = 'field_1';

    // Pass on multiple fields from Advanced Custom Fields to the view
    protected $acf = ['field_1', 'field_2'];
}

Clone fields will return the value of each the fields in a separate variable, unless the Prefix Field Names option is enabled in which case the the cloned fields will be returned in an object with the field name given to the clone field.

The values are returned as objects, however you can disable this to keep them as arrays.

add_filter('sober/controller/acf/array', function () {
    return true;
});

Template Override Option;

You should only use overrides in edge-case scenarios. Sticking to the WordPress hierarchy is recommended usage. However, one edge-case is the 404 template.

In your Blade view, you would have 404.blade.php as it begins with a number. In this case, you could rename your Controller class FourZeroFour.php and use parameter $template = '404';

<?php

namespace App\Controllers;

use Sober\Controller\Controller;

class FourZeroFour extends Controller
{
    protected $template = '404';
}

Lifecycles;

Controller Classes come with two lifecycle hooks for greater control.

public function __before()
{
    // runs after this->data is set up, but before the class methods are run
}

public function __after()
{
    // runs after all the class methods have run
}

Disable Option;

protected $active = false;

Blade Debugger;

In your Blade views, resources/views, you can use the following to assist with debugging;

  • @debug
  • @dump(__var__)

Blade Coder;

In your Blade views, resources/views, you can use the following to assist with jump-starting coding;

  • @code
  • @code('__name of variable as string__')

To wrap the code in if statements, use @codeif

  • @codeif
  • @codeif('__name of variable as string__')

Support

Updates

  • Change the composer.json version to 2.1.2
  • Check CHANGELOG.md for any breaking changes before updating.
$ composer update

controller's People

Contributors

9585999 avatar briggysmalls avatar clayton93 avatar darrenjacoby avatar fiskhandlarn avatar hofmannsven avatar leocolomb avatar markjaquith avatar n-dawson avatar osadler avatar slackday avatar sweber83 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

controller's Issues

9.0.0-beta.3 controller.php missing plugin headers - uninstallable

Can't install beta.3 using any normal methods.

From Sage 9 empty theme I have no way of updating to beta3. Adding the repository directly to my composer.json will install it into ../../plugins/controller (from inside theme dir), but the controller.php is lacking a plugin header so it won't activate. After manually adding the Plugin header and activating it complains that it's missing dependencies.

You can't manually install via zip for the same reason.

Thoughts? I know I'm missing something obvious here, any help would be much appreciated.

"repositories": [
    {
      "type": "package",
      "package": {
        "name": "soberwp/controller",
        "type": "wordpress-plugin",
        "version": "9.0.0-beta.3",
        "source": {
          "type": "git",
          "url": "[email protected]:soberwp/controller.git",
          "reference": "master"
        }
      }
    }
  ],
  "autoload": {
    "psr-4": {
      "Roots\\Sage\\": "app/lib/Sage/"
    }
  },
  "require": {
    "php": ">=5.6.4",
    "composer/installers": "~1.0.25",
    "illuminate/view": "~5.4.0",
    "illuminate/config": "~5.4.0",
    "soberwp/controller": "9.0.0-beta.3"
  },
  "require-dev": {
    "squizlabs/php_codesniffer": "^2.8.0"
  },
  "extra": {
    "installer-paths": {
      "../../mu-plugins/{$name}/": ["type:wordpress-muplugin"],
      "../../plugins/{$name}/": ["type:wordpress-plugin"],
      "../../themes/{$name}/": ["type:wordpress-theme"]
    }
  },

Call to undefined function Sober\Controller\add_action()

Just installed controller using

composer require soberwp/controller:9.0.0-beta.3

and getting the following error across the whole project

Error: Call to undefined function Sober\Controller\add_action() in /srv/www/myproj/current/vendor/soberwp/controller/controller.php on line 36

file paths

Hi, this looks really great.

just wondering if
resources/controllers/single.blade.php
should read
resources/views/single.blade.php
in the readme?

Do not force project namespace

We should not be forced to use the App/Controller namespace and be able to change App to our projects namespace.

Thanks.

Default directory

Hi,

Sometimes there is a point in moving required theme files (functions.php, style.css, index.php, screenshot.png) to theme's top-level directory. This might even become an option in Sage: roots/sage-installer#3. When those files are moved, get_template_directory() points to root folder and it breaks default directory both for Controller and Models:

$this->path = (has_filter('sober/controller/path') ? apply_filters('sober/controller/path', rtrim($this->path)) : dirname(get_template_directory()) . '/app/controllers');

My proposition is to use get_theme_file_path() without dirname() instead. Thanks to Sage filter (https://github.com/roots/sage/blob/b4421be2696bd6021a11eb6893bb6fbb8a949d15/resources/functions.php#L80) it points to root directory when using default Sage setup, and when functions.php are moved this filter must be disabled anyway, so it also points to root directory. Thanks to that this is a non-breaking change.

WDYT?

traits

ive got a trait that require data set in another trait, when i try to use trait 1 inside trait2, i get an not found error. is it possible to do this?

Index.php is missing from hierarchy for categoreis

This is the output of hierarchy debugger for one of category pages in one of my projects:

/controllers/app.php
/controllers/archive.php
/controllers/category.php
/controllers/category-2.php
/controllers/category-fitness.php

I would expect there to be an index.php just above archive.php to comply with the default wp template hierarchy. Is index.php omitted intentionally?

Make "data" property protected instead of private

Making the "data" property protected instead of private would make it easier to add data in bulk via the constructor. This would be useful for pulling all ACF fields at once, or pulling in additional data from database or API.

public function __construct(){
   $fields = get_fields();
   $this->data = array_merge($fields, $this->data);
}

How are you creating files?

Hey, man.
I'm trying to follow your example in Controller to add a directory with a couple of files to Sage upon composer install (or whatever trigger you're using), and I'm not sure where else to get a hold of you :)

I can't for the life of me find where you're creating these folders and files.

Can you point me in the right direction? How are you doing this? It's cool and I want to do it, too!

$__currentLoopData

Hi, is there any sense in these variables in the Controller Debugger?

img_2017-08-26_ _10_32_24

As I understood for the conclusion of similar things the function sanitize() answers, can it be necessary to it to fasten the filter, or something like this, so that it would be possible to optionally remove unnecessary variables?

For example, the $query variable that is defined in the template, I do not need in 99% of cases, but it is with a huge list of arrays ... The variable $term also makes no sense in the debugger, since this is one element of the array $terms_category, which can be so Peep at $terms_category ...

Variables from controllers/base.php not accessible in template

I'm using Sage 9.0.0-beta.2 and also the compatible version of this controller. Which I really like a lot btw :)

Reading the documentation about global variables I'm experiencing an issue.

I have created a simple base.phpcontroller which looks like following:

<?php

namespace App;

use Sober\Controller\Controller;

class Base extends Controller
{
    public function footer()
    {
        $footer = [];

        if (function_exists('get_field'))
        {
          $footer['text'] = get_field('footer_text', 'options');
        }

        return $footer;
    }
}

I also have controller controllers/page.php which runs.

If I var_dump inside the controller I can see that the code is running. However the variable is not present in templates/partials/footer.blade.php.

Why are variables in base not present when page also runs?

There are many workarounds if I use traits it works but I have to include the trait in Page which seems like overhead since I plan to add more controllers.

The best workaround is to add protected $tree = true; // Inherit all templates to Page but this is the same overhead as above.

Also I would find it useful if there was an options like "reverese tree" instead of using class X extends Controller implements Tree it would be cool if there was an global or "must use" kind of like Base but you could call the controller what you want and it would always run.

Thanks!

Controllers direcory

Just a thought, but shouldn't the controllers/ directory be by default under app/?
So app/controllers/ instead of resources/controllers, like Laravel does?

I know there is a filter for this, but i see that this package is now shipped with Sage 9, and because Sage seems to follow Laravel philosophy and file structure, why would it be under resources/?

Thanks!

Using constructor to pull data?

My intent was to use a simple constructor on my controller to pull in all the ACF field data for the page and store in a protected $fields property which could be accessed by the controller methods.

Unfortunately, this does not seem to be working. I'm not sure why, but I also created the below non ACF test which also does not work.


<?php

namespace App;

use Sober\Controller\Controller;

class FrontPage extends Controller {
    
    protected $message;

    public function __construct() {
        parent::__construct();
        $this->message = "This is my message.";
    }

    /**
     * Return message
     *
     * @return string
     */
    public function message(){
        return $this->message;
    }

}

Any ideas?

Naming with hyphens?

I see the naming strategy has been changed.

How do you name controllers whose templates include hyphens? For example template-faq.blade.php

Thanks

post loop?

great package, excellent addition for bedrock / sage. i have functions in src/single.php in which i am trying to output get_the_content() and post_class(), they are both empty, the_title is not empty. is this because its not inside of the loop?

Blade template doesn't work on my Sage 9

Hi, I am testing the plugin on my Sage 9 theme. However, there is a problem that I couldn't find the answer. When I follow the instruct to create an example to expose $images to resources/views/single.blade.php

However, my page doesn't recognize the blade template and displays the raw content of the blade instead of showing an error or something like that.

My code is at: https://github.com/dalenguyen/sage-dn/commit/ab9ed7d73ab096ddff73b29b91d714fde5133819

Sample post with the single.php created in resources/views/single.blade.php

http://edu.dalenguyen.me/blog/2017/05/11/hello-world/

Any thoughts? Thanks,

Sage - SoberWp Controller - {! App::title() !} in blade view is not working

https://discourse.roots.io/t/sage-soberwp-controller-app-title-in-blade-view-is-not-working/10326

I have raised this issue here already. sage with controller is not working out of the box~

I have just installed the latest version of sage that uses the soberwp controller package, after running composer install and yarn as instructed in docs I get this error on the site home page:

Fatal error: Uncaught Symfony\Component\Debug\Exception\FatalThrowableError: Class 'App' not found ....

ErrorException: Class 'App' not found (View: /srv/www/xxxxxxx.org/current/web/app/themes/sage-controller/resources/views/partials/page-header.blade.php) (View: /srv/www/xxxxxxx.org/current/web/app/themes/sage-controller/resources/views/partials/page-header.blade.php) in /srv/www/xxxxxxx.org/current/web/app/uploads/cache/b86c51c4f6669655bff05894c46da3bddd3b03b4.php on line 2

I thought the controllers weren’t loading but in vendor/composer/autoload_psr4.php this line exists:

'App\\' => array($baseDir . '/app'),

maybe the contollers/helpers are not accessible to the blade views

any help would be appreciated, thanks

Adding actions and filters

Hi,

I was wondering if Controller could be used to also run actions and filters for specific templates?

For example on an archive template I might need to change default query with pre_get_posts, change excerpt length, etc.

Using the hierarchy to run them makes sense, so can we use Controller for this?

Thanks!

Allow static methods to be called and inherited the same way variables are

The problem:
At the moment we can use public methods in the controllers which are then translated into variables to be used in blade templates.

These variables can be inherited from parent controllers using the Tree interface, or inherited from the App controller

Static methods, however, are always tied to the Controller class and cannot be inherited, so they always need to be called from the templates referencing the Controller itself

In an example: we cannot use methods from specific controllers in templates which are shared between multiple contexts
lets say an entry-meta.blade.php which is loaded in Singular context and Home context always has to use App::method() and never Home::method() or Singular::method()

The use case:
Imagine an entry-meta.blade.php which prints article categories

<div class="entry-meta">
    @foreach(App::categories() as $cat)
      {{ $cat }}
    @endforeach
</div>

Then for our use case, we want to print only a single category on the homepage, but list all categories in the article detail, so effectively we want to slice the array of categories for Singular context
At this moment we have two ways to achieve this:

  1. Use two template partials: entry-meta.blade.php and entry-meta-singular.blade.php - One would call App::categories() while the later would call Singular::categories() - this effectively duplicates our template partials
  2. Create this logic inside the App::categories() where we would add exceptions when is_singular() is true - which sort of goes against the controller design in itself, especially when the logic becomes more specific (Home context, Category context, page context, post context)

Proposed solution:
Have the static methods added to blade compiler as directives.
This, however, should be noted in the readme as well, because someone could define a static method foreach or something else from the default blade directives effectively overriding its function

Possibly a list of default blade directives should be checked against the method names and an exception should be thrown in that case

There is one more problem with the directives and that is the blade template cache.
So if I were to implement a method on the App class, call it from a template, it will get cached and the method would always be called from the App class until something in the template is changed. Even if I then define the same method on a more specific controller. There could be a solution using some sort of Middleware which would be called from the cached template and would then call the registeted method, however I am not sure if this is not an overkill for what I am trying to accomplish. Any thoughts on this?

I will submit a PR in a bit with the proposed solution, so lets have a look if we can think of something better? :)

Passing multiple variables from controller function to view

Firstly, thank you SO much for your work on the controller project. It's taking me a little bit to get to grips with it all but slowly getting there!

To help get up to speed with Blade in general, I've been watching the Laracast videos, specifically Laravel 5 Fundamentals. In the video Passing Data to Your Views (https://laracasts.com/series/laravel-5-fundamentals/episodes/4), passing multiple variables within a single function is discussed. I've been trying to decide what the best practice is here but the methods outlined in the video don't seem to work with Sage 9. Is this something to do with the particular implementation of Blade or am I being a super noob?

Before watching this video, this was my methodology:

resources/controllers/Single.php

public function fields()
{
    $images = get_field('image');
    $description = get_field('description');
    $data = [
        'images' => $images,
        'description' => $description
    ];

    return $data;
}

resources/view/contact.blade.php

<ul>
    @foreach($fields['images'] as $image)
        <li><img src="{{$image['sizes']['thumbnail']}}" alt="{{$image['alt']}}"></li>
    @endforeach
</ul>

<p>{!! $fields['description'] !!}

This works fine but is a bit more verbose than the implementation within the Laracast videos and also requires manually building an array of all of the required variables. In the videos, they pass variables to the view function within the controller, which are then passed to the view:

Controller:

public function about()
{
    $first = 'Fox';
    $last = 'Mulder';

    return view('pages.about', compact('first', 'last'))
}

or:

public function about()
{
    data = [];
    $data['first'] = 'Fox';
    $data['last'] = 'Mulder';

    return view('pages.about', $data)
}

View
<h1>About Me {{ $first }} {{ $last }}</h1>

Can we do something similar or is there even a better way for the Sage 9 implementation? I guess the other option is to build many different functions within the controller but then the tradeoff seems to be that the view are cleaner but the controller much more verbose.

Naming with underscores

Sorry if this issue already exists. The only similar one I was able to find was #20.

Problem

Controller loading doesn't occur with custom post types using underscores.
Example: resource_collection

Details

I have a custom post type of resource_collection. It's relevant files include:

  • view resources/views/partials/content-single-resource_collection.blade.php
  • controller app/controllers/SingleResourceCollection.php
    <?php
    namespace App;
    use Sober\Controller\Controller;
    
    class SingleResourceCollection extends Controller
    {
    . . . 
    

Hierarchy Debugger:

controllers/app.php
controllers/index.php
controllers/singular.php
controllers/single.php
controllers/single-resource_collection.php

Thanks for any help/clarification!

Use __construct() to add_action()

Hello !

First of all, really nice Job on this together with Sage ! We finally have the "VC" of "MVC" in Wordpress !
I am trying to add_fonction() from my controllers. I thought the best way doing this was to use the __constructor() method.
But unfortunatly, the Controller is instanciated multiple time (in my case taxonomy-product_cat for Woocommerce), and so the action is added multiple time wich is not good.

I found a way to prevent this, but I don't think that this is a good way, more of a "tweak".

class TaxonomyProductCat extends Controller
{
    private static $trigger = 0;

    public function __construct()
    {
       /* if (!self::$trigger) {
            $this->add_product_content_data();
            //add_action('woocommerce_after_shop_loop_item_title', [$this, 'add_actions_filters'], 9);
            self::$trigger++;
        }*/
    }

    public function add_actions_filters()
    {
        if (!self::$trigger) {
            add_action('woocommerce_after_shop_loop_item_title', function() {
                echo('<p>oks</p>');
            }, 9);
            self::$trigger++;
        }
    }

    public function term()
    {
        return get_term_by('slug', get_query_var('term'), get_query_var('taxonomy'));
    }
}

As you can see, I tried first putting the add_action() into the __constructor method. with a callback [$this, 'add_product_content_data'] to call a controller method that do a "echo()". But this was not working as the controller is used to populate variables to be binded to the view, and so was directly "echoing" on top of the site because, well there is a "echo" and i dont return nothing.

So i moved the add_action to a method that is triggered once, even if controller is instanciated multiple time. And as all controller methods are called to bind data to the view, this work.

Is there a better way to do this ?

Thanks !

Custom Template Controller

Hi!

TL;DR
By the way WordPress saves custom page template path and how Sage expands it into possible template files one cannot create Controller based on page template file name.

Current behavior
Let's say we have a custom page template located in views/template-custom.blade.php. The following is available controller hierarchy:

Hierarchy Debugger:
/controllers/app.php
/controllers/index.php
/controllers/resources/views/singular.php
/controllers/singular.php
/controllers/views/singular.php
/controllers/resources/views/page.php
/controllers/page.php
/controllers/views/page.php
/controllers/resources/views/page-4.php
/controllers/page-4.php
/controllers/views/page-4.php
/controllers/resources/views/page-signup.php
/controllers/page-signup.php
/controllers/views/page-signup.php

Expected behavior

Controller hierarchy should include /controllers/template-custom.php and /controllers/views/template-custom.php.

Details
Let's get back to our custom template located inviews/template-custom.blade.php. WordPress saves it's exact path and serves as template name. Then Sage's template_hierarchy filter expands it into following locations :

resources/views/views/template-custom.blade.php
resources/views/views/template-custom.blade.blade.php
views/template-custom.blade.php
views/template-custom.blade.blade.php
views/views/template-custom.blade.php
views/views/template-custom.blade.blade.php

I know, it looks broken but it does it's job (the list includes original template path). I'm not sure if this should be 'fixed' by Sage or bypassed by controller.

WP_ajax

Hello !

I would like to know if there's a way to use SoberWP controllers with WP_ajax ?
I tried to put the add_action into my controller __construct, but as it's an Ajax call, the constructor is never called and so the action never triggered...

Any way we could handle it ?
Thanks !

App\sage not defined when deploying using Trellis

I'm deploying using Trellis, and since Controller is a mu-plugin, I'm guessing that it gets enabled before Sage is enabled and as such is throwing a fatal error during a trellis deploy process, thereby exiting the deploy.

PHP Fatal error: Uncaught Error: Call to undefined function App\\sage() in /srv/www/viewfind.com/releases/20170228183833/web/app/mu-plugins/controller/controller.php:46

Can we check that the namespace exists before calling the function?

App controller methods are being called multiple times

These tests are performed on a homepage

I have the following structure:

app/controllers/App.php
app/controllers/Home.php

...
class App extends Controller {
    public function app_test()
    {
         error_log('called App::test');
    }
}
...
class Home extends Controller {
    public function home_test()
    {
         error_log('called Home::test');
    }
}

the result of the error log for a single request is:

called App::test
called App::test
called Home::test
called App::test

So far I have been debugging I found out the following:
\Sober\Controller\loader function adds filters for
sage/template/app-data/data (App controller)
sage/template/home-data/data (Home controller)

Sage's template_include filter then runs the above filters (it actually calls several other based on the body classes)

the filter then creates a new controller for each of the filters it added, in our case it can be translated as

    $controller = new App\Controllers\App(); // First instance of App being created
    $controller->__setup();
    return array_merge($loader->getAppData(), $loader->getPostData(), $controller->__setTreeData($data), $controller->__getData());

and

    $controller = new App\Controllers\Home(); // First instance of Home being created
    $controller->__setup();
    return array_merge($loader->getAppData(), $loader->getPostData(), $controller->__setTreeData($data), $controller->__getData());

So to clarify: We call the __setup method on the controller once for App and then once for Home.

The problem is in the array_merge when $loader calls getAppData which in turn calls __setup on App again

This results in the following calls:
__setup from the sage/template/app-data/data filter on App class (first App instance)
__setup from getAppData on new $this->instances['app']() from sage/template/app-data/data filter (second instance of App being created)
__setup from the sage/template/home-data/data filter on Home class (first instance of Home)
__setup from getAppData on new $this->instances['app']() from filter sage/template/home-data/data (third instance of App)

So I have a solution to migrate the controllers to singletons (not sure if this is viable as we would need protected contructors for a clean design and this might break already existing solutions based on the current controller pattern) - this could also make it harder for dependency injection if it was to be implemented later on

So if anyone has a better idea please share.

I will submit a PR for this in a bit in case nobody comes up with a better solution

Switching to 9.0.0-beta4 and back to dev-master break Sage integration

Hey !

I just tried to update the package to 9.0.0-beta4, and it broke the installation.
So i switched back to dev-master, and it didn't fixed the issue.

I add to add in my function.php (or included, filters.php for Sage)

add_filter('sober/controller/path', function () {
    return dirname(get_stylesheet_directory()) . '/resources/controllers';
});

again to match Sage 9 Beta Controller location.

Thanks !

@debug directives print in plain text

@debug('dump')
@debug('hierarchy')
@debug('controller')

Each line in my view outputs in plain text on the page. I am running Sage 9.

Am I missing any instructions other than installing this package in my sage theme directory via Composer?

Please let me know if I can provide any more information that may be helpful, thanks.

Unable to get variable in blade template

Sorry for another message! I tried recreating the single post images example verbatim for the single controller and blade template (including creating an ACF images field). However, when I go to the single post, it says Undefined variable: images.

When I include @controlleron the blade template it outputs the exact same text @controller

When I include @debugon the blade template it outputs controller debugger: and that's it.

I'm on the latest release and php7.0.15

Any thoughts on how I can troubleshoot this or why my class method is not converting into a variable?

Base controller issues

The base controller doesn't work without another matching controller for the template being loaded.

If I just have a base.php controller then the variables are not available to the page.blade.php template or even the base.blade.php template. However, if I create a page.php controller with a dummy function, the base controller variables become available.

Other than that things seem to be working great!

archive templates

i am trying to make the blade vie tpl files as easy to use as possible for designers. I really like the way that the controller allows us to use a variable to call a function, and trait work really well for partials. however i could do with a bit of guidance on how to use the archive comtrollers/views, like archive.php or even archive-news_article.php or even index.php.i

so far i have this -

src/controllers/archive.php

public function posts(){
    global $posts;
    $posts2 = null;
    $x = 0;
    foreach ($posts as $p){
        $post_excerpt = substr(strip_tags($p->post_content, '<b><div><p><i>'), 0, 250);
        $post_excerpt .= '<a href="' . get_permalink($p) . '">' . '...read more</a>';
        $p->post_excerpt = $post_excerpt;
        $posts2[$x] = (array) $p;
        $x++;
    }
    return (array) $posts2;
}

archive.blade.php

@foreach($posts as $post)
@include ('partials.content-'.($post->post_type !== 'post' ? $post->post_type : get_post_format()), $post)
@Endforeach

i am passing the $post value to the include partial statement

in content-program.blade.php to get the custom excerpt, i have to use

{!! $post['post_excerpt'] !!}

i would like to use

{!! $post_excerpt !!}

how can i do this with a function post_excerpt to the variable returns each post excerpt in a loop for the partial template?

thanks

Custom template controller issues.

I've been running into issues with custom templates. Whether I am relying on naming the controller the same or setting the template property, the controller fails to send data to the view.

However, the standard page controller does send it's data.

Thanks for any help you can provide!

templates/faq.blade.php

{{--
  Template Name: Frequently Asked Questions
--}}

@extends('layouts.base')

@section('content')
  @while(have_posts()) @php(the_post())
  @include('partials.page-header')
  @include('partials.content-page')
  @endwhile
  {{ $faq or 'No $faq variable returned' }}<br/>
  {{ $page or 'No $page variable returned' }}
@endsection

controllers/faq.php

<?php
namespace App;
use Sober\Controller\Controller;

class Faq extends Controller
{
    /**
     * Protected methods will not be passed to the template
     */
    protected function hidden()
    {

    }
    public function faq()
    {
        return 'Testing FAQ Controller';
    }
}

controllers/page.php

<?php
namespace App;
use Sober\Controller\Controller;

class Page extends Controller
{
    /**
     * Protected methods will not be passed to the template
     */
    protected function hidden()
    {

    }
    public function page()
    {
        return 'Testing Page Controller';
    }
}

Outputs

No $faq variable returned
Testing Page Controller

Cannot redeclare Sober\Controller\debugger()

It looks like since the update a few hours ago, you setup autoload in composer.json to autoload the plugin, but are still declaring "type": "wordpress-muplugin" thus the plugin is installing into /mu-plugins/ and being loaded by WordPress as well as Composer resulting in an error.

I can see how this could be overlooked as Sage 9 doesn't ship with installer-paths set in composer.json like it does Bedrock, but if they are manually set at a theme-level it will result in the error above.

Thanks in advance for a quick fix.

@debug('dump') style

How do you look at adding styles to debug('dump') and making it look something like this?

img 2017-07-01 10 42 12

In this form, the information is more readable ...

Uncaught ReflectionException after composer update

After running a composer update on my root sage theme

composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 2 installs, 16 updates, 1 removal
  - Removing paragonie/random_compat (v2.0.10)
  - Updating symfony/yaml (v3.3.6 => v3.3.10) Loading from cache
  - Removing soberwp/controller (9.0.0-beta.4)
  - Installing soberwp/controller (dev-master 93aa3cc) Cloning 93aa3ccd86 from cache
  - Updating symfony/polyfill-mbstring (v1.5.0 => v1.6.0) Loading from cache
  - Updating symfony/translation (v3.3.6 => v3.3.10) Loading from cache
  - Installing psr/simple-cache (1.0.0) Loading from cache
  - Installing psr/container (1.0.0) Loading from cache
  - Updating illuminate/contracts (v5.4.27 => v5.5.17) Loading from cache
  - Updating illuminate/support (v5.4.27 => v5.5.17) Loading from cache
  - Updating illuminate/config (v5.4.27 => v5.5.17) Loading from cache
  - Updating symfony/debug (v3.3.6 => v3.3.10) Loading from cache
  - Updating symfony/finder (v3.3.6 => v3.3.10) Loading from cache
  - Updating illuminate/filesystem (v5.4.27 => v5.5.17) Loading from cache
  - Updating illuminate/container (v5.4.27 => v5.5.17) Loading from cache
  - Updating illuminate/events (v5.4.27 => v5.5.17) Loading from cache
  - Updating illuminate/view (v5.4.27 => v5.5.17) Loading from cache
  - Updating symfony/console (v3.3.6 => v3.3.10) Loading from cache
  - Updating illuminate/console (v5.4.27 => v5.5.17) Loading from cache
  - Updating symfony/process (v3.3.6 => v3.3.10) Loading from cache
Generating autoload files

The entire theme stopped working. In the error log it is output this error

[Mon Oct 30 16:05:49.409392 2017] [:error] [pid 1366] [client 172.17.0.1:43296] PHP Fatal error:  Uncaught ReflectionException: Class App\\Controllers\\template-home does not exist in /app/wp-content/themes/asdf/vendor/soberwp/controller/controller.php:19\nStack trace:\n#0 /app/wp-content/themes/asdf/vendor/soberwp/controller/controller.php(19): ReflectionClass->__construct('App\\\\Controllers...')\n#1 /app/wp/wp-includes/class-wp-hook.php(298): Sober\\Controller\\loader('')\n#2 /app/wp/wp-includes/class-wp-hook.php(323): WP_Hook->apply_filters(NULL, Array)\n#3 /app/wp/wp-includes/plugin.php(453): WP_Hook->do_action(Array)\n#4 /app/wp/wp-settings.php(448): do_action('init')\n#5 /app/wp-config.php(125): require_once('/app/wp/wp-sett...')\n#6 /app/wp/wp-load.php(42): require_once('/app/wp-config....')\n#7 /app/wp/wp-blog-header.php(13): require_once('/app/wp/wp-load...')\n#8 /app/index.php(4): require('/app/wp/wp-blog...')\n#9 {main}\n  thrown in /app/wp-content/themes/asdf/vendor/soberwp/controller/controller.php on line 19, referer: http://localhost:3000/about-us/

Any idea what's causing this?

[doc] enqueue?

For a sage9 based theme, does it make sense to enqueue script/style for a particular page in controller?

Cannot import controller classes after last update

After the last update on master, while using the Sage9 WordPress Theme, the App class is not loaded properly.

After reverting our composer.json wpsober/controller depedency to tag 9.0.0-beta.4, this proble does not occur.

Only variables should be passed by reference in ~/Code/Sites/purewater/web/app/mu-plugins/controller/src/Loader/Controller.php on line 46

I'm receiving the error with a basic test.

templates/page.blade.php

@extends('layouts.base')
@section('content')
  @while(have_posts()) @php(the_post())
  @include('partials.page-header')
  @include('partials.content-page')
  @endwhile
  {{$test}}
@endsection

controllers/page.php

<?php

namespace App;

use Sober\Controller\Controller;

class Page extends Controller
{
    /**
     * Protected methods will not be passed to the template
     */
    protected function hidden()
    {

    }

    /**
     * Return test data
     *
     * @return array
     */
    public function test()
    {
        return 'Testing';
    }
}

Everything else is setup via defaults.

Improvment Request for declaring variables

T'would be nice if all data fell under one blanket function like _data() and you did all your variable declarations there. Having to do individual (non-static) functions just to declare variables is tedious. It is also confusing when you start mixing them with static functions.

I would like to see something like this within a controller:

public function _data() {
    
    $item = [
       // get some data from external class
    ];
    $title = $this->transform( get_the title() );
    $another_var = function() {
        // do some more stuff here
   }

  return compact( 'item', 'title', 'another_var');
}

Now you have a very clear, simple, and easier to read function for your variables. Using functions just to declare variables is counter-intuitive. A lot of people are getting hung up on this (I know I did).

Non-Sage usage?

Hi, any interest in making Controller compatible with this blade plugin? I have setup a fresh theme with bladerunner and laravel-mix, and was hoping controller would work too :)

https://github.com/ekandreas/bladerunner

edit: using bedrock/trellis still, just not sage

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.