Leaderboard
Popular Content
Showing content with the highest reputation on 04/07/2024 in all areas
-
3 points
-
Customized templates and fields Each and every content type only has the fields it really needs. Books, companies, recipes - it doesn't matter what kind of data my clients or I have to deal with. The templates and fields will reflect that. Therefore clients don't even have to learn anything in regards to creating or editing data. Super easy. It's typesafe (by my definition) We can discuss the meaning of 'typesafe' here but... I think ProcessWire is somewhat typesafe because I define each field, template, relationship, and almost everything else. I know where to expect what kind of data and know what data is allowed in which field. No guessing, no errors. (Sure this depends on your setup and your will to invest some time.) Works perfectly fine for non-developers I won't call myself a coder or programmer - I just tinker around with code and have fun. When I started using ProcessWire, getting around was super easy, and learning the fundamentals took only a day or two. From there on, it was easy-going. It's impressive what you can achieve with only some if/foreach/echo in PHP/ProcessWire. I said it a few years back and still stand behind it: ProcessWire seems to be the easiest way to learn and work with PHP. Low maintenance There are ProcessWire projects of mine that haven't been updated in the last 5+ years and still work without any PHP or security issues. The moment a project is finished and works without flaws it will do so for a very long time. There is no real need to update a project. Small footprint, high performance A ProcessWire website doesn't need that much of a big hosting package. The moment you start using Core cache functionalities or even ProCache most websites are fine and ready for an average amount of traffic. Maybe not ready for a slashdot/reddit/ProductHunt-peak but that's a totally different story. I can get so much out of ProcessWire compared to WordPress (and others I used/tested in the past). ZIP downloads and no real need for a package manager What I really love and enjoy is that you can get everything as a ZIP file, unpack those, move them around and do whatever you want or need with them. Not needing NPM or composer to get started - like in the good old days - is just perfect. In the last 1-2 years I did a lot with NPM due to 11ty and Astro, yet an old-school ZIP file has its very own charme. For comparison: Installing CraftCMS feels good and really nice, yet I absolute don't know what's happening, what is needed, and so on. It's like a blackbox. It works but I don't know why. I hate that.3 points
-
2 points
-
Looks like the next level of Business Email Compromise just became unlocked (if it wasn't already.) Lutra Security have a nice write-up on the attack they are calling "Kobold Letters". Basically, email clients change the DOM of the email when they forward it, allowing different CSS to apply between the first recipient viewing an email, and subsequent recipients. Allows an innocent-looking "request to forward to the CFO" phishing email to the CEO to become a "request to send funds/data" when received by the CFO from the CEO. Explict verification of the request contents needed now, not just a "Did you send me a message?" question which only verifies that the message was forwarded. Something to be aware of if you work in a team or are responsible for any kind of staff training on phishing etc.1 point
-
This tutorial is about making the Latte template engine available in ProcessWire template files via the use of ProcessWires Custom Page Classes. Based on some inspiring posts from @bernhard, I wanted to use custom page classes and Latte templates in my own projects. I know there are modules like RockFrontend and others available to integrate template engines like Latte or Twig . However I wanted to start with a small, flexible and reusable code base as playground for my next projects without module dependencies as starting point. Please note: The template part of this tutorial assumes you are using the Site profile Default profile (standard/intermediate edition), which can be downloaded from the ProcessWire Github repository. Here a technique called delayed output strategy is used. I also posted an alternative Latte implementation some posts below, using a normal class file for implementing Latte via your template _init.php file. Step 1: Enable ProcessWire Custom Page Classes PageClasses were added with ProcessWire 3.0.152. To use page classes open site/config.php and enable the feature if needed via $config->usePageClasses = true;. After that create the folder site/classes in your site installation and add the PHP file DefaultPage.php inside with the following content for now. <?php namespace ProcessWire; class DefaultPage extends Page {} The DefaultPage class is used whenever a ProcessWire template like site/templates/your-template.php has no page class associated with it. In other words, if no site/classes/YourTemplatePage.php exists, the default page class site/classes/DefaultPage.php is used as fallback. Step 2: Install PHP Dependency Manager Composer As we are using the Latte Composer package, we first need to install Composer on our computer if not yet available. Visit the Composer webiste and install Composer on your system. On Windows just grab the Composer-Setup.exe file and execute it. Once Composer is installed, open a new terminal and type the command composer. You should see some Composer output in your console. If so, proceed with Step 3. If an error occurs, please read and follow the Docs on the Composer website to get Composer installed on your system before proceeding with this tutorial. Step 3: Install Latte Composer Package In the next step, we install the Latte template engine files as Composer package in our site folder. Open a terminal and switch into your local site/classes folder created in Step 1. From inside the site/classes folder type the following command into your terminal composer require latte/latte. Please note: If your installation has a composer.json file in the root, you will get asked if you want to use the composer.json in the root. As this tutorial assumes to install the composer files inside our site/classes folder, you MUST answer no. Otherwise the Latte files will be installed inside /root/vendor not /root/site/classes/vendor as expected in this tutorial. Once done, your site classes folder should contain a vendor folder with the Latte composer files, the two Composer files composer.json and composer.lock and our DefaultPage.php file created in Step 1. site/ classes/ vendor/ bin/ composer/ latte/ autoload.php composer.json composer.lock DefaultPage.php (implements Latte logic inherited by other PageClasses) EventsPage.php (implements logic for /templates/events.php) // Note this part is setup and explained later in this tutorial templates/ views/ events.latte your-template.php (associated with fallback classes/DefaultPage.php) events.php (associated with classes/EventsPage.php) Please note: The files located under site/templates are explained later in this tutorial. I just thought it would be a good idea to show the relevant file structure at one spot. Step 4: Make Latte available from PageClasses Now we need to make Latte available in our custom PageClasses. Open site/classes/DefaultPage.php and change the code as follows: <?php namespace ProcessWire; /** * The DefaultPage class implements methods to render Latte templates as string. This page class serves as * fallback for PW templates inside site/templates not implementing their own page class inside site/classes. */ class DefaultPage extends Page { protected static \Latte\Engine|null $latte = null; private array $latteConfig = []; // Constructor. public function __construct(Template $tpl = null) { parent::__construct($tpl); $this->setupLatteEngine(); $this->setLatteConfig(); } // Set or update Latte configuration. public function setLatteConfig(array $config = []): void { if (!isset(self::$latte)) return; // Remove keys from user config not available in Latte defaults, except for 'pwAPI'. $config = array_intersect_key($config, $this->getLatteDefaultConfig()); // Merge user config with Latte defaults. $this->latteConfig = array_merge($this->getLatteDefaultConfig(), $config); // Apply updated configuration to actual Latte instance. self::$latte->setAutoRefresh($this->latteConfig['autoRefresh']); self::$latte->setTempDirectory($this->latteConfig['cacheFolder']); } // Render given Latte template as string, injecting ProcessWire API and $data. public function renderTemplate(string $template, array $data = []): string { if (!isset(self::$latte) || !$this->latteConfig) return ''; // Ensure Latte template exists within specified template folder. $latteTemplateFolder = realpath($this->latteConfig['latteTemplateFolder']); $templatePath = realpath($latteTemplateFolder . '/' . $template); if ($templatePath === false || stripos($templatePath, $latteTemplateFolder) !== 0) { throw new \Exception("Latte template '$template' not found or outside 'latteTemplateFolder'."); } // Render Latte template and inject ProcessWire API and $data. return self::$latte->renderToString($templatePath, array_merge($data, $this->latteConfig['pwAPI'])); } // Returns associative array with Latte default configuration. protected function getLatteDefaultConfig(): array { return [ 'autoRefresh' => true, 'cacheFolder' => $this->wire('config')->paths->cache . 'Latte/', 'latteTemplateFolder' => $this->wire('config')->paths->templates, 'pwAPI' => [ 'page' => $this, 'pages' => $this->wire('pages'), 'config' => $this->wire('config'), ], ]; } // Initiate Latte template engine. private function setupLatteEngine(): void { if (isset(self::$latte)) return; require_once "vendor/autoload.php"; self::$latte = new \Latte\Engine; } } The DefaultPage class assumes the Latte template files to be stored inside path site/templates/. By default we can access the PW-API $page, $pages and $config inside our Latte templates. You can add more ProcessWire APIs like $sanitizer or template specific data via the setLatteConfig() method or via the optional associative array $data of the renderTemplate() method. Assume we have another PageClass in site/classes/EventsPage.php, which implements the complex method hello(). To make the Latte render methods available in the EventsPage class, we need to extend from our DefaultPage class instead of the ProcessWire Page class. This way we can create as many page classes with logic for specific templates as needed, while keeping code structured and organized. <?php namespace ProcessWire; class EventsPage extends DefaultPage { public function hello() { return "Hello World!"; } } Step 5: Add Latte template (acting as View) Next we add a Latte template file to site/templates/views/events.latte with the following content. <div> <h2>{$page->title|capitalize}</h2> <p>PageId: {$page->id}</p> <p n:if="$config->useFunctionsAPI"> Using Functions API and Latte is fun. </p> {* This will be translated based on the default PW language or users language preference *} <p>{$lang['Please select a date']}</p> <ul n:if="$page"> <li n:foreach="$page->getFields() as $field"> $page->{$field}: {$page->$field} </li> </ul> </div> Step 6: Render Latte template from ProcessWire templates (acting as Controller) The code below shows how custom methods and the Latte render method can be invoked within normal ProcessWire templates like site/templates/events.php. The first code line appends the output from the method hello() implemented in the associated PageClass site/classes/EventsPage.php to our template $output variable. Please note: In this example the ProcessWire template file uses a technique called Delayed Output Strategy. You can read more about this strategy in the linked ProcessWire blog post from Ryan. <?php namespace ProcessWire; /** * Template: "events.php" * Using Processwire delayed output strategy * https://processwire.com/docs/tutorials/how-to-structure-your-template-files/ */ // Append output from method hello() implemented in `site/classes/EventPage.php`. $content .= $page->hello(); // Add needed translations here. You can access them via $lang inside your Latte template. // The translation for 'Please select a date' can be added via the ProcessWire backend. // For details see https://processwire.com/docs/multi-language-support/code-i18n/. $data = ['lang' => [ 'Please select a date' => __('Please select a date!'), ], ]; // Append output of rendered Latte template located in `site/templates/views/events.latte`. $content .= $page->renderTemplate('views/events.latte', $data); At the bottom of our template file site/templates/events.php we call the render method implemented in site/classes/DefaultPage.php to render the specified Latte template in site/templates/views/events.latte. The ProcessWire API $page, $pages, $config is available in all Latte templates by default. As the EventsPage class extends the DefaultPage class, it inherents it's render methods This way we need to implement the Latte template code once, but can use it in all our custom PageClasses and default ProcessWire template files located in /site/templates. Note: If you are using the output strategy Markup regions, the Events template file would look as follows: <?php namespace ProcessWire; /** * Template: "events.php" * Using Processwire delayed output strategy * https://processwire.com/docs/tutorials/how-to-structure-your-template-files/ */ // Append output from method hello() implemented in `site/classes/EventPage.php`. // Add needed translations here. You can access them via $lang inside your Latte template. // The translation for 'Please select a date' can be added via the ProcessWire backend. // For details see https://processwire.com/docs/multi-language-support/code-i18n/. $data = [ 'lang' => [ 'Please select a date' => __('Please select a date!'), ], ]; ?> <div id="content"> <?= $page->hello(); ?> <?= $page->renderTemplate('views/events.latte', $data); ?> </div> Have fun. cwsoft Please note: Edited the initial post to include the code suggestions from member @d'Hinnisdaël some posts below. Thanks for your suggestions.1 point