Jump to content

Leaderboard

Popular Content

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

  1. As a default? Big NOPE from me. The super easy way and low barrier to enter the world of ProcessWire was one of the main reasons I gave it more than a quick look, did all the tutorials, read the docs, read the forum, ... and stayed. I tried a lot of CMSs back then and because ProcessWire had this "direct output"-way of achieving a lot without needing to know much about PHP or programming in general was the biggest PLUS ever. if/else/echo/foreach is almost everything you need to know to get up and running - and this quite far. Easier than anything. Easier than the Wordpress-loop, Silverstripe's way of doing things, or Drupal and Typo3. Such a delight and super fun to learn something new, a new CMS. Sorry for interrupting this great discussion.
    9 points
  2. Output logic is a part of the view. When I build a site profile to share with others my primary goal is to make it as simple and easy-to-follow as possible. For most websites powered by ProcessWire the template files are the views, and that's where I think most should start too, as it's very simple. As needs grow, many will naturally isolate the views to reusable files separate from the template files when it makes sense (like that parts directory in the invoice profile). But I think it's good for PW to be less opinionated about that because people may be using different template engines, different output strategies (direct, delayed, markup regions), etc., or they may not even care about following an MVC pattern, even if PW naturally leads there. This pattern was around before we had web sites/applications, so the "view" part is not like it was when we were building desktop applications in the old days with Borland C++. With HTML we've got server side markup and the additional layers of client side CSS and JS. Not everyone always agrees about where to draw the lines and it can depend on the case. I don't think we should decide that for people and I think it's good to be flexible on on this part of it.
    8 points
  3. This is super true. Gideon
    6 points
  4. @wbmnfktr was just a minute faster, but I feel exactly the same way: I have to say I am using ProcessWire exactly because it doesn't force me into a direction and/or into a form of "best practice". But nevertheless I think there is already a lot of controller in the ProcessWire core. What you @szabesz want I think is a way to create your own controller manifested as a class and tightly integrated in the request lifecycle. But can't you already do that? That is the beauty of ProcessWire. You can alter anything I can think of with hooks. They will allow you to create a fully-fledged controller system if you want to. But again, I feel like ProcessWire handles most of the controller stuff one would ever need.
    4 points
  5. Hi all. Reading through the discussion about page classes, I have to add my two cents. I feel like we are mixing concepts here. We are talking about OOP concepts where the request arises to extend page classes' capabilities to better allow for separation of concerns. Many OOP concepts stem from or are just a fancy form of the MVC pattern. I strongly believe ProcessWire follows such a form too. Whereas the core handles MC and it's API provides endpoints for the V in Model-View-Controller and hooks for extending and altering the C part. So to really allow for separation of concerns, page classes aren't the right place to start off. A page is just the representation of an entity, a line in the database. Instances of said class that is. And thus Page and page classes belong to the Model part of ProcessWire. And this is exactly where my motivation to side with @ryan and his general scepticism of page class init and ready methods comes from. So it makes sense to add virtual properties or basic relationships to the page class. But the model should never contain business logic which acts outside of the lifecycle of the entity. Having made my point so far, I think Ryan's second to add a new class file to act as a controller (by using the ProcessWire's hooks) makes a lot of sense. And exactly that is why I believe, ProcessWire already offers a very good way to enforce MVC patterns and true separation of concerns. It offers a good API without forcing everyone to use the same architectural patterns so many other systems do.
    3 points
  6. @Jonathan Lahijani Preferably use require_once() or include_once(). But if you prefer autoloading, you could add this in your /site/init.php if you wanted to autoload any classes in /site/classes/ that ended with "PageHooks": $classLoader->addSuffix('PageHooks', $config->paths->classes); ProcessWire's class autoloader is more efficient than most, but if you already know a file exists and where it is, I prefer to require_once(). It's more efficient and more clear, nothing hunting for files behind the scenes. There's a reason why this file exists in ProcessWire, even though all of those classes could likely load without it. It makes the boot faster. Class autoloading is obviously necessary for many cases, especially if working with other libraries. But for a case like the one mentioned here, skip the autoloading unless you feel you need it.
    3 points
  7. ProcessWire Improvement Suggestions I’m pleased to see ideas being gathered to improve ProcessWire, and as a loyal user and contributor since 2014, I'd like to share my list and thoughts on the matter. Over the past few years, there has been a lack of clarity on whether requests and ideas will be implemented, and if so, when. Requests and issues often remain open for years without updates. I'll address how this can be optimized. There is also no clear way to influence these decisions. Years ago, we introduced the idea that thumbs-ups in the Requests Repo should mark the importance of requests. However, there's still no way to know if any of these points will be implemented. My idea for the future is as follows: Increase Community Involvement and Establish a Fixed Release Cycle Optimize Integration of Requests It could be beneficial to review which GitHub issues have the most thumbs-ups within a set period (e.g., quarterly or biannually) and then fix or implement them. If there are too many features or if requests have the same number of thumbs-ups, a poll could be conducted in the forum to see what the community wants implemented first. Introduce New Status Labels for Requests Under consideration In Progress Completed Faster Closure of Issues When a request is integrated, it should be closed immediately rather than marked as “completed.” Often, the requester doesn’t provide feedback or forgets to close the issue (which has happened to me as well). If something doesn’t work, the issue can be reopened. Automatically Close Stale Issues There is a stale action for GitHub that automatically closes issues after a period of inactivity. The issue creator can reopen it by responding. Better Definition of ProcessWire’s Target Audience The target audience for ProcessWire is not clearly defined. This makes it difficult to determine which features are truly necessary. Developers will likely have different requirements compared to someone looking to create a website quickly and cheaply. Developers eventually hand over the website to a client, who then manages the content themselves. Non-developers struggle to know which modules exist to manage their website. The module installation process is cumbersome, which is why I developed the ModuleManager2 years ago (link). Despite user interest, it hasn’t been widely used. There was a discussion that module installation directly through ProcessWire was rejected for security reasons (though my module only uses core methods). Integrated module management, similar to systems like WordPress, Prestashop, or Shopware, would simplify module discovery, installation, and maintenance. Discovery Process The discovery process is beneficial for all users, including power users. Sometimes I can’t remember a module’s name, but with MM2, I can search for a term in the description and find the corresponding module. Security is a concern, but I believe it’s possible to implement this in a secure way. PHP 8 and Named Arguments Finally, PHP 8 and named arguments will greatly assist in module development. Easier Customization of the Admin Theme Custom Navigation It's cumbersome to change the navigation or create a completely custom one without creating a new admin theme. This has been mentioned before (insert link). This is usually only necessary when developing custom software with ProcessWire. It would be helpful to create menu items that link to modules or specific actions within those modules, or simply a URL path. Introduce a dark mode (toggle switch). A quick solution is with one line of CSS: nightowl, but an integrated dark mode would be better. Global Media Manager A global media manager is a great idea, especially for certain assets like logos or seals used across multiple pages. While it’s possible to create a page and field to source these images, it’s not user-friendly for newcomers. For instance, I have a client with 30 product pages that require seals to be updated annually. A central management point would simplify this process. I’ve implemented this for my client, but it’s challenging for those accustomed to systems like WordPress and conceptually difficult to grasp. Aligning with Conventions from Other Frameworks Environment Configuration A .env file to store database connections, httpHosts, etc., which are read by site/config.php and site/config-dev.php. The config-dev.php file should include config.php and allow properties to be modified/overridden. This is how I and others currently do it (insert reference). Automated Deployments and Module Updates Composer is a stable package manager for PHP and a convention widely used in the PHP community, making automated deployments and updates easier. Built-In SEO Built-in rudimentary SEO would be a significant plus for websites. During installation, users could choose between a website or custom software without a frontend. If they choose a website, either ProcessWire-Core-SEO or the SEOMaestro module could be selected for installation. Lack of Visibility on ProcessWire Adoption There is no clear overview of how widely ProcessWire is adopted, such as the number of installations. This lack of visibility can make it difficult to gauge the platform's popularity and growth. Absence of a Marketplace Ecosystem The absence of a marketplace ecosystem makes it uncertain for module developers like Bernhard or myself to determine whether and how much money can be made from developing modules for ProcessWire. Other systems like Kirby, Statamic, and WordPress have a store that can be accessed directly through the admin interface. These stores also include license management, making it easier for developers to monetize their work and for users to manage their purchases. Proposed Marketplace and Revenue Sharing One idea could be to introduce a marketplace for ProcessWire, where a portion of the revenue from sales is reinvested into the development of ProcessWire. However, this is not a necessity and should be a point of discussion, considering the controversies seen with Epic or the Apple Store.
    2 points
  8. @Jonathan Lahijani I'd need specific examples to respond to or questions to answer. This is a fully built out profile. I think some might expect that I would classify/objectify everything, but I don't do that unless there's a strong reason for doing so. I use classes when there's an OO reason for doing so, and rarely is "group of related functions" one of those reasons, unless for sharing and extending. Using custom page classes or OOP is not at all necessary for most installations. It's only when you get into building larger applications that you might benefit from these things. And even then, it's not technically necessary. One good reason to use custom Page classes is just to have a documented or enforceable type, with no need to have any code in the actual class: /** * @property string $title * @property float $price * @property PageArray|CategoryPage[] $categories * @property string $body * @property Pageimages $photos */ class ProductPage extends Page {} If you add something to the class, it might be to add an API for the type's content that reduces the redundant code you'd need when outputting it. class ProductPage extends Page { /** * Get featured photo for product * * @return Pageimage|null * */ public function featuredPhoto() { $photos = $this->photos; if($photos->count()) return $photos->first(); foreach($this->categories as $category) { $photo = $category->photos->first(); if($photo) break; } return $photo; } } I'd like that too. Maybe "buy" is a longer term goal, but shorter term I'd be interested in suggestions for how best to help promote others modules. @bernhard There's no need to use OOP in ProcessWire, especially for someone new to it. ProcessWire does all the work to make sure that by the time your template file is called, you are output ready. So it's only once you get to be more advanced that you might then start using hooks, and you might never use OOP. If someone wants to add a hook, the most reliable place for that is the /site/ready.php file, or in some file that you include from it (conditionally or otherwise), and that's what I'd recommend. ProcessWire wouldn't even load your ProductPage.php file if no instance was created. But even if it did, why would there be a need for any hooks related to page class "ProductPage" if no page of the type is ever loaded? Maybe I'm missing something. You already know I'm skeptical of hooks being added by Page objects, but now we're talking about hooks that aren't even related to the page class being within it? ? If there are, they still wouldn't be called unless something triggered PW to load the ProductPage.php file. And the primarily reason it would load the file is to create an instance of the class. That makes sense. For most I'd suggest this: $wire->addHook('Pages::saveReady(template=product)', function($e) { // ... }); Or this if you are using custom page classes, and want to capture ProductPage and any other types that inherit from it: $wire->addHook('Pages::saveReady(<ProductPage>)', function($e) { // ... }); If conditional for the requested $page, then wrap the call in an if() if($page->template->name === 'product') { $wire->addHook(...); } If you need to hook the same method for multiple types, it can be more efficient to capture them all with one hook. Maybe you want it to call a saveReady() method on any custom Page classes that have added it. Since you wanted hook type code in the Page class, here's how you could do it without having hooks going into the Page class: $pages->addHook('saveReady', function($e) { $page = $e->arguments(0); if(method_exists($page, 'saveReady') $page->saveReady(); }); Rather than more initialization methods, if you needed hook-related implementation in the custom Page class, the above is the sort of thing that I think would be better. At this point, it's only about being "ready to save THIS instance of the page" which I'd have no concerns about. I could even see the core supporting this so that you could just add a saveReady() or saved() method to the custom Page class, and neither you or the core would even need to use hooks. But back to hooks, if you don't want to load up your /site/ready.php with code, maybe just use ready.php as the gatekeeper and organize them how you want. If you only need hooks for the admin, maybe put them in /site/templates/admin.php. If you want to maintain groups of hooks dedicated one type or another, put them in another file that you include from your ready.php file: include('./hooks/product.php'); I understand you like to maintain these things in or alongside your Page class files. Your MyCustomPage.php class file is one that might be suitable because those hooks won't get added unless an instance of the class is created, or something does a class_exists('ProcessWire\ProductPage'). I think you did something like the following in an earlier example, and it's just fine because it's independent of any instance and doesn't add pointers into any specific instance, and will only ever get added once: class ProductPage extends Page {} $wire->addHook(...); Or maybe you want the hooks in a separate related but dedicated file. It would have the same benefits as the previous example, but isolated to a separate file: class ProductPage extends Page { public function wired() { require_once(__DIR__ . '/ProductPageHooks.php'); parent::wired(); } } Maybe you want to do it for all classes that extend BasePage.php. Or you could use a trait, but here's an example using inheritance: // site/classes/BasePage.php class BasePage extends Page { public function wired() { parent::wired(); $f = __DIR__ . '/' . $this->className() . 'Hooks.php'; if(file_exists($f)) require_once($f); } } // /site/classes/ProductPage.php class ProductPage extends BasePage {} The word "trivial" means "of little value or importance" and I wouldn't agree with that classification of these files. But I think you might (?) mean that it's really "basic/simple" (which is meaning I think of sometimes too), and that's actually the goal of it, so I would agree with that classification.
    2 points
  9. Full ack. I’ve long appreciated and admired the tasteful restraint with which Ryan has been steering the project all these years, but even so, PW has accumulated some features/concepts that could still use some love. The custom page classes being one hotly discussed example recently. A lot of the suggestions here would make for great third-party modules. If we want more module developers and more core contributors, an official test suite may be helpful, as would better docs and more developer relations like this (also possibly someone deranged spamming memes on twitter every 10 minutes). Obviously I say this with two hearts beating in my chest, because we all know the failure modes of playing these engagement-chasing games and of large communities in general. Regarding database abstraction, to be a little flippant, if I wanted to pay for or manage that kind of hosting, I would be building on ASP.Net Core and not use an insane language where 0 == null. I’m here because PW runs on little shared hosting plans for less than a cappuccino a month, I think a lot of us are, and as much as that sort of thing is derided and reported dead, it’s an okay niche to serve. (No hate here, I love Carson Gross, .Net, PHP and everything) It’s an absolute travesty that this sort of thing isn’t a browser feature. At least give us date ranges already.
    2 points
  10. A Fieldtype for dynamic options that are generated at runtime via a hook. Configuration Inputfield type You can choose from a range of inputfield types on the Details tab of a Dynamic Options field. Your field will return a string or an array depending on if the selected input field type is for "single item selection" or "multiple item selection". Maximum number of items You can define a maximum number of items the field is allowed to contain. The core inputfields supported by this module will become disabled once the limit is reached. This option is only applicable if you have selected an inputfield type that is for multiple item selection. Format as Pagefile/Pageimage object(s) If the field will store paths/URLs to Pagefiles/Pageimages then you can enable this option to have the formatted value be a Pagefile/Pageimage object for "single" fields or an array of Pagefile/Pageimage objects for "multiple" fields. There is a related Select Images inputfield module that allows you to visually select image thumbnails. Defining selectable options Selectable options for a Dynamic Options field should be set in a FieldtypeDynamicOptions::getSelectableOptions hook in /site/ready.php. The hook should return an array of options as 'value' => 'label'. An example hook is shown on the Details tab of a Dynamic Options field: $wire->addHookAfter('FieldtypeDynamicOptions::getSelectableOptions', function(HookEvent $event) { // The page being edited $page = $event->arguments(0); // The Dynamic Options field $field = $event->arguments(1); if($field->name === 'your_field_name') { $event->return = [ 'red' => 'Red', 'green' => 'Green', 'blue' => 'Blue', ]; } }); Formatted value If a Dynamic Options field uses a "single" input type then its formatted value is a string, and if it uses a "multiple" input type then its formatted value is an array. The unformatted value of a Dynamic Options field is always an array. Also see the Configuration section above for description of an option to have the formatted value be Pagefile/Pageimage object(s). Examples of possible uses $wire->addHookAfter('FieldtypeDynamicOptions::getSelectableOptions', function(HookEvent $event) { // The page being edited $page = $event->arguments(0); // The Dynamic Options field $field = $event->arguments(1); // Select from the "files" field on the page if($field->name === 'select_files') { $options = []; foreach($page->files as $file) { // Value is basename, label is description if one exists $options[$file->basename] = $file->get('description|basename'); } $event->return = $options; } // Select from files in a folder if($field->name === 'select_folder_files') { $options = []; $path = $event->wire()->config->paths->root . 'my-folder/'; $files = $event->wire()->files->find($path); foreach($files as $file) { // Value is full path, label is basename $options[$file] = str_replace($path, '', $file); } $event->return = $options; } // Select from non-system templates if($field->name === 'select_template') { $options = []; foreach($event->wire()->templates as $template) { if($template->flags & Template::flagSystem) continue; $options[$template->id] = $template->name; } $event->return = $options; } // Select from non-system fields if($field->name === 'select_field') { $options = []; foreach($event->wire()->fields as $field) { if($field->flags & Field::flagSystem) continue; $options[$field->id] = $field->name; } $event->return = $options; } // Select from FormBuilder forms if($field->name === 'select_formbuilder_form') { $form_names = $event->wire()->forms->getFormNames(); // Use form names as both keys and values $event->return = array_combine($form_names, $form_names); } }); https://github.com/Toutouwai/FieldtypeDynamicOptions https://processwire.com/modules/fieldtype-dynamic-options/
    1 point
  11. Hey folks! Took a couple of late nights, but managed to turn this old gist of mine into a proper module. The name is SearchEngine, and currently it provides support for indexing page contents (into a hidden textarea field created automatically), and also includes a helper feature ("Finder") for querying said contents. No fancy features like stemming here yet, but something along those lines might be added later if it seems useful (and if I find a decent implementation to integrate). Though the API and selector engine make it really easy to create site search pages, I pretty much always end up duplicating the same features from site to site. Also – since it takes a bit of extra time – it's tempting to skip over some accessibility related things, and leave features like text highlighting out. Overall I think it makes sense to bundle all that into a module, which can then be reused over and over again ? Note: markup generation is not yet built into the module, which is why the examples below use PageArray::render() method to produce a simple list of results. This will be added later on, as a part of the same module or a separate Markup module. There's also no fancy JS API or anything like that (yet). This is an early release, so be kind – I got the find feature working last night (or perhaps this morning), and some final tweaks and updates were made just an hour ago ? GitHub repository: https://github.com/teppokoivula/SearchEngine Modules directory: https://modules.processwire.com/modules/search-engine/ Demo: https://wireframe-framework.com/search/ Usage Install SearchEngine module. Note: the module will automatically create an index field install time, so be sure to define a custom field (via site config) before installation if you don't want it to be called "search_index". You can change the field name later as well, but you'll have to update the "index_field" option in site config or module settings (in Admin) after renaming it. Add the site search index field to templates you want to make searchable. Use selectors to query values in site search index. Note: you can use any operator for your selectors, you will likely find the '=' and '%=' operators most useful here. You can read more about selector operators from ProcessWire's documentation. Options By default the module will create a search index field called 'search_index' and store values from Page fields title, headline, summary, and body to said index field when a page is saved. You can modify this behaviour (field name and/or indexed page fields) either via the Module config screen in the PocessWire Admin, or by defining $config->SearchEngine array in your site config file or other applicable location: $config->SearchEngine = [ 'index_field' => 'search_index', 'indexed_fields' => [ 'title', 'headline', 'summary', 'body', ], 'prefixes' => [ 'link' => 'link:', ], 'find_args' => [ 'limit' => 25, 'sort' => 'sort', 'operator' => '%=', 'query_param' => null, 'selector_extra' => '', ], ]; You can access the search index field just like any other ProcessWire field with selectors: if ($q = $sanitizer->selectorValue($input->get->q)) { $results = $pages->find('search_index%=' . $query_string . ', limit=25'); echo $results->render(); echo $results->renderPager(); } Alternatively you can delegate the find operation to the SearchEngine module: $query = $modules->get('SearchEngine')->find($input->get->q); echo $query->resultsString; // alias for $query->results->render() echo $query->pager; // alias for $query->results->renderPager() Requirements ProcessWire >= 3.0.112 PHP >= 7.1.0 Note: later versions of the module may require Composer, or alternatively some additional features may require installing via Composer. This is still under consideration – so far there's nothing here that would really depend on it, but advanced features like stemming most likely would. Installing It's the usual thing: download or clone the SearchEngine directory into your /site/modules/ directory and install via Admin. Alternatively you can install SearchEngine with Composer by executing composer require teppokoivula/search-engine in your site directory.
    1 point
  12. I thought I would share this as I am finding it increasingly useful and am often using it to replace the standard PW modal. It allows display and customisation of admin page in front end as well as back end via a modal. In the modules library at https://processwire.com/modules/admin-in-modal/ . Also here https://github.com/MetaTunes/AdminInModal This module provides a Page hook method ($page->aim($array)) for front-end use and a similar Inputfield hook (for back-end use) to render a link to a lightbox modal containing an admin page. Optionally, class styling can be passed, otherwise default button styling is supplied. Full list of options and defaults for the array is : 'href' => null, // the url for the linked page (including any required GET params) 'text' => '##', // the text that will appear in the link 'class' => "uk-button uk-button-primary", // any suitable styling for an <a> tag 'width' => '90%', // size for iframe 'height' => '95%', 'header-text' => 'Save required changes before closing -->', // Text to appear above top left of modal 'save-head-button' => '1', // Adds a save button at the top of the modal. Set to '0' to omit. 'suppress-notices' => 'messages', // e.g. null/[]: no suppression, 'messages': suppress messages, 'warnings messages': suppress warnings & messages, 'errors': suppress errors 'close-button' => '1', // set to '0' to remove close button (but you'd better be sure you know how the modal will be closed!) 'redirect' => '.', // url to redirect to after closing the modal - default is to reload the current page (use redirect => '' to suppress) (From v0.3.0, these defaults can be configured in the module settings). For front-end use, the lightbox will only be rendered if the page is editable by the current user. Configure editability of the page by calling a hook after User::hasPagePermission The lightbox is provided by the Magnific popup, which is in the PW core. Although I have used it quite a lot, I cannot say that it has been fully tested, so is alpha at this stage and should be used with care. It is the user's responsibility to check that it suits their needs. Because it allows access to the admin back-end, particular care should be taken to restrict page-edit access.
    1 point
  13. Overview The TextformatterTokens module allows other modules to register tokens and replace them with actual values. Installation Enable the TextformatterTokens module. Enable the SiteTokens module. Enable the TextformatterTokens text formatter for a field. Usage Use tokens provided by the SiteTokens module inside a field that has the TextformatterTokens text formatter enabled. Save and display your page. The tokens should be replaced with the actual content. Example Tokens [site:name] [page id=123] where id is the ID of the page you want to embed its body field. Debugging You can view logs under your ProcessWire admin dashboard at Setup > Logs > tokens. Writing own tokens To create custom tokens, refer to the SiteTokens.module file for an example implementation.
    1 point
  14. See my query here: My solution was to bulid my own module - HannaMigrate. Basically it exports or imports all Hanna codes in a database. It was built to use along with my migration module ProcessDbMigrate, but should operate without it (but not tested). It provides 2 methods exportAll() and importAll() Simple usage: Install the module. Use TracyDebugger console in the source database to: $hannaMig = $modules->get('HannaMigrate'); $hannaMig->exportAll('optional_migration_name'); where optional_migration_name is a name of a related migration, if you are using ProcessDbMigrate. Otherwise leave blank and the code will be in assets/migrations/hanna-codes/. Then use TracyDebugger console in the target database to: $hannaMig = $modules->get('HannaMigrate'); $hannaMig->importAll('optional_migration_name'); (Do this while on the Hanna Codes page, then refresh the page to see the results and any error messages). You could also use the methods in your own code. I may look to integrating it more fully in ProcessDbMigrate.
    1 point
  15. ...you can instead do... has_parent!=/foo/|/bar/|/baz/ Long time ago, but another gem from @Robin S!
    1 point
  16. The cleanest way to do this currently is handling the request and preparing data inside /site/templates/home.php (controller) and then including a view from /site/templates/views/home.php. Using modules such as TemplateEngineFactory, this becomes the default. Prepare data in a PHP file, then render a Twig/Smarty/Latte view. It's certainly not as clean as having a proper controller class pattern available, that's for sure, but it's a pattern that works across projects of all sizes (at least in my experience).
    1 point
  17. It's not quite as simple as a user being unpublished - it could be changes to the account pages referencing them as well and it's multiple different templates. The other reason for this approach is that I want to continue to alert users with a wire()->warning which wouldn't persist if I hooked on unpublished or changes to those other pages. Same kinda goes for emails or other alerts - I feel like this one needs to be a constant reminder. Perhaps a better approach would be to prevent unpublishing any user tied to an account page and prevent saving an account page unless a valid published user is selected. So many options :)
    1 point
  18. @ryanThank you very much for the code examples you provided for possible hook options related to PageClasses. Personally like the idea of including a page related hook file following the naming convention concept of PageClasses like PageNameHook.php. Will try some of those concepts soon in a real world project I am working on right now.
    1 point
  19. Hi everyone ? I have just updated and streamlined my own local development experience. Most importantly, I used to have a custom Dockerfile which resulted in a custom image for every project I ran locally. This has now changed! There is now a GitHub template repository tailored to local development: https://github.com/poljpocket/processwire-docker. This has everything you need to start developing locally on Docker. Some of the features: The composition is set up so that the site folder is fully accessible on the host. You can use any site profile upon first installation. The actual install of ProcessWire is still manual though. I found that there is little benefit in automating this. You can export the database to commit it into your repo and can also import it after pulling changes from upstream. The comp uses my new image for ProcessWire which I just published to Docker Hub: https://hub.docker.com/r/poljpocket/processwire. It uses PHP8.2 via Apache and includes all the PHP extensions needed for ProcessWire. You can find the GitHub repo for it here: https://github.com/poljpocket/processwire-docker-image. There are images for the three most recent stable versions of ProcessWire (210, 227 and 229). Important: I didn't care about security and hardening of the image. It is really only meant for local development. Have fun with it! Any requests and reports are welcome ?, thank you.
    1 point
  20. Yeah it's clear now that I was confusing RockPageBuilder with RepeaterMatrix. I probably saw the conversation in its early stages and that's why I wasn't finding anything. At some point I hacked the file selector module to a similar effect. The user experience was great, but it was a pain to set up using the standard repeater module (had to add all possible fields and then control visibility of each one depending on the chosen file). Eventually I started using RepeaterMatrix instead. I might have a look at Rock's module in a future project, as this one's too far ahead in development and it's hard to add the cost now.
    1 point
  21. It's long overdue for a refresh of a personal website. At least it was built on the fantastic ProcessWire! Pats website awkwardly. I gave this poor thing a makeover before it got mistaken for a museum exhibit. I hope for positive comments, but I would rather listen to what the critics say to improve. It is not yet tweaked to the details (I am on the heroin run for the proper images for service pages), but it is something I can brag about. Here is the link: Digital Marketing Montenegro
    1 point
  22. With regards to SEO related features, I think that being natively built in to ProcessWire is not the best choice as it goes against the unopinionated nature of ProcessWire. If one were to develop a webapp where SEO is not necessary, those fields would cause bloat. But if this were to be an official Profield, it would be wonderful. Personally, I use the FieldsetGroup Pro field (I gave SEOMaestro a try but it didn't work the way I liked), but since that's now legacy, I will have to switch my approach at some point in the future. It looks like this (note: it used to have XML sitemap fields as well, however when WireSitemapXML came out, I removed them and let that module handle it): If there were to be an new SEO module similar to my screenshot (meaning it supports fields for X, Facebook and other social networks), I would hope it's not officially called "FieldtypeSEO" but rather something like "FieldtypePresence" (ChatGPT helped me with that one) since it's more fitting (it helps improve your site's "presence" via search engines and social media networks). Personally I dislike the word SEO as it represents a lot of what's wrong with the internet and the snake-oil behind it.
    1 point
  23. Please no ? To elaborate, there are a couple of issues with this: Depending on how this is implemented, it could be a major turn-off for users like me, who have never (and likely will never) click that "download" link on the website, let alone use a configuration tool to get a download package. Most of the time I'm installing ProcessWire via Composer or by cloning it via Git, and obviously my wish would be that this process isn't made more complicated. On the other hand I've seen some users (beginners) kind of trip on things like "you'll have to install a module to get Repeaters working" or "you need to get a separate site profile". As such, I don't think this would necessarily be a good idea considering new users either. A configuration tool would likely be interesting mostly for advanced users, who know exactly what they want... and prefer to use a download link on a website to get it, which (I would assume) somewhat limits its usefulness. That being said, as long as I can still get a "viable" version of ProcessWire (most of what's currently in the core, and future additions as well, assuming that they are meaningful ones — which they undoubtedly will be!) without having to use a configuration tool, I of course don't mind if it is added as an additional option. If someone likes that kind of thing, then great, why not! Also if this would mean that non-essential core modules could be also installed one by one via Composer, that would be nice ? What I'm missing here is the context: is this about getting a smaller downloadable package? Is that still a thing, e.g. is it really a problem for many users? Serious question, because I really don't know. I care a lot about performance on websites, but have never considered the download size of a CMS I'm using; unless it's in gigabyte range or something crazy like that. Or is it about dropping support for some core features? I'm not getting that vibe from here either, but that would make more sense to me, though in that case it might be better to just drop them from the core and perhaps find new maintainers for the packages if possible ? Or is there some other benefit I'm missing?
    1 point
  24. Thank you for all of the valuable comments last week! I'll reply to several of the comments soon in last week's thread. A couple months ago a new addHeaderAction() method was added to to our Inputfields JS API, enabling you to add custom header icon actions to any Inputfield (more details here). A short while later, the same method was added to our Inputfield PHP API. This week it's been expanded so that now you can also add drop down menu header actions to Inputfield, like the one in the screenshot below. Though this is just a simple example: Here's how we defined that action and menu in JS: $f = Inputfields.get('checkboxes_field_name'); Inputfields.addHeaderAction($f, { name: 'tools', icon: 'fa-wrench', tooltip: 'Select or unselect all', menuItems: [ { name: 'select-all', label: 'Select all', icon: 'fa-check-square-o', // called when the user clicks on the action callback: function() { $f.find('input[type=checkbox]').prop('checked', true); $f.trigger('change'); }, // called to determine whether action is available to click on (optional) active: function() { return $f.find('input[type=checkbox]').not(':checked').length > 0; } }, { name: 'unselect-all', label: 'Unselect all', icon: 'fa-square-o', callback: function() { $f.find('input[type=checkbox]').prop('checked', false); $f.trigger('change'); }, active: function() { return $f.find('input[type=checkbox]:checked').length > 0; } } ] }); For more details on the options, see documentation here in the inputfields.js file where the addHeaderAction() function is defined. How does that JS code get called in the admin in the first place? Well there's a lot of different ways you could do that, but in my case, I hooked after ProcessPageEdit::loadPage in my /site/templates/admin.php file and added a custom .js file (containing the code above): $wire->addHookAfter('ProcessPageEdit::loadPage', function(HookEvent $e) { $page = $e->return; /** @var Page $page */ $config = $e->wire()->config; if($page->template->name === 'tour') { $config->scripts->add($config->urls->templates . 'scripts/admin-tour.js'; } }); Have a great weekend!
    1 point
  25. Oh heck yeah. This is awesome.
    1 point
  26. Elementor is not part of Wordpress, but a plugin developed by someone else to run in WordPress. Maybe this is an opportunity for someone in ProcessWire. And there are already RockPageBuilder and PageGRID in ProcessWire to consider as well. The dominance of WordPress has always been the case, and it will likely continue to be the case. ProcessWire is unique and has always been something completely different from WordPress. The CMS projects that are trying to mirror WordPress never seem to last long because, if you want something like WordPress, then why not just use WordPress? Though I don't know anyone that really knows both well who prefers to develop in WordPress. Instead, WordPress dominance is largely a matter of name familiarity with clients, which is completely understandable. But there are also several things it genuinely does well, and I always believe in using the best tool for the job. If the types of projects you work on are a good match for WordPress, then great, but I hope you also have projects that are a good match for ProcessWire as well. ProcessWire fully supports it. Many (most?) of us is have used exclusively on new installations for years. I don't know what those are. it sounds like another opportunity for modules. But more info needed. Good idea. This is something I think I can do. Can you describe further? In the majority of cases, older modules will still work fine. I'm not aware of anything in the modules directory that does not work, but if any become apparent I will remove them. Maybe it would be a good community effort to identify modules that could be removed from the directory. I think this might turn off as many people as it turns on. I know I wouldn't like it. But if it can be automated as an installation option then sure, why not. ProcessWire already supports WEBP and has for awhile. I was working on core AVIF support, but Robin S. released an AVIF module so I put mine on the back burner. And this may be the sort of thing that is better as a module, or maybe it'll be better in the core at some point, I'm not sure. Right now we don't build core versions in a way that breaks things from one to another. At least not in a way that is known at the time of assigning a version number. When that changes, I think we'll want to adopt semantic versioning, and maybe that's a part of 4.x. Maybe it would benefit 3rd party modules more in the shorter term, so it's worth looking at there first. Sounds interesting but I need more details. If there's anyone that is an nginx expert that wants to step up to have this responsibility I'd welcome it. I've mentioned this before too, but nobody has stepped up. I'm not an nginx expert so don't feel qualified to support it on my own. For real? This is the first I've heard of any chaos. Good to hear. We do have the PageAutosave module which does Live Preview even better than ProDrafts. This module is available in ProDevTools or ProDrafts boards, but maybe it can have a wider release. This is exactly the sort of thing that PW is great at supporting already. But I have been exploring building an everything-SEO module here, as it's something I'd like to use and support, but just not as part of the core. The hard-core SEO experts will still want to do their own SEO stuff like they do now, but for those that want something they can turn-key and have it all ready, a module is ideal. I'll very likely be building one within the next year hopefully.
    1 point
  27. ProFields Table gets a ton of love, perhaps the most of any module I develop currently, as I work with in every single day. I looked at all of the threads you linked. The first linked thread has been waiting for your reply for awhile, and the last one is already in the GitHub queue. In the others, I'm seeing feature requests as well as some back-and-forth between us about one behavior or another, but none appear to be actual bugs. If you disagree on one or another, drop a reply to bump it in the relevant thread. I try to focus on features that will benefit the largest audience. Following that I do try to add support for new selector features and things of the sort you've mentioned. Sometimes folks ask for things that might take more time than I have to implement and might only be used by one person, so I have to be selective in what gets added when, whether in Table, the core or any other modules. Generally if someone needs one particular feature and it won't take a lot of time to implement then I do try to implement when the request comes in. If I've not yet implemented something you want then it's more than likely just a matter of not having the time to do it immediately. That doesn't mean I don't love you, it just means I'm working within the resources I have.
    1 point
  28. @ryan - can I also kindly suggest that Profields Table needs some love. There are lots of weird bugs as well as some things that I think would really improve the experience. In my eyes this is THE banner profield that really demonstrates what PW can do, but is not quite working as it should. eg (in no particular order): https://github.com/processwire/processwire-issues/issues/1947
    1 point
  29. I lost 85% of our clients to WordPress due to page builders like Elementor. They aren't concerned with code clutter, page speed and SEO disadvantages. I would love some offerings in that direction, I am aware that this maybe will open Pandora's box. Some praise here for ProcessWire: ProcessWire is unbeatable for websites that almost work as applications. We coded the whole backend office management for our web design firm with ProcessWire including tons of SEO-, Data protection-monitoring- and wp-plugin-updates-montitoring crawlers and checkers: We kind of remote control WordPress from ProcessWire. Clients can log in and see everything they booked at a glance, and can order things directly from ProcessWire, and it is directly connected to the invoicing app. This is a unique system, 10 years of work in it and now makes the entire company manageable by a minimal team, unthinkable without ProcessWire. Thinks I would like in PW4 are things I am used to from WordPress, a full switch to utf8mb4, those needed GDPR utilities out of the box, modules can be "deactivated" leaving the settings intact, and "removed" to make troubleshooting modules compatibility issues much easier. Some image optimization capabilities would be great, the existing 3rd party modules do not meet our expectations yet. Also a good monitoring/curation of outdated/abandoned modules, with supplied warnings, would be great; there are a lot of those old modules, unfortunately.
    1 point
  30. I would like to see SEO support integrated into PW by default. I know that there is the SEO Maestro module, which is fabulous, but I think every CMS should have a good SEO support by default. So it would be great if a new tab will be added to the pages like this: In addition to this, there should be a new property inside the configuration file to disable/enable the tab globally in the way like this. $config->seo = false; // or true And in the settings of the page, there could be a checkbox to enable/disable the SEO tab per page. The content of the SEO tab could be as it is in the SEO Maestro module.
    1 point
  31. With huge amounts of gratitude for everything you do to make PW as great as it is: I know this is not in the intended spirit of this thread, so apologies for that, but honestly what I would most like to see is fixing all of the current Github Issues before anything new is implemented. I personally still have 49 open issues, many of which require ugly hook workarounds, some result in things being broken for site editors, and others are inconsistencies in the API which continue to trip me up. I am honestly struggling to put energy into thinking of shiny new feature ideas with these things always impacting my workflow.
    1 point
  32. No question, ProcessWire is fabulous for developers and the suggestions above would make it even better. Customers who are not developers are increasingly giving me feedback about how unintuitive the backend admin/editor is, especially now with the proliferation of DIY pagebuilders. Clients don't understand or care about the consequences. They care about not having to learn code to easily update their sites. They want the backend to look similar to the frontend, the convenience of doing it themselves without having to pay a developer. Too bad if the site doesn't work on all screen sizes, light/dark modes, isn't accessible, the home page looks like a ransom note, whatever. They genuinely don't like the default PW admin UI/UX. Pagegrid and RockPageBuilder modules are leading the way to solve this issue. Kudos to both developers BUT the modules are premium while a WP site gives customers basic WYSIWG page editing out of the box. My vote is to overhaul the admin UI/UX to make editing pages more WYSIWIG.
    1 point
  33. This module provides Captcha functionality to ProcessWire. This specific captcha uses a puzzle that has to be solved by pulling the slider into the correct position. In contrast to other graphical captchas, this captcha also verifies the result on the server side. No jQuery is required. Only PHP and JavaScript. After module installation the source code in the page has to be modified as described in the following 3 examples. Example 1 This example shows, how to use the captcha with a form-submit and the captcha on the submit-button. Insert a onclick-listener in the button-tag: <button onclick="javascript:captcha('testform');return false;">Submit</button> Add the JavaScript: <script> function captcha(form) { slideCaptcha.onsuccess(function () { document.getElementById(form).submit(); slideCaptcha.hide(); slideCaptcha.refresh(); }); slideCaptcha.init(); slideCaptcha.show(); } </script> The form is not submitted by clicking on the button. Instead, the captcha is displayed. If the captcha has been solved correctly, the form is submitted. Check again on the server side, whether the captcha has really been solved: <?php session_start(); if ((isset($_POST['send'])) && ($_POST['send'] == '1')) { if ((isset($_SESSION['SlideCaptchaOk'])) && ($_SESSION['SlideCaptchaOk'] == 'ok')) { unset($_SESSION['SlideCaptchaOk']); echo '<p style="color:lime">Form submit received: Captcha solved</p>'; } else { echo '<p style="color:red">Form submit received: Captcha NOT solved.</p>'; } } ?> Example 2 This example shows, how to use the captcha with a form-submit and the captcha on a checkbox. Insert a onclick-listener in the checkbox-tag: <input id="id_checkbox" type="checkbox" required="required" onclick="javascript:captcha('id_checkbox');return false;" /> Add the JavaScript: <script> function captcha(checkbox) { slideCaptcha.init(); slideCaptcha.show(); slideCaptcha.onsuccess(function () { document.getElementById(checkbox).checked = true; slideCaptcha.hide(); slideCaptcha.refresh(); }); } </script> By using the required option inside the checkbox-tag, the form can only be submitted when the checkbox is checked. By clicking on the checkbox, the captcha is displayed. If the captcha has been solved correctly, the checkbox will be checked and the form can be submitted. Check again on the server side, as described in example 1, whether the captcha has really been solved. Example 3 This example shows, how to use the captcha with a hyperlink. Insert a onclick-listener in the hyperlink-tag. Also move the href link into the JavaScript-function: <a href="" onclick="javascript:captcha('Example3.php');return false;">DOWNLOAD</a> Add the JavaScript: <script> function captcha(file) { slideCaptcha.onsuccess(function () { window.location.href = file; slideCaptcha.hide(); slideCaptcha.refresh(); }); slideCaptcha.init(); slideCaptcha.show(); } </script> The captcha is displayed by clicking on the hyperlink. If the captcha has been solved correctly, the JavaScript will redirect to the specified location. Check again on the server side, whether the captcha has really been solved and deliver the content: <?php session_start(); if ((isset($_SESSION['SlideCaptchaOk'])) && ($_SESSION['SlideCaptchaOk'] == 'ok')) { unset($_SESSION['SlideCaptchaOk']); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="Example3.php"'); readfile('Example3.php'); die(); } ?> Module settings The settings for this module are located in the menu Modules=>Configure=>CaptchaSlide. Filename Filename which must not exist in the root directory and also not represents a page. The filename must be also changed in the captcha.js. The resolving URL receives the information from the client side JavaScript. Tolerance Specifies a tolerance in order to offer better user experience. A tolerance of 3 means +- 3 pixel tolerance (3 recommended). Logging Logs unsolved and solved Captcha attempts in the ProcessWire system logs. Pages The JavaScript and CSS for the Captcha will be included into the following pages. Photos All photos provided by unsplash.com. As described on their website, all photos, offered on their website, can be used for free for commercial and non-commercial purposes: Link to module directory: https://processwire.com/modules/captcha-slide/ Link to github.com: https://github.com/techcnet/CaptchaSlide
    1 point
  34. This is likely more of a pro module type of thing, but I feel one area that ProcessWire is lacking from other comparable offerings out there is a site theme that is extendable and customizable from the admin backend. Tying a site-profile to the architecture of the site makes sense due to how PW is built, but being unable to switch a theme (even if temporary, to preview what the same content on a site might look like under a different skin), stylistically, after a site-profile is chosen is a little lacking. Even as a developer I like the ability to change things up now and then, but we don't really have a built-in way (that I'm aware of) a way to alter the frontend CSS via the backend using a known definition of basic templating to create themes. We can create one-off site-profiles, but not reusable themes. Maybe @bernhard is getting there with RockFrontend(?) as a third-party offering, but it would be nice to see some way that this could be supported from a (potentially optional) core (or pro) module. Similarly, I think it may be a good idea to start seriously considering alternatives to our richtext editor. I don't mean actually switching, I literally just mean considering. We switched back to TinyMCE because the newest version of CKEditor was no longer handling data in a similar way and it wouldn't be backward compatible, but TinyMCE is still handling data in the same way, but then after we switched, the company that now owns TinyMCE enacted a new licensing scheme. Although they're allowing an opensource license for now, that may not be the case, longer-term. Having a core proof-of-concept alternative (however the data is structured) would be lovely. No one wants to be caught off-guard! ? 3.1 or 4.0: If only updating the core to support PHP 8+ capabilities, a 3.1 nomenclature sounds good. If in the process of doing that there were additional and significant enough updates applied, maybe a 3.5. If attacking even more functionality, then a 4.0 seems reasonable. ?
    1 point
  35. 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.
    1 point
  36. 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.
    1 point
  37. 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
  38. @kongondo I hadn't even noticed the email customer option!! That's wicked ??
    1 point
  39. Quick demo of the 'custom shop root page' feature. Note: The option 'Hide the parent pages and their children in the page tree' will do just that. The pages will still be visible in the frontend and in the Products Dashboard. The options 'Limited page tree actions and redirect to Padloper dashboards' will display the pages in the page tree with actions that point to the pages in their respective Padloper Dashboards. E.g. 'edit' will edit the page in Padloper. Thanks.
    1 point
  40. Renewals and Resend Download Code are ready! Apologies it too longer than expected. Forms should be straightforward. Any issues, please let me know. Might need to hard reload the site for the new CSS to catch. Thanks!
    1 point
  41. I just released a new extension module AppApiPage (waits for approval), which handles the initial steps from my post above completely automatic. You install AppApi and AppApiPage. That makes the /api/page route available and you only have to add the code on top of your template php to add a custom JSON output to your pages. <?php // Check if AppApi is available: if (wire('modules')->isInstalled('AppApi')) { $module = $this->wire('modules')->get('AppApi'); // Check if page was called via AppApi if($module->isApiCall()){ // Output id & name of current page $output = [ 'id' => wire('page')->id, 'name' => wire('page')->name ]; // sendResponse will automatically convert $output to a JSON-string: AppApi::sendResponse(200, $output); } } // Here continue with your HTML-output logic... I hope that this makes it even simpler to add a full-blown JSON api to new and existing pages.
    1 point
  42. Hello all! I guess I'm a little late to the party, but here's an explanation to my AppApi approach. I basically wanted to achieve exactly the same thing with my projects as well: A universal JSON api that I make all public ProcessWire pages also queryable as JSON. For this I use the combination of my Twack module and AppApi. Twack is a component system that allows me to get a JSON output from each ProcessWire page in addition to the standard HTML output. Twack registers a route that allows to query each Page from the PageTree (via ID or Path). But for this route you don't need the Twack module, of course. As here it would work only with the AppApi module: routes.php: <?php namespace ProcessWire; require_once wire('config')->paths->AppApi . 'vendor/autoload.php'; $routes = [ 'page' => [ ['OPTIONS', '{id:\d+}', ['GET', 'POST', 'UPDATE', 'DELETE']], ['OPTIONS', '{path:.+}', ['GET', 'POST', 'UPDATE', 'DELETE']], ['OPTIONS', '', ['GET', 'POST', 'UPDATE', 'DELETE']], ['GET', '{id:\d+}', PageApiAccess::class, 'pageIDRequest'], ['GET', '{path:.+}', PageApiAccess::class, 'pagePathRequest'], ['GET', '', PageApiAccess::class, 'dashboardRequest'], ['POST', '{id:\d+}', PageApiAccess::class, 'pageIDRequest'], ['POST', '{path:.+}', PageApiAccess::class, 'pagePathRequest'], ['POST', '', PageApiAccess::class, 'dashboardRequest'], ['UPDATE', '{id:\d+}', PageApiAccess::class, 'pageIDRequest'], ['UPDATE', '{path:.+}', PageApiAccess::class, 'pagePathRequest'], ['UPDATE', '', PageApiAccess::class, 'dashboardRequest'], ['DELETE', '{id:\d+}', PageApiAccess::class, 'pageIDRequest'], ['DELETE', '{path:.+}', PageApiAccess::class, 'pagePathRequest'], ['DELETE', '', PageApiAccess::class, 'dashboardRequest'] ] ]; You can use this class to get the page-outputs: <?php namespace ProcessWire; class PageApiAccess { public static function pageIDRequest($data) { $data = AppApiHelper::checkAndSanitizeRequiredParameters($data, ['id|int']); $page = wire('pages')->get('id=' . $data->id); return self::pageRequest($page); } public static function dashboardRequest() { $page = wire('pages')->get('/'); return self::pageRequest($page); } public static function pagePathRequest($data) { $data = AppApiHelper::checkAndSanitizeRequiredParameters($data, ['path|pagePathName']); $page = wire('pages')->get('/' . $data->path); return self::pageRequest($page); } protected static function pageRequest(Page $page) { $lang = SELF::getLanguageCode(wire('input')->get->pageName('lang')); if (!empty($lang) && wire('languages')->get($lang)) { wire('user')->language = wire('languages')->get($lang); } else { wire('user')->language = wire('languages')->getDefault(); } if (!$page->viewable()) { throw new ForbiddenException(); } return $page->render(); } private static function getLanguageCode($key) { $languageCodes = [ 'de' => 'german', 'en' => 'english' ]; $code = '' . strtolower($key); if (!empty($languageCodes[$key])) { $code = $languageCodes[$key]; } return $code; } } On top of your ProcessWire-template file you have to check if an api-call is active. If so, output JSON instead of HTML: <?php // Check if AppApi is available: if (wire('modules')->isInstalled('AppApi')) { $module = $this->wire('modules')->get('AppApi'); // Check if page was called via AppApi if($module->isApiCall()){ // Output id & name of current page $output = [ 'id' => wire('page')->id, 'name' => wire('page')->name ]; // sendResponse will automatically convert $output to a JSON-string: AppApi::sendResponse(200, $output); } } // Here continue with your HTML-output logic... That should be everything necessary to enable your ProcessWire-templates to output JSON. You will have an /api/page/ endpoint, which can be called to get the JSON-outputs. /api/page/test/my-page -> ProcessWire page 'my-page' in your page-tree under test/ /api/page/42 -> ProcessWire page with id 42 /api/page/ -> root-page And a small addition: If you want to query the page files also via api, have a look at my AppApiFile module. With it you can query all images via an /api/file/ interface.
    1 point
×
×
  • Create New...