Leaderboard
Popular Content
Showing content with the highest reputation on 07/06/2024 in all areas
-
This week there were several commits to the core, mostly for resolving pending issue reports. In addition, this week I've posted a new version of the "Page Edit Children" module in the ProFields download thread. Below is the changelog for this new version: Added support for adding new children that can be fully edited right away (without having to save first). This is similar to how it already worked for the clone action. It makes it a lot quicker and easier to build out child pages, and you can add+edit as many as you want before hitting "Save". In addition, you can now drag/drop the "Add New" fieldset to the place where you want to add the new child page. This enables you to easily insert new pages anywhere you want, rather than only adding them at the bottom of the list. Added support for new child actions: Lock/Unlock and Hide/Unhide. These accompany the existing Publish/Unpublish and Clone actions. You can now configure what actions you want to be available via setting in the module configuration. For instance, maybe you don't need Hide/Unhide or Lock/Unlock, so you can simply turn them off. Action status is now more obvious, as the "on" states of actions (like unpublished, locked, hidden) now appears in red, making it much more obvious when a child page has one of these states. Added new configuration option that lets you choose whether the sort handle for each item should be on the left side of each child, or on the right side (with the other actions). You probably want it on the left side, unless you are using custom page icons (defined with templates) and you want them to appear. In v1 the sort handles were always on the right. Added support for an optional headline that appears above the child pages. Added support for customizing the "Add new" label in the module settings. If you want to change the icons that are used for actions, you can now do so by hooking the new actionIcons() hookable method. Added a confirmation dialog for the Clone action. This helps make it easier to recover if you accidentally click the clone action. There were also various other minor updates, including minor fixes and optimizations. This version is available for download now in the ProFields thread. This is still considered a development version so be sure to test thoroughly before using in any production environments. For version 3 (or nearby), I am hoping to add support for one of the feature requests: editing both children and grandchildren on the same screen. The screenshot below d emonstrates a few of things mentioned in the changelog above. Thanks for reading and have a great weekend!5 points
-
Important to note that that module is no longer being maintained in favor of its commercial follow-up: https://processwire.com/store/login-register-pro/ Note that Ryan's modules are worth their price, and they are also secure. One can save a significant amount of time and receive quality support for the price. Compared to almost all other PHP CMS/CMF options out there, ProcessWire requires the least amount of time and effort when upgrading the system and its modules. You can keep a ProcessWire site online "forever" without the fear of it not being updated. The only driving force to update a ProcessWire site that is running fine is to keep up with PHP deprecations. Other than that, there are no maintenance tasks to perform if you are okay with a particular ProcessWire site. By purchasing the most important modules from Ryan (modules most important to you), you also support the continuous development of the system. At least that's how I look at it ?2 points
-
PW provides all the API to create users and login them. You just need to create the frontend form so the regular users will be able to login on the site. No module is required, but if you don't want to write code at all you can use a free module, in the past I've used this one.2 points
-
So I started playing around with Supermaven's free tier. If you are looking for a code assistant for VSCode I would recommend giving it a try. I started using it after Theo covered it in one of his tool videos, and I can say it probably shaves about 15 minutes of work per hour for me. It does a reasonably good job of anticipating structures you are building based on a quick overview of the codebase for your project. I haven't extended the codebase to include the entire source for processwire in my projects, but even with just the minimum core wire folder modules and a few site module source code bits it is more than enough to cover the bases. I am using the free tier which has a smaller token context limitation, but the code suggestions are fast, they don't feel inappropriately intrusive and don't write-ahead too far until the engine has high confidence in the direction you are trying to go. When it has high certainty, it opts to give you large code blocks - even entire functions with appropriate substitutions. It has sped up my RockMigration script writing considerably - beyond the macros, because it sees other migration functions I have defined and does a very good job of anticipating not only the class structures for custom page classes, etc, but also replacing names for new classes with proper singular/plural forms, etc. I'd say it provides the correct code without modification 85% of the time. https://supermaven.com/1 point
-
I suggest using URL hooks for any requests coming from the front-end. It wouldn't be ideal to have front-end requests going to a Process module page in any case because that would decrease site security by publicly revealing the admin login URL.1 point
-
Can you try disabling mutagen? Existing ddev issues point towards mutagen as the culprit.1 point
-
Hi, just my two cents ? to do all of this i simply use the tinytmce module config abilities and then in this css file i simply import my fonts.css or, depending of their number define my fontfaces as in the font side afterwards, il can, exactly like on the front end, set all the rules i want to be applied in tinymce for the h, the classes and so on have a nice day1 point
-
Hi! Per default all my web projects are located in my "Websites" folder inside my user folder (I am working on a mac). For testing I moved my current ddev project into a different folder, unlisted the project from ddev, started it new and I still have the problem that the file permissions are set to 600.1 point
-
Thank you for these updates @ryan! A small note / bug though: you forgot to check if the userActivity module is installed in the `userActivityReady()` function1 point
-
My personal believe is that ProcessWire would be the perfect platform for what you want to do, but you won't be able to completely circumvent a PHP learning curve. Since I don't know any platform or toolkit on the market that provides all the features you want without some programming (and the trend goes towards dropping pre-built solutions and requiring more programming, even with the "big players" like Sharepoint or Typo3), it's probably just a question of picking your poison. I'll try to answer your points as good as I can, though others with more experience with the specific requirement may have even better ideas. 1. Member login is possible with the free FrontendUser module. 2. Donations could e.g. be achieved with Stripe (Patreon, from what I hear, is cutting down on its APIs and trying to monetarize things to a point of pain). There's a stripe payment processor that's part of the commercial FormBuilder module. 3. Taxonomy is an integral part of PW. Tagging, either with plain text tags or pages (the later even created on demand when you add a tag or relationship item) can easily be achieved out of the box, and there are free modules for things like creating two-way relationships between pages. PW's philosophy that "everything is a page" may sound a bit scary at first if you've worked with CMSes like WP or Drupal, but in the most simple case, a page is just a title field and auto-generated name living somewhere in the page tree. 4. You actively have to implement (yourself or with a module) the blog behavior. If you want it, it's pretty simple with PW's built-in selectors and pagination. 5. Really easy to implement. Add a "featured" checkbox to the templates that are relevant, call $pages->findOne('features=1, sort=-created') to your home template and render the returned page. 6. This is easy too. Yes, it too requires small bits of PHP, but most of it is still CSS and JS. Just a small step up from a static HTML page. 7. Again, FormBuilder might be a good choice here. There are a few more options out there as well, and you'll certainly get good responses here if you inquire with a specific example or use case. 8. Rendering an RSS feed is possible (though I haven't used those in a long time) with free modules, it just needs a tiny bit of (well documented) programming. 9. Just add PW's core Markdown Textformatter or (if you want to mix Markdown and HTML) install and add TextformatterMarkdownInMarkup in the field's configuration, and it will convert the markdown when the contents are shown in the frontend. One thing I'd like to add: you'll certainly not find a CMS with a more friendly and helpful community than PW.1 point
-
This week a need came up in a client project. The client's team wanted to be able to navigate to their tours (pages) in the admin page-list by different criteria (operator, brand, boat, etc.). You can do this in Lister already (filtering by page references), but the client was looking for some predefined navigation paths in the main page list, as they thought this would be a helpful and time saving optimization, as they spend a lot of time in ProcessWire. They don't always know the exact tour at first, so starting from an operator, brand or boat helps them get to where they want to go more quickly. Once implemented, I thought it was actually quite useful for a lot of situations so decided to develop it into a module on my own time, and that's now available for download in the modules directory. I've published a new blog post that describes it more and covers all the details— https://processwire.com/blog/posts/page-list-custom-children-module/1 point
-
I'd be happy to provide something like that. I'm really short on free time right now but I may be able to adapt a real life example once I get enough done on one of my projects. That way I can avoid double work and have a good example. Will keep it in mind and bring that info back here as a demo repository when I can do it right. I've implemented the exact same method on sites before and that's a great example. I like to create a jsonld() method which returns null in my BasePage class that exists specifically to be overwritten by inheriting pages. That way I can call $page->jsonld() in a partial like site_header.php without any logic, it renders something or it doesn't.1 point
-
Hi @Robin S. Please also take a look at my request "automatically call the init method on custom page classes" https://github.com/processwire/processwire-requests/issues/456 and maybe leave a thumbs up. Your method requires changes to /site/ready.php or /site/init.php files. I think self-initiating custom page files are way better, so for example, a blogPage.php custom page class file would automatically create all fields and provide custom methods like `localDate`. This way, you can simply copy the file to a new project, and everything will be set up automatically without needing additional changes to other files.1 point
-
Added namespace but sadly it doesn't change the result. [EDIT] I solved it by restoring a backup. Still kinda strange...1 point
-
I've seen a couple of questions regarding namespaces and autoloading floating around the forum recently, so I decided to write a little tutorial. In general, I often see people getting confused when they try to wrap their head around namespaces, autoloading, Composer and the mapping of namespaces to directory structures all at once. In fact, those are very much independent, distinct concepts, and it is much easier to explain and understand them separately. So this guide is structured as follows: How namespaces work in PHP. How autoloading works in PHP. Conventions for mapping namespaces to directory structures: PSR-4. How autoloading works in Composer and ProcessWire's class loader. How to use the class loader in a ProcessWire module. Feel free to skip the sections you're already familiar with. Namespaces in PHP The purpose of namespaces in PHP is to avoid naming conflicts between classes, functions and constants, especially when you're using external libraries and frameworks. Nothing more. It's important to understand that this has nothing at all to do with autoloading, directory structures or file names. You can put namespaced stuff everywhere you want. You can even have multiple namespaces inside a single file (don't try this at home). Namespaces only exist to be able to use a generic name – for example, ProcessWire's Config class – multiple times in different contexts without getting a naming conflict. Without namespaces, I couldn't use any library that includes a Config class of it's own, because that name is already taken. With namespaces, you can have a distinction between the classes ProcessWire\Config and MoritzLost\Config. You can also use sub-namespaces to further segregate your code into logical groups. For example, I can have two classes MoritzLost\Frontend\Config and MoritzLost\Backend\Config– a class name only needs to be unique within it's namespace. You can declare the namespace for a PHP file using the namespace statement at the top: // file-one.php <?php namespace ProcessWire; // file-two.php <?php namespace MoritzLost\Frontend; This way, all classes, methods and constants defined inside this file are placed in that namespace. All ProcessWire classes live in the ProcessWire namespace. Now to use one of those classes – for example, to instantiate it – you have a couple of options. You can either use it's fully qualified class name or import it into the current namespace. Also, if you are inside a namespaced file, any reference to a class is relative to that namespace. Unless it starts with a backward slash, in this case it's relative to the global namespace. So all of those examples are equivalent: // example-one.php <?php namespace ProcessWire; $page = new Page(); // example-two.php <?php use ProcessWire\Page; $page = new Page(); // example-three.php <?php $page = new ProcessWire\Page(); // example-four.php <?php namespace MoritzLost\Somewhere\Over\The\Rainbow; $page = new \ProcessWire\Page(); The use statement in the second example can be read like this: “Inside this file, all references to Page refer to the class \ProcessWire\Page” How autoloading works Every PHP program starts with one entry file – for ProcessWire, that's usually it's index.php. But you don't want to keep all your code in one file, that would get out of hand quickly. Once you start to split your code into several individual files however, you have to take care of manually including them with require or include calls. That becomes very tedious as well. The purpose of autoloading is to be able to add new code in new files without having to import them manually. This, again, has nothing to do with namespaces, not even something with file locations. Autoloading is a pretty simple concept: If you try to use a class that hasn't been loaded yet, PHP calls upon it's registered autoloaders as a last-ditch attempt to load them before throwing an exception. Let's look at a simple example: // classes.php <?php class A { /** class stuff */ } class B { /** class stuff */ } // index.php <?php spl_autoload_register(function ($class) { include_once 'classes.php'; }); new A(); new B(); This is a complete and functional autoloader. If you don't believe me, go ahead and save those two files (classes.php and index.php) and run the index.php with php -f index.php. Then comment out the include_once call and run it again, then you'll get an error that class A was not found. Now here's what happens when index.php is executed (with the autoloader active): Our anonymous function is added to the autoload queue through spl_autoload_register. PHP tries to instantiate class A, but can't because it's not loaded yet. If there was no autoloader registered, the program would die with a fatal error at this point. But since there is an autoloader ... The autoloader is called. Our autoloader includes classes.php with the class definition. That was a close one! Since the class has been loaded, execution goes back to the index.php which can now proceed to instantiate A and B. If the class was still not loaded at this point, PHP would go back to the original plan and die. One thing to note is that the autoloader will only be called once in this example. That's because both A and B are in the same file and that file is included during the first call to the autoloader. Autoloading works on files, not on classes! The important takeaway is that PHP doesn't know if the autoloader knows where to find the class it asks for or, if there are multiple autoloader, which one can load it. PHP just calls each registered autoloader in turn and checks if the class has been loaded after each one. If the class still isn't loaded after the last autoloader is done, it's error time. What the autoloader actually does is pretty much wild wild west as well. It takes the name of the class PHP is trying to load as an argument, but it doesn't have to do anything with it. Our autoloader ignores it entirely. Instead, it just includes classes.php and says to itself “My job here is done”. If class A was in another file, it wouldn't have worked. This process has two main advantages: Since autoloaders are only called on-demand to load classes just in time, we only include the files we actually need. If in the example above class A and B are not used in some scenarios, the classes.php will not be included, which will result in better performance for larger projects (though this isn't as cut and dry, since autoloading has it's own overhead, so if you load most classes anyway during a single request, it will actually be less efficient). If the autoloader is smart enough to somehow map class names to the files they're located in, we can just let the autoloader handle including the classes we need, without having to worry about jamming include statements everywhere. That brings us to ... PSR-4, namespaces and directory structures As you see, namespaces and autoloading are both pretty limited concepts. And they aren't inherently linked to each other. You can namespace your classes without ever adding an autoloader, and you can autoload classes that are all in the same namespace. But they become useful when you put them together. At the core of all that autoloading talk is a simple idea: By putting classes in files named after their class names, and putting those files in directory hierarchies based on the namespace hierarchy, the autoloader can efficiently find and load those files based on the namespace. All it needs is a list of root namespaces with their corresponding directories. The exact way class names and namespaces are mapped to directory structures and file names is purely conventional. The accepted convention for this is PSR-4. This is a super simple standard which basically just sums up the ideas above: A base namespace is mapped to a specific directory in the file system. When the autoloader is asked to load a class in that namespace (or a sub-namespace of it), it starts looking in that folder. This "base" namespace may include multiple parts – for example, I could use MoritzLost\MyAwesomeLibrary as a base and map that to my source directory. PSR-4 calls this a "namespace prefix". Each sub-namespace corresponds to a sub-directory. So by looking at the namespace, you can follow subdirectories to the location where you expect to find the class file. Finally, the class name is mapped directly to the file name. So MyCoolClass needs to be put inside MyCoolClass.php. This all sounds simple and straightforward - and it absolutely is! It's only once you mash everything together, mix up language features, accepted conventions and proprietary implementations like Composer on top that it becomes hard to grasp in one go. Composer and ProcessWire's class loader Now all that's left is to talk about how Composer and ProcessWire provide autoloading. Composer, of course, is primarily a tool for dependency management. But because most libraries use namespaces and most developers want to have the libraries they're using autoloaded, those topics become a prerequisite to understanding what Composer does in this regard. Composer can use different autoloading mechanisms; for example, you can just give it a static list of files to include for every request, or use the older PSR-0 standard. But most modern libraries use PSR-4 to autoload classes. So all Composer needs to function is a mapping of namespace prefixes to directories. Each library maintains this mapping for it's PSR-4-structured classes through the autoload information in their composer.json. You can do this for your own site to: Just include the autoload information as shown in the documentation and point it to the directory of your class files. Composer collects all that information and uses it to generate a custom file at vendor/autoload.php — that's the one you need to include somewhere whenever you set up Composer in one of your projects. Bells and whistles aside, this file just registers an autoloader function that will use all the information collected from your own and your included libraries' composer.json to locate and include class files on demand. You can read more about how to optimize Composer's autoloader for production usage here. If you want to read up on how to set up Composer for your own sites, read my ProcessWire + Composer integration guide instead. And finally, what does ProcessWire do to handle all this? Turns out, ProcessWire has it's own autoloader implementation that is more or less PSR-4 compliant. You can access it as an API variable ($classLoader or wire('classLoader'), depending on context). Instead of using a static configuration file like Composer, the namespace -> directory mapping is added during the runtime by calling $classLoader->addNamespace. As you would expect, this function accepts a namespace and a directory path. You can use this to register your own custom namespaces. Alternatively, if you have site-specific classes within the ProcessWire namespace, you can just add their location to the class loader using the same method: $classLoader->addNamespace('ProcessWire', '/path/to/your/classes/'). Utilizing custom namespaces and autoloading in ProcessWire modules Now as a final remark, I wanted to give an example of how to use custom namespaces and the class loader in your own modules. I'll use my TrelloWire module as an example: Decide what namespace you're going to use. The main module file should live in the ProcessWire namespace, but if you have other classes in your module, they can and should use a custom namespace to avoid collisions with other modules. TrelloWire uses ProcessWire\TrelloWire, but you can also use something outside the ProcessWire namespace. You need to make sure to add the namespace to the class loader as early as possible. If either you or a user of your module tries to instantiate one of your custom classes before that, it will fail. Good places to start are the constructor of your main module file, or their init or ready methods. Here's a complete example. The module uses only one custom namespaced class: ProcessWire\TrelloWire\TrelloWireApi, located in the src/ directory of the module. But with this setup, I can add more classes whenever I need without having to modify anything else. /** * The constructor registers the TrelloWire namespace used by this module. */ public function __construct() { $namespace = 'ProcessWire\\TrelloWire'; $classLoader = $this->wire('classLoader'); if (!$classLoader->hasNamespace($namespace)) { $srcPath = $this->wire('config')->paths->get($this) . 'src/'; $classLoader->addNamespace($namespace, $srcPath); } } Source Thanks for making it through to the very end! I gotta learn to keep those things short. Anyway, I hope this clears up some questions about namespaces and autoloading. Let me know if I got something wrong, and feel free to add your own tips and tricks!1 point