Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 07/13/2024 in all areas

  1. I'd like to second this. It would be great if the new/improved admin theme was built with maximum customisability in mind. One use case is so that we can more easily offer a "mostly-frontend" user an admin experience that's radically different to what a superuser or site administrator gets in the uncustomised admin. Another admin customisation issue I've struck recently is when you want to customise markup for InputfieldWrapper. There's InputfieldWrapper::setMarkup() but this is marked as internal and isn't that practical to use because InputfieldWrapper::markup is static. That means any custom markup you set there persists for all InputfieldWrappers that are subsequently rendered, when what I want to do is customise markup for a specific instance of InputfieldWrapper. Edit: pull request When the admin theme is revisited it would be great to ask of each component that's rendered, "Is there an opportunity to make this rendering customisable?"
    7 points
  2. I think the most talked about feature is an asset manager. The drilling down of file and imagefields so that you can choose assets from a global library that have already been uploaded somewhere, instead of having to upload assets multiple times. Actually, the approach using references is the best I've come across so far. The data remains where it was originally uploaded, but is only referenced in a file/image field on another page.
    7 points
  3. Excited to see thoughts about starting work on ProcessWire 4. PHP 8+ bring so many improvements, would be nice to utilize them. My personal pain points and wishlist for ProcessWire: - a global media manager - more official integration of multi site / multi domain capabilities (in my case especially for the one database, multiple roots option) - admin theme improvements: - a permanently visible page tree to quickly jump between pages - more ways to customize it, depending on the applications needs. Like having a predefined place to add a "website select" for multi domain websites. - quick mockup, based on www.clickup.com. Clickup also has a "task bar" where you can put pages that you want to come back to. That's quite handy as well. - from a tech point, some things that could be nice to have, but most likely not feasible and against the philosophy of ProcessWire because it would most likely make the project more bloated: - better utilization of composer, e.g. having the ProcessWire core and admin package as separate composer packages, so a ProcessWire installation would just have a "site" and a "vendor" directory - PSR standards / framework ineropability where it makes sense - some automated tests, at least for the core api @Jonathan Lahijani+1. We're using it for application development and it works very well if there is not too much data involved (with 10,000,000+ pages you'll start to having to search for workarounds to keep things fast, in my experience). Would be nice to hear what would be your ideas for improvement. A more web-application like and customizable backend would be nice for us as well. In some projects we were able to hack and hide everything that was not needed. In other projects we build a custom admin panel. Then a way to render a form for a full template in the frontend would have come in handy several times already.
    5 points
  4. Thanks for this topic @ryan! Great to have a chance to look into the future and maybe even influence it a bit. I agree with @Jonathan Lahijani, but we surely need to expand on that. I can understand his point quite well. ProcessWire taught me be a (somewhat) ambitious developer, that is ready for bigger projects. And some of those grew big enough I started seeing the limitations of PW. And though I think that PW might be not the best choice for some projects (bigger web apps, as Ryan himself pointed out before), it can have its sweet spot in between regular CMS and web frameworks like Laravel. I will try to point some of the ways I see to improve PW to move further into that sweet spot. For now I can throw in this one: A better way to build custom user admin area. Reusing existing admin сomponents, but without the need to hide lots of stuff with permissions and hooks. So we could build something like /user-admin with limited functionality, but still using page edit module.
    4 points
  5. Making ProcessWire stronger for full-stack web application development, allowing it to become an unassuming alternative to Laravel and Rails but from the origins as a CMS. ProcessWire is the perfect CMS (there's no doubt in my mind about that), and it's actually already quite good for web application development (both natively and with 3rd party modules), but with some enhancements to make it more "batteries included", enhancing page classes and some tooling, ProcessWire can have its feet in both the CMS and full-stack framework buckets in a way that's perhaps unique. I can elaborate on this further as that sounds a little too generic, but I've been developing a web application with PW for over 9 months (it's a very complicated project and it's replacing an existing, in-production system which makes it even more tricky and high-stakes) and when it's done I can share some ideas. This one enhancement alone moved the needle quite a bit in making ProcessWire more web application friendly.
    4 points
  6. Something that would be nice is an easier way to handle multisites. Something that could be useful is a sort of namespacing for databases. The default namespace would be just like normal allowing backwards compatability. However something like // Render your multisite’s primary navigation pages()->namespace('website2')->get('/')->children->each('<li><a href={url}>{title}</a>'); would be huge. This would allow easy access to the primary database for configurations or anything needed there as well as possibly allowing to set permissions for users to just access to their namespaced database. The namespacing I'd think could happen one of two ways, one would be table prefixing, the other would be creating a whole new database. Another advantage of creating a whole new database would be that it would allow us to create a processwire instance in one database, but also have completely custom data in another database that is easily accessed would be nice. Another thing that is on my wishlist for processwire 4.0 would be sqlite. For me, processwire is a beautiful CMS / CMF because as a developer, if I can adjust my projects around processwire, it becomes a low code tool, great for prototyping. Sqlite would allow me to bring up a processwire instance, create to my hearts content. Then just push this whole new project live. I would think that this would require an additional $db abstraction. It would definitely be harder to make this backwards compatible. Maybe making this some sort of opt in with disclaimers everywhere saying that this breaks backward compatability with 3.0.
    3 points
  7. Hmm. I have a lot of sympathy with this, having created a number of quite complex apps, but wonder whether it can be done while maintaining what currently makes ProcessWire so distinctive. Would it lead to a more direct comparison with competitor “full frameworks” and possible future compromises? I have managed to accomplish quite a bit of @Robin S’s objectives using process modules and my AdminInModal module. A more core way of doing it would be nice, however.
    3 points
  8. Fridays are always the days when I'm full-time on ProcessWire. Other days I may be doing client work, or ProcessWire, just depending on the week. This week it's been mostly client work. And I just learned that I'll have to be out of the office tomorrow (Friday) for a family commitment. So I'm writing this weekly update today instead, and just sent out Teppo's great ProcessWire Weekly newsletter with ProMailer today (usually it gets sent Friday). Because of this change in schedule, I don't have much new to report just yet. Instead, I wanted to start talking a little about future plans, so here's a few ideas. I think we should get another main/master version out, perhaps by September. Following that, I thought we should focus on ProcessWire 3.1, or maybe it's time for version 4. What would be in this next major version of PW? For starters, we'll finally drop support for older PHP versions and start taking advantage of all that's been added new newer PHP versions (8+). This will involve lots of updates to the ProcessWire core code base, while remaining 100% API compatible with PW 3.x. I thought that would be a good starting point into our next major version at least. In addition, we'll likely be trimming some things out of the core and into separate non-core modules, such as FileCompiler, CKEditor, the two legacy admin themes, and a few rarely used Textformatter modules. Most likely we'll also have an overhaul of this website and some nice improvements to our primary (Uikit) admin theme to accompany the next major version as well. There will be plenty more too, but this is what I've been thinking about so far. Your feedback is welcome. Thanks for reading and have a great weekend!
    2 points
  9. https://hamy.xyz/labs/2024-01_htmx-vs-alpine Quote: "Low-js tools like HTMX and AlpineJS are the future of the web. They allow us to build modern web apps without the bloat of popular SPA frameworks." What perplexity.ai says: https://www.perplexity.ai/search/explain-the-pros-and-cons-of-l-IrCeVWXSTAWsWJEv_GuNIA Let's think forward...
    2 points
  10. Logs JSON Viewer Formats JSON data in ProcessLogger for improved readability. Because log files can only contain strings, it's a common practice to use json_encode() to convert an array to a string when you want to save the data to a log file. But the resulting JSON is not as readable as it could be when viewing the log in ProcessLogger. The Logs JSON Viewer module uses the json-viewer library to improve the readability of JSON data in ProcessLogger and add some useful features. Before: After: Configuration You can set the config options for json-viewer in a textarea field. See the json-viewer readme for information about the options. There is also an option to set the width of the column that contains the JSON data. This setting exists because otherwise the column jumps around in an inconsistent and distracting way when changing from log to log or between paginations. Features You can switch the view of the JSON data between formatted and unformatted using the toggle button at the bottom of the data. The viewer has a number of useful features such as: Progressively expand or collapse levels in the data. View the count of child items and the data type of each item. Search for a string within the data. Copy all or part of the data to the clipboard (requires the HTTPS protocol). https://github.com/Toutouwai/LogsJsonViewer https://processwire.com/modules/logs-json-viewer/
    1 point
  11. @bernhard Thanks and I'll give that a shot!
    1 point
  12. Sorry, but I still can't reproduce it even with "hidden" setting... No logo field there... If you want to find the reason I think you have to debug that further and maybe check everything on a fresh install and see when/if you see the same bug. If you want a quick&dirty solution we could try to add a hookable method that runs after each migration of the settingspage where you should be able to override any settings.
    1 point
  13. @bernhard I am hiding some fields using the template context settings, but only the fields I mentioned aren't keeping those settings. All of the other fields keep the visibility settings.
    1 point
  14. Custom Logs When you use the core $log->save() method you can only save a single string of text. When you view the log in the core ProcessLogger the columns and their header labels are predetermined. The Custom Logs module is different in that it lets you write and view log files with the number of columns and the column header labels you specify in the module configuration. Configuration In the "Custom logs" textarea field, enter custom logs, one per line, in the format... name: column label, column label, column label ...with as many comma-separated column labels as needed. The log name must be a word consisting of only [-._a-z0-9] and no extension. If you prefix a URL column label with {url} then the value in the column will be rendered as a link in the log viewer. The date/time will automatically be added as the first column so you do not need to specify it here. Writing to a custom log Use the CustomLogs::save($name, $data, $options) method to save data to a custom log file. $cl = $modules->get('CustomLogs'); $cl->save('my-log', $my_data); Arguments $name Name of log to save to (word consisting of only [-._a-z0-9] and no extension). $data An array of strings to save to the log. The number and order of items in the array should match the columns that are configured for the log. $options (optional) Options for FileLog::save(). Normally you won't need to use this argument. Example of use Custom log definition in the module configuration: visits: {url}URL, IP Address, User Agent, {url}Referrer Saving data to the log: $cl = $modules->get('CustomLogs'); $data = [ $_SERVER['REQUEST_URI'] ?? '', $_SERVER['REMOTE_ADDR'] ?? '', $_SERVER['HTTP_USER_AGENT'] ?? '', $_SERVER['HTTP_REFERER'] ?? '', ]; $cl->save('visits', $data); Viewing the resulting log in Setup > Logs > visits: https://github.com/Toutouwai/CustomLogs https://processwire.com/modules/custom-logs/
    1 point
  15. And here I was thinking that this is so useful that it should be a core feature ? Anyway, just wanted to say that I absolutely love the concept of this module. In fact both Custom Logs and Logs JSON Viewer are brilliant additions!
    1 point
  16. Hello @marie.mdna I hope I have fixed the problem now ?. For testing purposes I have added the profile form inside segment 2 so it was reachable under /profile/segment1/segment2. After form submission it redirects successfully to the same url (on success and error) - so everthing works fine. I have tested it on a single and a multi-language site and with/without Ajax. On my local installation it works as expected. So please update FrontendForms to 2.2.8 and FrontendLoginRegister to 1.3.4 and let me know if it works for you now. Best regards
    1 point
  17. Hello @marie.mdna You are right, it does not work inside url segments. The failure is inside the form action attribute and/or the redirects which does not recognize the segments after the url, so every redirect leads to the base url instead of the base url including the segments. I try to fix this now!
    1 point
  18. As I know you are using RockMigrations / RockPageBuilder have you seen https://www.baumrock.com/en/processwire/modules/rockmigrations/docs/magicpages/ ? It will let you define hooks in an init() or ready() method in your custom page class. There you can add hooks and RM will make sure it will only trigger init/ready once for each pageclass, which is one culprit when using loaded() as it will get triggered multiple times and potentially add hooks more often than once. Also it has shortcuts for often needed hooks, so for example you can hook the backend page edit form like this: public function editFormContent($form) { $form->add([ 'type' => 'markup', 'label' => 'foo', 'value' => 'bar', ]); }
    1 point
  19. You are just missing the final semicolon after addDefaultFolder()
    1 point
  20. I meant to mention that I didn't know about that method before your comment. Now that I know about it though I'll probably end up using it. So thank you for the tip! There was one instance where it may have come in handy. I created a PageClass method that analyzes the current page request to determine if it was an AJAX request for a specific purpose, but decided to just call $page->whateverMethdName() at the top of the template before anything rendered. The loaded() method is the way I'll go with that next time. I learned something new today ? Bookmarking this. Keeping hooks closer to the location/context that makes sense is a good idea.
    1 point
  21. I use a mixture of calls to run various initializing code, depending on what to initialize, e.g., copied from a Product page's custom class: /* * Called when the page is requested on the frontend. * Called from _init.php via include_once(config()->paths->templates . 'path/to/this/_init_once.php'); * so that it only runs once per request: * page()->requested(); */ public function requested() { $this->request_ws = "\ProcessWire\RqtProduct"; parent::requested(); } /* * When initialization of object properties is required right from the beginning. */ function __construct(Template $tpl = null) { parent::__construct($tpl); $this->factsAy = new Arrayy([]); } public function ___loaded() { parent::___loaded(); // Either building a structured array of all product data and caching it in a variable or reading that from memory. if (empty($this->facts)) { $this->encodeFacts(); } else { $this->factsAy = Arrayy::createFromJson($this->facts); } } /** * Product page specific hooks. This method is called from site/init.php from my custom loop * that runs for each frontend template based page. * if (in_array($templateName, config()->noneFrontendTemplates)) { * if ($templateName === "user") call_user_func_array("{$namespace}{$className}::initiate", []); // UserPage needs special treatment. * continue; * } * if (class_exists($namespace . $className)) call_user_func_array("{$namespace}{$className}::initiate", []); // Page classes register hooks in their initiate() method this way. */ public static function initiate() { parent::initiate(); wire()->addHookBefore("Pages::saveReady(template=product)", function ($event) { ... more hooks go here ....
    1 point
  22. I'd love to see an "officially supported and recommended (and even documented) way" of initializing custom page class objects, discussed and requested by us over the years: https://github.com/processwire/processwire-requests/issues/456 https://processwire.com/talk/topic/30138-page-classes-diving-into-one-of-processwires-best-features/?do=findComment&comment=242737 https://processwire.com/talk/topic/25342-custom-classes-for-page-objects-the-discussion/
    1 point
  23. How to initialize a "custom page" object has also been discussed here before: https://processwire.com/talk/topic/25342-custom-classes-for-page-objects-the-discussion/ and is also discussed in this request at Github: https://github.com/processwire/processwire-requests/issues/456 I'd love to see an "officially supported and recommended way" of doing this.
    1 point
  24. Well, funny story, I have no reasoning. I just misremembered between reading that and hacking out this post. Jumping between projects in and outside of ProcessWire didn't help haha. I've used DefaultPage in the past, it was just an oversight this time around. Ryan's is of course the correct way. I generally always have a custom page class for each of my templates so I've never had an issue where DefaultPage was loaded on it's own. Appreciate you mentioning it, I've updated the post to use DefaultPage. My first reaction is that unexpected behaviors may indicate that there may be too much abstraction. My DefaultPage classes have traditionally been lightweight and stick to only containing what can be reliably counted on as valuable across all pages. One of the criticisms of OOP is that classes and inheritance can make for brittle code so it's something that I try to be mindful of. It may also be good to try an keep anything that executes automatically or hooks into the Page lifecycle to a minimum (maybe none at all) in DefaultPage since it spans the entire application. I use names like these myself for the same reason. Really helps keep a sane number of fields and reduce redundancy. I haven't taken this approach to reassigning values to properties like this but it's an interesting idea. I reviewed the code for the Page class and there is a good amount of logic in Page::set() that can be useful when working with values but may not be needed within the context of a page class. At first blush though I would just assign the value of the field to an instance variable directly rather than call Page::set() because at time of authorship- you know what field you'll be working with, it's data type, and intended usage within the context of that template/page. <?php public $introTitle; public $introText; // set custom properties in loaded public function loaded() { // load custom properties only for allowed statuses if (!empty(array_intersect(array_keys($this->status(true)), self::excludeStatuses))) return; $this->introTitle = $this->text; $this->introText = nl2br($this->textarea); } I may be missing the added value of using Page::set() in your use case though. My other thought though is that if these fields have consistent and wide enough usage through all templates, enough to reassign them to alternate property names, they might be a candidate for dedicated fields rather than repurposing generalized fields. Both introTitle and introText seem like they have wide enough usage, so I would create those fields and skip any extra logic needed here in DefaultPage. I actually haven't set a lot of instance variables in page classes. I've focused on methods that can abstract logic out of templates, or perform computationally expensive operations only on demand. Here's a DefaultPage from a production site: <?php namespace ProcessWire; use Ramsey\Uuid\Uuid as Uuid; use \DateTime; class DefaultPage extends Page { /** * Paths for rendering methods */ const COMPONENTS_PATH = '/../templates/components/'; const FORMS_PATH = '/../templates/components/forms/'; const PARTIALS_PATH = '/../templates/partials/'; const SVG_PATH = '/../templates/img/svg/'; /** * Stub method that may be overridded by inheriting classes where needed */ public function renderStructuredData(): ?string { return null; } /** * Outputs full path and filename for CSS files */ public function css(string $file): string { return wire('config')->urls->templates . "dist/styles/{$file}"; } /** * Outputs full path and filename for JavaScript files */ public function js(string $file): string { return wire('config')->urls->templates . "dist/scripts/{$file}"; } /** * Returns contents of an SVG file with unique IDs for title/description attributes for accessibility */ final public function renderSvg(string $file, array $variables = []): string { $variables = array_merge($variables, [ '{ARIA_TITLE_ID}' => Uuid::uuid4()->toString(), '{ARIA_DESC_ID}' => Uuid::uuid4()->toString(), '{CLASSES}' => $variables['classes'] ?? null, ]); return strtr(file_get_contents(__DIR__ . self::SVG_PATH . $file), $variables); } /** * Renders a file in /templates/partials/ */ final public function renderPartial(string $file, array $variables = []): string { return wire('files')->render($file, $variables, [ 'defaultPath' => __DIR__ . self::PARTIALS_PATH ]); } /** * Renders file located in templates/components/ */ final public function renderComponent(string $file, array $variables = []): string { return wire('files')->render($file, $variables, [ 'defaultPath' => __DIR__ . self::COMPONENTS_PATH ]); } /** * Renders a form */ final public function renderForm(string $file, array $variables = []): string { return wire('files')->render($file, $variables, [ 'defaultPath' => __DIR__ . self::FORMS_PATH ]); } /** * Gets the time period of the day based on the hour */ final public function getPeriodOfDay(): string { $hour = (new DateTime())->format('H'); switch (true) { case $hour < 12: return 'morning'; case $hour >= 12 && $hour <= 17: return 'afternoon'; default: return 'evening'; } } /** * Returns all top level pages for the main navigation */ final public function topLevelPages(): PageArray { $pages = wire('pages'); $selector = 'parent=1'; $excludedIds = $pages->get('template=admin_website_settings') ->nav_main_excluded_pages ->explode('id'); // Check for excluded pages from nav defined in the "Website Settings" page count($excludedIds) && $selector .= ',id!=' . implode('|', $excludedIds); $homePage = $pages->get(1); $topLevelPages = $pages->find($selector); $topLevelPages->prepend($homePage); return $topLevelPages; } } All of the other magic goes into traits or inheriting page classes. My soft guidelines when it comes to code organization is: Save abstraction until something is repeated 3 times, consistency should be maintained, or complexity warrant it for the sake of the surrounding code. Abstract to a trait or enum that can be selectively used where needed. Consider abstracting to a parent class last, there has to be a case for why it should be shared between all classes because it's more than ubiquity, it comes down to rock solid shared behavior and purpose
    1 point
  25. I would love to see some kind of a bare bones of e-commerce features in the core, that could help to build a basic small shop directly in PW, without the need of integrating with third party e-commerce systems like Shopify etc. Just thinking out loud ? Have a great weekend!
    1 point
  26. Thanks. Good call, I didn't think about that panel. You don't want to be making changes and additions to Tracy Debugger for the sake of other modules. The appeal of CustomLogs might be quite niche so I'll wait for a bit, but I could perhaps look at including a panel for Tracy within the CustomLogs module. I think I remember reading somewhere that you've allowed for third-party panels - can you refresh my memory on this? And could there be a way to hook into the ProcessWire Logs panel rendering (if there isn't already)? I have another log-related module to release and I could potentially add a feature so that it applies to the Logs panel too.
    1 point
  27. Really cool Robin! Just an FYI for Tracy users - I have pushed a new version which excludes any CustomLogs logs from the PW logs panel because they were just confusing with the incorrect headers and mismatched number of columns. Not sure yet, but I might build a new CustomLogs Panel to properly handle displaying them.
    1 point
  28. DaCha is a water sports center in Egypt and a hotel. https://surfdacha.com/en/ Multi-language. The backend implements the management of customer reservations and bookings. Naturally, the website is made on ProcessWire. UiKit 3 layout Modules: LoginRegisterPro, Cookie Management Banner, Map Marker, FrontendForms, Markup Sitemap XML, Video embed for YouTube (and Vimeo), Tracy Debugger. The backend implements the management of customer reservations and bookings.
    1 point
×
×
  • Create New...