Leaderboard
Popular Content
Showing content with the highest reputation on 05/30/2020 in all areas
-
There were lots of core updates this week, very much in the same theme as last week — major long term quality improvements for the core, but no shiny toys to play with… Just lots of good and solid foundational core improvements, and a few fixes too. It's mostly kind of technical stuff that's probably not that interesting to read about, so I'll keep this short, but for those interested here's the commit log. Thanks for reading and have a great weekend!5 points
-
Hi @Greg Lumley, Implementing a "user admin" on the front-end isn't difficult because of PW's API -- In theory, that is. If you aren't familiar with PHP, or aren't familiar with the API, then it obviously will be a little more difficult. You can ask any questions here in the forum and a plethora of highly-skilled programmers will be glad to help. That's another big selling point with PW vs any other. The community support is second to none. The following is an example break-down of one of my sites. I have one site where specific users have the only permissions to access specific pages. All other users could only view pages. Think of it like the *nix RGE permission structure, where Root is super user, Group is any registered user, and Everyone else is a guest just visiting. PW initially gives you the Root and Everyone roles, so you will need to add the Group role. You can name it what you want. And since I don't let *any* user access the PW admin, I don't need to specify any permissions, such as page-edit, etc. I use Processwire's built-in page management to further limit a user to only their pages. Specifically, all pages have a created_users_id, and other information that is saved each time a page is created or updated. So when a user wants to create a new entry (page) their $user->id is assigned to the created_users_id property. Now I have a one-to-many relationship between a user and all of their pages. I also have different sections where a user can create a page. For example, when a user logs into my site acme.com, they can create a page under "high-explosives", and another page under "jet-powered devices". They may not wish to create a page under any other section. Each section has it's own template, so I can easily use selectors to retrieve the user pages by section, or even retrieve all pages. The front-end "user admin" interface is simply a two column layout with a menu on the left and the content on the right. I use the Group role to determine the menu options. I obviously don't want one user viewing details of another user, except for me as super user (Root). This also restricts the admin page(s) from view by the Everyone (Guest) role. I also have a drill-down capability from this initial user admin page to get more specific details. Each user can manage their own personal data page as well. That is the basic overview. The next thing are the modules. If you do not have your own login system then I would recommend LoginRegisterPro as it covers all the bases (register, login, forgot password, etc.) that you will need for your user access requirements. I am currently looking into implementing @bernhard's RockFinder3 module to handle queries because I have many users and they each have many pages and I want to be as efficient as possible. You must have TracyDebugger. That is a requirement (should be in core ? ). It will save you many hundreds of hours of scratchin' your head. You may elect to use other modules, such as caching, etc. These are just the minimum I would recommend for a project like yours. I hope this helps.3 points
-
What exactly is the resulting settings or options here with the size call? Have a look at it with: https://processwire.com/api/ref/pageimage/get-debug-info/ // instead of // $img = $image->size($size["width"], $size["height"], $size["settings"]); // call $debuginfo = $pageimage->getDebugInfo($size["settings"], 'string'); // 'string' | 'array' | 'object' // and inspect the $debuginfo with Tracy or a var_dump()2 points
-
1. Set the columns to 0 in the Page Reference field settings. 2. Use AdminOnSteroids to add some custom admin CSS that applies columns to the list of checkboxes: #wrap_Inputfield_your_field_name .InputfieldCheckboxesStacked { column-count:2; }2 points
-
Cacheable Placeholders This module allows you to have pieces of dynamic content inside cached output. This aims to solve the common problem of having a mostly cacheable site, but with pieces of dynamic output here and there. Consider this simple example, where you want to output a custom greeting to the current user: <h1>Good morning, <?= ucfirst($user->name) ?></h1> This snippet means you can't use the template cache (at least for logged-in users), because each user has a different name. Even if 99% of your output is static, you can only cache the pieces that you know won't include this personal greeting. A more common example would be CSRF tokens for HTML forms - those need to be unique by definition, so you can't cache the form wholesale. This module solves this problem by introducing cacheable placeholders - small placeholder tokens that get replaced during every request. The replacement is done inside a Page::render hook so it runs during every request, even if the response is served from the template cache. So you can use something like this: <h1>Good morning, {{{greeting}}}</h1> Replacement tokens are defined with a callback function that produces the appropriate output and added to the module through a simple hook: // site/ready.php wire()->addHookAfter('CachePlaceholders::getTokens', function (HookEvent $e) { $tokens = $e->return; $tokens['greeting'] = [ 'callback' => function (array $tokenData) { return ucfirst(wire('user')->name); } ]; $e->return = $tokens; }); Tokens can also include parameters that are parsed and passed to the callback function. There are more fully annotated examples and step-by-step instructions in the README on Github! Features A simple and fast token parser that calls the appropriate callback and runs automatically. Tokens may include multiple named or positional parameters, as well as multi-value parameters. A manual mode that allows you to replace tokens in custom pieces of cached content (useful if you're using the $cache API). Some built-in tokens for common use-cases: CSRF-Tokens, replacing values from superglobals and producing random hexadecimal strings. The token format is completely customizable, all delimiters can be changed to avoid collisions with existing tag parsers or template languages. Links Github Repository & documentation Module directory If you are interested in learning more, the README is very extensive, with more usage examples, code samples and usage instructions!1 point
-
@horst, if you have a chance, please look at the above? Sorry for pinging you like this.... ?1 point
-
@Robin S Dudeeeeee, you rock! It works like a charm. Didn't know there's such a thing!!!!! Thanks!1 point
-
There's a lot I use regularly, but one of my favorites is Soma's ModulesManager. Makes it much easier to install other modules lol It's worth noting though that Soma's module needs a slight update in order to work properly these days: https://github.com/Awesomolocity/ModulesManager/1 point
-
Similar topic: So I guess it's not supported by the core. But it's not difficult to write your own custom JS to show/hide the field: $(document).ready(function() { // Show/hide a field if another field's value is zero function showHideField() { $('#wrap_Inputfield_my_textarea_field').toggle($('input[name="my_integer_field"]').val() === '0'); } // Show/hide on DOM ready showHideField(); // Show/hide on input change $(document).on('change', 'input[name="my_integer_field"]', showHideField); }); You'll need to get clever with the jQuery selectors if you are using fields inside a Repeater.1 point
-
Thanks! Yes i made it for the specific needs of a client website but the idea is to pollish it a bit and publish it in the Processwire repository, I want to add some options like custom amount of cols etc1 point
-
Not to keep a thread going, but will this eventually become available in the modules directory? I really like the approach you have taken!1 point
-
Hm, that's interesting - I didn't think about that ? I think it's not too late for that change and will make using RockFinder3 easier, so I just committed that change, thx!1 point
-
What about ditching the "3" ? IIRC there wasn't an API variable for the first version anyway, was there? Wouldn't this be cleaner going forward?1 point
-
Generally, this would be a shared template as the homes all contain the same content blocks (title, description, number of bedrooms, number of bathrooms, picture gallery, etc.). The only difference really is the classification of homes. Years ago, I used to work with the CMS Expression Engine which would allow for this type of grouping. I can’t remember how it did it, but it was was useful.1 point
-
Thank you! ? Yes, sure, I can give some examples. The workflow is getting refactored right now, so I can't show any specific details, but I'll describe the process. A quite simple example for a tiny helper class is this Headline Class for rendering headlines without risking to use more than one <h1> tag per page call: I like to use this on content heavy pages (e.g. within RepeaterMatrix Elements) where I want to be sure to not have more than one <h1>. By default only the first call of this helper method returns the <h1> tag, all the others an <h2> (unless otherwise specified with $sizeTag). To output a headline with this, simply use <?php echo Headline::render($page->headline); ?> I also have some helpers for rendering responsive (lazy loading) images or buttons and in this project most of the business logic of the "magic link" login is within one of these helper functions. Currently I require these classes manuelly within the ready.php include_once($_SERVER['DOCUMENT_ROOT'] . "/site/templates/helpers/Headline.php"); include_once($_SERVER['DOCUMENT_ROOT'] . "/site/templates/helpers/Image.php"); include_once($_SERVER['DOCUMENT_ROOT'] . "/site/templates/helpers/Link.php"); include_once($_SERVER['DOCUMENT_ROOT'] . "/site/templates/helpers/FrontendUserManagement.php"); include_once($_SERVER['DOCUMENT_ROOT'] . "/site/templates/helpers/CopeCartHandler.php"); But I definitely want to dig deeper into autoloading them. I want to refactor especially my Link and Image helper soon, perhaps I'll explain them afterwards further... As example for the custom Page Class here is an extract from my SpeakerPage: My Workflow Local <-> Stage <-> Live Our webserver uses Plesk Onyx as the hosting control panel. For each web project we create a separate "subscription" where the stage and live domain will live. For the dev / stage domain we use the plesk integrated git repo as dev branch. The live domain gets connected to the master branch of the same repo. As we exclude a lot of files in git (e.g. the whole /wire/ directory or the assets and module directories) we had to find a solution to copy them between stages. I'll come to that point later again. In my local environment I'm using MAMP Pro for the server environment. After pulling everything from the dev branch, we need also pull the database and exluded files / directories. To do so, the python script connects itself via SSH to the server and dumps the database, creates the same database locally and imports its contents. The files / directories will be pulled as zip files and extracted locally. Our first try here was to use rsync, but with asset-heavy pages this can take quite a while to copy... During development we usually do all the database-related stuff in the staging environment and just pull the database with our Python CLI script. When we need to pull also modules or the wire dir, our CLI script can handle that as well. Our content-editors mostly work in the staging environment ( on new web projects) or directly in the live environment (on existing projects). I'll definitely write an in-depth article about this, as soon as we have refactored it completely! Then I can also show some code snippets or even publish it, we'll see.1 point
-
1 point
-
I received the link here in different newsletters last week. So it seems to be a good source if you consider that the newsletter curators are people like Chris Coiyer or Rachel Andrew: https://moderncss.dev/1 point
-
True. At least we got Migrations and RockMigrations now. Why not? Does that feel more like a router? $this->addHookBefore('ProcessPageView::pageNotFound', function($event) { $url = $event->arguments(1); // ensure trailing slashes? if($url[-1] !== "/") $this->session->redirect("$url/"); // prevent pageNotFound to fire $event->replace = true; switch($url) { case: '/my/route1/': return $this->route1(); case: '/my/route2/': return $this->route2(); default: $event->replace = false; } });1 point
-
@SamC it's really as simple as that: https://processwire.com/blog/posts/new-ajax-driven-inputs-conditional-hooks-template-family-settings-and-more/#new-conditional-hooks Update 2022: $wire->addHookAfter('Pages::saved', function(HookEvent $event) { $page = $event->arguments('page'); bd('page saved'); bd($event, 'event'); bd($event->object, 'event->object'); bd($event->arguments(), 'event->arguments'); }); in the beginning it can be a little confusing when to use event->object, event->arguments and event->return but with the help of tracy you can quickly bring light into the dark: add the code above to the tracy console, set the radio on the right to load it on "ready" (same as placing the code in the site/ready.php file) and save any page: $event->arguments('page') is the same as using $event->arguments(0) that you will see very often and in the tracy dump you see that 0 is simply the key for the first argument in that hookevent. you can also collapse the "data" property of the hookevent and you would see the same: You can also use your IDE to quickly find what the HookEvent is returning/containing in which hook. Let's take the common saveReady hook as an example: We know that the hook is attached as Pages::saveReady (eg because we have read that somewhere) That means that the hook is part of the "Pages" class, which is located at "/wire/core/Pages.php" - that's easy to find out using CTRL+P in VSCode: Searching for "___saveReady" lets us find the corresponding method: Now we see, that we have ONE "arguments", being Page $page - this means $event->arguments(0) would return the page being ready for saving $event->object would be the class, here "Pages" $event->return is the return value of that method, here $data (line 1739) Edit: There's some additional explanations in this post: https://processwire.com/talk/topic/27248-pagestrashtemplatefoo-vs-pagestemplatefootrash/?do=findComment&comment=224659 #search afraid of hooks1 point
-
Depends a bit on context, but especially for modules I prefer translating strings in module file, storing them in $config->js and then in JS file fetching from config var. Simple example: PageListPermissions.module => PageListPermissions.js (though I'd also suggest "namespacing" JS config content, i.e. instead of using config.i18n.*, use config.YourModuleName.* and/or config.YourModuleName.i18n.* etc.)1 point