Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 07/08/2019 in all areas

  1. We had the opportunity and pleasure to create a multi-site with ProcessWire. The Walter Group consists of four investment units, each with its own domain name(s). Thus, six domain names with two different language negotiation strategies had to be managed by a single installation. The four sites more or less share news, staff and other information. waltergroup.ca (in English) and groupewalter.ca (in French) walterfinancial.ca (in English) and financierewalter.ca (in French) waltercapital.ca/en and /fr walter-gam.com/en and /fr The Multisite module was designed to meet the challenge. A tree structure has been created with the four units, with news and management staff pages placed outside these sites so that they can be more easily managed by Walter Group. We also used FormBuilder for the four contact forms whose entries had to be directed to different people. The result really pleased the Walter group, long used to complicated CMS!
    11 points
  2. Version 3.0.135 of ProcessWire on the dev branch focuses on adding additional layers of security via .htaccess updates, adds clarity to debug mode, and improves upon the installer— https://processwire.com/blog/posts/pw-3.0.135/
    2 points
  3. I've been doing a little rejigging of our default htaccess file after yesterday's dev release, and trying to understand Section 18 a bit better too... In section 18 we use a rule based on what is outlined here: https://processwire.com/blog/posts/optimizing-404s-in-processwire/ RewriteCond %{REQUEST_URI} !\.(jpg|jpeg|gif|png|ico|webp|svg|php|cgi|pl|asp|rar|zip)$ [NC] This is entered after the existing section 18 rules, which are left commented out. After the end of ProcessWire's htaccess rules we have: <FilesMatch "\.(jpg|jpeg|gif|png|ico|webp|svg|php|cgi|pl|asp|rar|zip)$"> ErrorDocument 404 "The requested file was not found. </FilesMatch> Without that rule, I get the ProcessWire 404 page when accessing a non-existent file matching one of those types. On a different htaccess-related note, I recommend the 6G htaccess Firewall https://perishablepress.com/6g/. We have this at the start of our default .htaccess file, followed by: ErrorDocument 403 "Sorry, you are not permitted to access this resource. The only issue I've come across after a few years of use is with the autocomplete Page field, when using OR selectors (e.g. template=home|default). I wrote this hook as a remedy: <?php // Replace pipes (|) with %7C in PageAutocomplete data-url attribute // This gets around 6G htaccess rules which disallows pipes in urls $wire->addHookAfter("InputfieldPageAutocomplete::render", function(HookEvent $event) { $out = $event->return; if(strpos($out, "data-url") === false) return; $url = explode("'", ltrim(explode("data-url=", $out)[1], "'"))[0]; $event->return = str_replace($url, str_replace(" ", "+", str_replace("|", "%7C", $url)), $out); }); Cheers, Chris
    2 points
  4. Hi everyone, Here's a new module that I have been meaning to build for a long time. http://modules.processwire.com/modules/process-admin-actions/ https://github.com/adrianbj/ProcessAdminActions What does it do? Do you have a bunch of admin snippets laying around, or do you recreate from them from scratch every time you need them, or do you try to find where you saw them in the forums, or on the ProcessWire Recipes site? Admin Actions lets you quickly create actions in the admin that you can use over and over and even make available to your site editors (permissions for each action are assigned to roles separately so you have full control over who has access to which actions). Included Actions It comes bundled with several actions and I will be adding more over time (and hopefully I'll get some PRs from you guys too). You can browse and sort and if you have @tpr's Admin on Steroid's datatables filter feature, you can even filter based on the content of all columns. The headliner action included with the module is: PageTable To RepeaterMatrix which fully converts an existing (and populated) PageTable field to either a Repeater or RepeaterMatrix field. This is a huge timesaver if you have an existing site that makes heavy use of PageTable fields and you would like to give the clients the improved interface of RepeaterMatrix. Copy Content To Other Field This action copies the content from one field to another field on all pages that use the selected template. Copy Field Content To Other Page Copies the content from a field on one page to the same field on another page. Copy Repeater Items To Other Page Add the items from a Repeater field on one page to the same field on another page. Copy Table Field Rows To Other Page Add the rows from a Table field on one page to the same field on another page. Create Users Batcher Allows you to batch create users. This module requires the Email New User module and it should be configured to generate a password automatically. Delete Unused Fields Deletes fields that are not used by any templates. Delete Unused Templates Deletes templates that are not used by any pages. Email Batcher Lets you email multiple addresses at once. Field Set Or Search And Replace Set field values, or search and replace text in field values from a filtered selection of pages and fields. FTP Files to Page Add files/images from a folder to a selected page. Page Active Languages Batcher Lets you enable or disable active status of multiple languages on multiple pages at once. Page Manipulator Uses an InputfieldSelector to query pages and then allows batch actions on the matched pages. Page Table To Repeater Matrix Fully converts an existing (and populated) PageTable field to either a Repeater or RepeaterMatrix field. Template Fields Batcher Lets you add or remove multiple fields from multiple templates at once. Template Roles Batcher Lets you add or remove access permissions, for multiple roles and multiple templates at once. User Roles Permissions Batcher Lets you add or remove permissions for multiple roles, or roles for multiple users at once. Creating a New Action If you create a new action that you think others would find useful, please add it to the actions subfolder of this module and submit a PR. If you think it is only useful for you, place it in /site/templates/AdminActions/ so that it doesn't get lost on module updates. A new action file can be as simple as this: <?php namespace ProcessWire; class UnpublishAboutPage extends ProcessAdminActions { protected function executeAction() { $p = $this->pages->get('/about/'); $p->addStatus(Page::statusUnpublished); $p->save(); return true; } } Each action: class must extend "ProcessAdminActions" and the filename must match the class name and end in ".action.php" like: UnpublishAboutPage.action.php the action method must be: executeAction() As you can see there are only a few lines needed to wrap the actual API call, so it's really worth the small extra effort to make an action. Obviously that example action is not very useful. Here is another more useful one that is included with the module. It includes $description, $notes, and $author variables which are used in the module table selector interface. It also makes use of the defineOptions() method which builds the input fields used to gather the required options before running the action. <?php namespace ProcessWire; class DeleteUnusedFields extends ProcessAdminActions { protected $description = 'Deletes fields that are not used by any templates.'; protected $notes = 'Shows a list of unused fields with checkboxes to select those to delete.'; protected $author = 'Adrian Jones'; protected $authorLinks = array( 'pwforum' => '985-adrian', 'pwdirectory' => 'adrian-jones', 'github' => 'adrianbj', ); protected function defineOptions() { $fieldOptions = array(); foreach($this->fields as $field) { if ($field->flags & Field::flagSystem || $field->flags & Field::flagPermanent) continue; if(count($field->getFieldgroups()) === 0) $fieldOptions[$field->id] = $field->label ? $field->label . ' (' . $field->name . ')' : $field->name; } return array( array( 'name' => 'fields', 'label' => 'Fields', 'description' => 'Select the fields you want to delete', 'notes' => 'Note that all fields listed are not used by any templates and should therefore be safe to delete', 'type' => 'checkboxes', 'options' => $fieldOptions, 'required' => true ) ); } protected function executeAction($options) { $count = 0; foreach($options['fields'] as $field) { $f = $this->fields->get($field); $this->fields->delete($f); $count++; } $this->successMessage = $count . ' field' . _n('', 's', $count) . ' ' . _n('was', 'were', $count) . ' successfully deleted'; return true; } } This defineOptions() method builds input fields that look like this: Finally we use $options array in the executeAction() method to get the values entered into those options fields to run the API script to remove the checked fields. There is one additional method that I didn't outline called: checkRequirements() - you can see it in action in the PageTableToRepeaterMatrix action. You can use this to prevent the action from running if certain requirements are not met. At the end of the executeAction() method you can populate $this->successMessage, or $this->failureMessage which will be returned after the action has finished. Populating options via URL parameters You can also populate the option parameters via URL parameters. You should split multiple values with a “|” character. You can either just pre-populate options: http://mysite.dev/processwire/setup/admin-actions/options?action=TemplateFieldsBatcher&templates=29|56&fields=219&addOrRemove=add or you can execute immediately: http://mysite.dev/processwire/setup/admin-actions/execute?action=TemplateFieldsBatcher&templates=29|56&fields=219&addOrRemove=add Note the “options” vs “execute” as the last path before the parameters. Automatic Backup / Restore Before any action is executed, a full database backup is automatically made. You have a few options to run a restore if needed: Follow the Restore link that is presented after an action completes Use the "Restore" submenu: Setup > Admin Actions > Restore Move the restoredb.php file from the /site/assets/cache/AdminActions/ folder to the root of your site and load in the browser Manually restore using the AdminActionsBackup.sql file in the /site/assets/cache/AdminActions/ folder I think all these features make it very easy to create custom admin data manipulation methods that can be shared with others and executed using a simple interface without needing to build a full Process Module custom interface from scratch. I also hope it will reduce the barriers for new ProcessWire users to create custom admin functionality. Please let me know what you think, especially if you have ideas for improving the interface, or the way actions are defined.
    1 point
  5. Normally in multi-language websites comments are associated to the language of the page where they have been submitted. A couple of weeks ago I realized that PW Comments field is not language sensitive. This results in a discussion in several languages below an article, as blog-post language is not used for comments filtering. In some cases this may be a plus as you can show a broader discussion in multiple language, but if other cases where a tight language consistency is required may become a limitation. ? Enhancing the Comments field to become language sensitive is not really a big deal. ? It would be enough to add a language column in the database table field_comments to store the user language ID. Thanks to this additional column, each comment would be associated with the language ID of the page where it has been submitted. To achieve that I went through a modification of FieldtypeComments. As it took some time to understand the core module, I thought to write a tutorial hoping this may be of help for others in the future. ? Apart the specific purpose of the language field, in principle this could be useful anytime is necessary to add a custom database column (field) to Comments. FieldtypeComments is a core module located in wire/modules/Fieldtype/FieldtypeComments. As usual we will not work directly on core modules as our modification may be overwritten during PW updates. ? We will make a copy of /FieldtypeComments directory with all its content to site/modules/FieldtypeComments. As we want to overwrite the original FieldtypeComments and keep using the module ProcessCommentsManager, we are not going to rename FieldtypeComments, its directory and files. Now we can Login PW Admin panel, select Modules, then Site. Here we press the button Refresh. PW should inform you that FieldtypeComments module is duplicated and you have to choose which one to use. In the alert click on FieldtypeComments, it will open the module settings: Please select to use /site/modules/FieldtypeComments/FieldtypeComments.module, and make sure to press the submit button on the top right. Remain on the same page and click on InputfieldCommentsAdmin. It will open another module settings. Here select to use site/modules/FieldtypeComments/InputfieldCommentsAdmin.module and make sure to press the submit button on the top right. The two modules are now no longer visible under Core Modules but in Site Modules. Now you can test your comments, adding a new one and approving it with ProcessCommentsManager in the Admin panel just to make sure nothing went wrong. If you will need to revert back to the original core module, in Site Modules click on their links. The module settings will open and there you can select the /wire/modules version. OK now it's time to make our code modifications. Inside the directory /site/modules/FieldtypeComments you will find 14 files (3 modules, 7 php, 2 css, 2 js). ? Do not worry! we will modify only 3 files: FieldtypeComments.module, Comment.php and CommentForm.php. ? We start with FieldtypeComments.module, where we will update the database schema. After that the new language ID column can be read/written from/to the database. We will modify two functions: getDatabaseSchema() and ___sleepValue(): public function getDatabaseSchema(Field $field) { ... $schema['ip'] = "varchar(15) NOT NULL default ''"; $schema['user_agent'] = "varchar($maxIndexLength) NOT NULL default ''"; $schema['language'] = "int unsigned NOT NULL"; //>>>>> ADD THIS LINE $schemaVersion = $field->schemaVersion; ... public function ___sleepValue(Page $page, Field $field, $value) { ... $a = array( 'id' => $comment->id, 'status' => $comment->status, 'data' => $comment->text, 'cite' => $comment->cite, 'email' => $comment->email, 'created' => $comment->created, 'created_users_id' => $comment->created_users_id, 'ip' => $comment->ip, 'user_agent' => $comment->user_agent, 'language' => $comment->language, // >>>>> ADD THIS LINE ); Now we will modify Comment.php where we will set the language property modifying __construct() and set() functions: public function __construct() { ... $this->set('downvotes', 0); $this->set('stars', 0); $this->set('language', 0); // >>>>> ADD THIS LINE } public function set($key, $value) { if(in_array($key, array('id', 'parent_id', 'status', 'flags', 'pages_id', 'created', 'created_users_id', 'language'))) $value = (int) $value; // >>>> MODIFY THIS LINE else if($key == 'text') $value = $this->cleanCommentString($value); Now that we should be capable to read/write the language ID from/to the database, we need to make each comment aware of the user language. It is CommentForm.php turn.. where we will modify processInput() function: public function processInput() { ... $comment->parent_id = (int) $data->parent_id; $comment->language = wire()->user->language->id; // >>>> ADD THIS LINE $errors = array();\ ... As in my case I had some test comments, I decided to use PHPMyAdmin to add the language column into table field_comments using SQL. ? If you plan to do the same, please make sure to backup your database before, to avoid surprises.. ? After creating the new column, I manually updated the language ID of the test comments. ALTER TABLE `field_comments' ADD COLUMN `language` int unsigned NOT NULL AFTER `user_agent`; Now select a blog-post you have available in multiple languages and write new comments for each language. If no issue occurred, in the database table field_comments you should see (with PhpMyAdmin ) the new comments with the user language ID in the language column. This sounds great ... ? but still we have an issue. ? If we look at the blog-post comments and we switch the language, we still have in the comments a discussion in multiple languages. ? We will have to filter the page comments to display only the ones corresponding to the user language. This will depend on your theme profile. As in my case I am using Uikit 3 Site/Blog Profile I had to modify _uikit.php function ukComments(): function ukComments(CommentArray $comments, $options = array()) { ... $out = "<ul id='$options[id]' class='uk-comment-list'>"; $language = user()->language->id; // >>>>> ADD THIS LINE foreach($comments as $comment) { //$out .= "<li class='uk-margin'>" . ukComment($comment) . "</li>"; // >>>>> COMMENT OUT ORIGINAL LINE if($comment->language === $language) $out .= "<li class='uk-margin'>" . ukComment($comment) . "</li>"; // >>>>> REPLACE WITH THIS ONE } After this modification only the comments corresponding to the user language will be displayed ! ? Picky ones.. like me.. ? may notice that comments count in the blog-post header are showing the total count for all the language. For my project this is ok, as I am fine with all comments being counted, doesn't matter the language. But in case you want to fix it, that is pretty simple. Still to work on _uikit.php, now on function ukBlogPost(): function ukBlogPost(Page $page, $options = array()) { ... $moreIcon = ukIcon($options['moreIcon']); $categoryIcon = ukIcon($options['categoryIcon']); //$n = $page->get('comments')->count(); // >>>>> COMMENT OUT ORIGINAL LINE $n = $page->get('comments')->find("language=$language")->count(); // >>>>> REPLACE WITH THIS LINE $numComments = $n ? "<a href='$page->url#comments'>" . ukIcon('comments') . " $n</a>" : ""; ... I hope you may find something helpful in this tutorial ! ?
    1 point
  6. Thanks again, @Robin S. I appreciate it!
    1 point
  7. It is very simple. ? The language ID is picked up from the language the user is reading the website. This takes place in CommentForm.php, processInput() modified line: $comment->language = wire()->user->language->id; The comments are picked (filtered) when read by the profile. This takes place in _uikit.php, ukComments() modified lines: $language = user()->language->id; ... if($comment->language === $language) $out .= "<li class='uk-margin'>" . ukComment($comment) . "</li>";
    1 point
  8. Correct ? Technically yes, but I guess you'd have to do a lot of customizations. Just give it a try and please report back your findings!
    1 point
  9. To test the explode() method you would dump its return value (an array):
    1 point
  10. Just have to let at least my words here - the last months sadly i don't had much work with PW - but now i was in need of pdf thumbs....and there are two modules....first one doesn't work. This one runs for me now on shared host, PHP 7.2 and PW 3.101 and i have to say thank you again to Adrian! Even the small not polished modules from you work as a charm over years ? Best regards from a atm sparetime PW user.....(two daughters have taken over my time almost complete - best wishes to @Pete ) mr-fan
    1 point
  11. I have had MS Office 365 the last couple of years just for the storage of 1TB which turned out to be not more than 6GB which is super comfortable to use on Google's Drive option - even for free accounts. I made the switch to Google One in the last weeks to move company data there and well... now we pay 20 EUR/year instead of ~60 EUR/year and due to "welcome vouchers" can use everything vom G Suite as well for at least the next 2 years - which is totally fine. ? MS Office Online works pretty well on Linux but still not as good as the installed versions of Word, Excel and every other app provided by Microsoft. No matter which OS you use. Libre and Google Drive can handle UTF8 and everything Calc/Excel-related way better than Microsoft itself. Strange but true. Handling data within Libre or Google is way more easy than in any MS product out there. Even clients like the simplicity of it. To be honest... I miss XD a bit... but for now... I'm almost as fast in prototyping in HTML/CSS as in XD. Weird but it works and it's way more closer to the final result as in XD. I never used Sketch but XD is nice. My Surface still runs Windows 10 so if I ever feel the need of using any Adobe product, I can switch cables and use another device for it. For now... the switch to I3WM and some modifications (aaaaaaaa lot!) later I feel way more productive than all months and projects before.
    1 point
  12. Therefore I used this in the past: https://processwire-recipes.com/recipes/change-homepages-default-language/ Maybe it works in your case as well.
    1 point
  13. Definitely go with Repeater Matrix. It's worth every cent. Plus, ProFields has lots of other items you'll find helpful. You'll reduce development time drastically, and your client will enjoy the ease of use and flexibility.
    1 point
  14. I just want to share my findings from today when I wanted to create one million pages quickly: First, via Tracy Console: ini_set('max_execution_time', 150); $last = $pages->findOne("parent=/data,include=all,sort=-id"); $last = (int)$last->title ?: 0; for($i=$last+1;$i<$last+1000;$i++) { // create page $p = new Page(); $p->template = 'basic-page'; $p->parent = '/data'; $p->title = $i; $p->save(); l("saved page $i"); $pages->uncacheAll(); gc_collect_cycles(); } d('done'); It started at 23 pages per second: And at the end of the 150 seconds it was already down at 4 pages per second: Testing without logging: Memory usage also increased proportionally. Finally running a PHP script from the command line that bootstrapped PW worked well: <?php namespace ProcessWire; $time_pre = microtime(true); include("../../../index.php"); // bootstrap ProcessWire $last = $pages->findOne("parent=/data,sort=-id"); $i = (int)(string)$last->title ?: 0; // multilang quickfix convert to string // foreach($pages->find('parent=/data') as $p) { // $p->delete(); // echo "deleted $p\n"; // } // return; $i++; $num = 0; while($i <= 1000000) { // create page $p = new Page(); $p->template = 'basic-page'; $p->parent = '/data'; $p->title = $i; $p->save(); $pages->uncacheAll(); gc_collect_cycles(); $num++; echo "done: $num ($i)\n"; $i++; } function convert($size) { $unit=array('b','kb','mb','gb','tb','pb'); return @round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i]; } $time_post = microtime(true); $t = $time_post - $time_pre; $m = memory_get_usage(); echo "created $num pages in " . round($t, 3) . "s, " . round($t/$num, 3) . "s per page, used " . convert($m) . " memory\n"; Benefits: quick runs in the background and does not lock the site direct feedback via echo without creating huge log files cancel via ctrl+c any time easy persistant saving of your scripts
    1 point
  15. » A more exhaustive version of this article is also available on Medium in English and German « First, we'd like to thank the very helpful community here for the excellent support. In many cases we found guidance or even finished solutions for our problems. So a big THANK YOU!!! We are pleased to introduce you to the new Ladies Lounge 18 website. The next ICF Women’s Conference will take place in Zurich and several satellite locations across Europe. We embarked on bold new directions for the development of the website — in line with the BRAVE theme. Ladies Lounge 18 — ICF Woman’s Conference website on Processwire ICF Church is a European Church Movement that started 20 years ago in Zurich and since experienced tremendous growth. There are already well over 60 ICF churches across Europe and Asia. ICF is a non-denominational church with a biblical foundation that was born out of the vision to build a dynamic, tangible church that is right at the heartbeat of time. With the growth of the Ladies Lounge from a single-site event to a multi-site event, the demands and challenges to the website have also increased. A simple HTML website no longer cuts it. Simplified frontend Our goal with the development of the new site was it to present the different locations — with different languages and partly different content — under once uniform umbrella — while at the same time minimising the administrative effort. In addition to the new bold look and feel, this year’s website is now simpler and easier and the information is accessible with fewer clicks. Some highlights of the new website Thanks to processwire, all contents are maintained in one place only, even if they are displayed several times on the website 100% customised data model for content creators Content can be edited directly inline with a double-click: Multi-language in the frontend and backend Dynamic Rights: Editors can edit their locations in all available languages and the other content only in their own language Easy login with Google account via OAuth2 Plugin Uikit Frontend with SCSS built using PW internal features (find of files…) Custom Frontend Setup with Layout, Components, Partials and Snippets Only about 3 weeks development time from 0 to 100 (never having published a PW before) Despite multi-location multi-language requirement, the site is easy to use for both visitors and editors: The search for a good CMS is over It’s hard to find a system that combines flexibility and scope with simplicity, both in maintainance and development. The search for such a system is difficult. By and large, the open source world offers you the following options: In most cases, the more powerful a CMS, the more complex the maintenance and development It is usually like that; The functionality of a system also increases the training and operating effort — or the system is easy to use, but is powerless, and must be reporposed for high demands beyond its limits. Quite different Processwire : You do not have to learn a new native language, you don’t have to fight plugin hell and mess around with the loop, you don’t have to torment yourself with system-generated front-end code or even learn an entierly new, old PHP framework . All our basic requirements are met: Custom Content Types Flexible and extensible rights-management Multilanguage Intuitive backend Well curated Plugin Directory Actually working front-end editing Simple templating with 100% frontend freedom In addition, Processwire has an exceptionally friendly and helpful community. As a rule of thumb, questions are answered constructively in a few hours . The development progresses in brisk steps , the code is extremely easy to understand and simple. Processwire has a supremely powerful yet simple API , and for important things there are (not 1000) but certainly one module which at least serves as a good starting point for further development. Last but not least, the documentation is easy to understand, extensive and clever . Our experience shows, that you can find a quick and simple solution with Processwire, even for things like extending the rights-management — most of the time a highly complex task with other systems. This is also reflected positively in the user interface. The otherwise so “simple” Wordpress crumbles when coping with more complex tasks. It sumbles over its apparent simplicity and suddenly becomes complex: Old vs. New — Simple and yet complicated vs. easy and hmmm … easy Our experience with Processwire as first-timers Before we found out about Processwire, we found CraftCMS on our hunt for a better CMS. We were frustrated by the likes of Typo3, WP or Drupal like many here. CraftCMS looked very promising but as we were digging deeper into it, we found it did not met our requirements for some big projects in our pipeline that require many different locations, languages and features. Initially we were sceptical about Processwire because; A. CraftCMS Website (and before UiKit also the admin interface) simply locked much nicer and B. because it is built on top of a Framework It was only later, that we found out, that NOT depending on a Framework is actually a very good thing in Processwire's case. Things tend to get big and cumbersome rather then lean and clean. But now we are convinced, that Processwire is far superior to any of the other CMS right now available in most cases. The good Processwire is the first CMS since time immemorial that is really fun to use (almost) from start to finish— whether API, documentation, community, modules or backend interface. Every few hours you will be pleasantly surprised and a sense of achievement is never far away. The learning curve is very flat and you’ll find your way quickly arround the system. Even modules can be created quickly without much experience. Processwire is not over-engineered and uses no-frills PHP code — and that’s where the power steams from: simplicity = easy to understand = less code = save = easy maintanance = faster development … Even complex modules in Processwire usually only consist of a few hundred lines of code — often much less. And if “hooks” cause wordpress-damaged developers a cold shiver, Hooks in Processwire are a powerful tool to expand the core. The main developer Ryan is a child prodigy — active, eloquent and helpful. Processwire modules are stable even across major releases as the code base is so clean, simple and small. There is a GraphQL Plugin — anyone said Headless-CMS?! Image and file handling is a pleasure: echo "<img src='{$speaker->image->size(400, 600)->url}' alt='{$speaker->fullname}' />"; I could go on all day … The not soooo good Separation of Stucture and Data The definition of the fields and templates is stored in the database, so the separation between content and system is not guaranteed. This complicates clean development with separate live- and development-environments. However, there is a migration module that looks promising — another module, which is expected to write these configurations into the file system, unfortunately nuked our system. I'm sure there will be (and maybe we will invest) some clever solutions for this in the future. Some inspiration could also be drawn here, one of the greatest Plugins for WP: https://deliciousbrains.com/wp-migrate-db-pro/ Access rights The Access-Rights where missing some critical features: Editors needed to be able to edit pages in all languages on their own location, and content on the rest of the page only in their respective language. We solved it by a custom field adding a relation between a page the user and a role that we dynamically add to the user to escalate access rights; /** * Initialize the module. * * ProcessWire calls this when the module is loaded. For 'autoload' modules, this will be called * when ProcessWire's API is ready. As a result, this is a good place to attach hooks. */ public function init() { $this->addHookBefore('ProcessPageEdit::execute', $this, 'addDynPermission'); $this->addHookBefore('ProcessPageAdd::execute', $this, 'addDynPermission'); } public function addDynPermission(HookEvent $event) { $message = false; $page = $event->object->getPage(); $root = $page->rootParent; $user = $this->user; if ($user->template->hasField('dynroles')) { if ($message) { $this->message('User has Dynroles: '.$user->dynroles->each('{name} ')); } // for page add hook… if ($page instanceof NullPage) { // click new and it's get, save it's post… $rootid = wire('input')->get->int('parent_id') ? wire('input')->get->int('parent_id') : wire('input')->post->parent_id; if ($message) { $this->message('Searching Root '.$rootid); } $root = wire('pages')->get($rootid)->rootParent; } elseif ($page->template->hasField('dynroles')) { if ($message) { $this->message('Page "'.$page->name.'" has Dynroles: '.$page->dynroles->each('{name} ')); } foreach ($page->get('dynroles') as $role) { if ($role->id && $user->dynroles->has($role)) { if ($message) { $this->message('Add dynamic role "'.$role->name.'" because of page "'.$page->name.'"'); } $user->addRole($role); } } } if (!($root instanceof NullPage) && $root->template->hasField('dynroles')) { if ($message) { $this->message('Root "'.$root->name.'" has dynamic roles: '.$root->dynroles->each('{name} ')); } foreach ($root->get('dynroles') as $role) { if ($role->id && $user->dynroles->has($role)) { if ($message) { $this->message('Add dynamic role "'.$role->name.'" because of root page "'.$root->name.'"'); } $user->addRole($role); } } } } } With the Droles and Access Groups Modules we were not able to find a solution. I thought it was hard to get absolute URLs out of the system — Ha! What a fool I was. So much for the topic of positive surprise. (Maybe you noticed, the point actually belongs to the top.) But while we’re at it — that I thought it would not work, was due to a somewhat incomplete documentation in a few instances. Although it is far better than many others, it still lacks useful hints at one point or another. As in the example above, however, the friendly community quickly helps here. processwire.com looks a bit old-fashioned and could use some marketing love. You notice the high level to moan with Processwire. There is no free Tesla here. Conclusion Processwire is for anyone who is upset about any Typo3, Wordpress and Drupal lunacy — a fresh breeze of air, clear water, a pure joy. It’s great as a CMF and Headless CMS, and we keep asking ourselves — why is it not more widely known? If you value simple but clean code, flexibility, stability, speed, fast development times and maximum freedom, you should definitely take a look at it. You have to like — or at least not hate PHP — and come to terms with the fact that the system is not over-engineerd to excess. If that’s okay with you, everything is possible — with GraphQL you can even build a completely decoupled frontend. We are convinced of the simplicity of Processwire and will implement future sites from now on using it as a foundation. Links & resources we found helpful API documentation and selectors API cheatsheet pretty handy, not quite complete for version 3.0 Captain Hook Overview of Hooks Weekly.PW newsletter a week, exciting Wireshell command line interface for Processwire Nice article about Processwire Plugins & Techniques that we used Custom Frontend Setup with Uikit 3 and SCSS, and Markup Regions Uikit Backend Theme ( github ) Oauth2 login modules In-house development Login with E-Mail Pro Fields for repeater matrix fields (infos, price tables, daily routines) Wire upgrade to update plugins and the core Wire Mail Mandrill to send mails FunctionalFields for translatable front-end texts that are not part of a content type (headings, button labels, etc.) Runtime markup for dynamic backend fields (combination of first and last name) Tracy debugger for fast debugging Textformatter OEmbed to convert Vimeo and Youtube links into embed codes HideUneditablePages thanks to @adrian
    1 point
  16. Hey guys, Just launched a new project called Fabricius: fabriciusstrasse31.de Fabricius is a new building thats being built in Hamburg (Germany), that offers modern living comfort in a green environment. I developed the whole brand strategy and visual identity for the website and some printing materials. The logo mark is derived from the silhouette of the building, which is surrounded by trees (circular shapes) and green areas. More details here The website is build with PW 3.0 and uses Modules like Map Marker, Pages2PDF (to generate the apartment exposes) and MarkupSrcSet. Thanks for the awesome support here and the development of PW and the modules!!
    1 point
  17. Well done website and opened my mind to catch similar work.
    1 point
  18. WillyC's example just modifies the output of the $page->path() function (which is also used by $page->url). His intention there is to change what URL gets sent out when you call $page->url. It's really no different than making your own function and using it instead, except by using a hook like this, you can continue to use ProcessWire's API and get the result out of it that you want. Ultimately it's just a syntax convenience. While his hook example handles the URLs that get output in your markup, you still have to have something to look for and capture those URLs. Perhaps you could use mod rewrite, but typically you would use the "URL segments" feature that you see on the "URLs" tab when editing any template in PW admin. Lets use a simple example of your homepage template (home) with filename home.php. And lets say you want to make it so that when someone access domain.com/contact/ (a URL that doesn't currently exist) you want it to display the page that lives at domain.com/about/contact/. So you are setting up your site to respond to the shorter URL of /contact/ (rather than /about/contact/, where the page actually lives). Go to Setup > Templates > home > URLs. Click the checkbox to "allow URL segments", and save. Now edit your /site/templates/home.php file, and do something like this at the top: if($input->urlSegment1 == 'contact') { // render the /about/contact/ page echo $pages->get('/about/contact/')->render(); return; } else if($input->urlSegment1) { // throw a 404 throw new Wire404Exception(); } // otherwise continue normally and display your homepage.
    1 point
×
×
  • Create New...