Search the Community

Showing results for tags 'Module'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Welcome to ProcessWire
    • News & Announcements
    • Showcase
    • Wishlist & Roadmap
  • Community Support
    • Getting Started
    • Tutorials
    • FAQs
    • General Support
    • API & Templates
    • Modules/Plugins
    • Themes and Profiles
    • Multi-Language Support
    • Security
    • Jobs
  • Off Topic
    • Pub
    • Dev Talk

Product Groups

  • ProDrafts
  • ListerPro
  • ProFields
  • ProCache
  • Form Builder
  • Likes
  • ProDevTools
  • Custom Development

Categories

There are no results to display.


Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Website URL


ICQ


Yahoo


Jabber


Skype


Location


Interests

Found 734 results

  1. adrian

    Hi everyone, Here's a quick little module that I hope you'll find useful. NB It requires PW 2.5.16 (or late 2.5.15 - this is the exact commit) It allows you can control display of the various Page Edit tabs by user permissions. So if you want to always hide the Settings tab for users of a particular role across all templates, this should come in handy. http://modules.processwire.com/modules/restrict-tab-view/ https://github.com/adrianbj/RestrictTabView You can approach this from two directions - hide from all users unless they have View permission, or show to all users unless they have Hide permission. It's up to you to create the permissions and assign them to roles. Let me know if you have any problems or suggestions for improvements. BTW - I am not sure how much use the Delete and View options really are in most situations, but they are there if you want them. PS Thanks to @LostKobrakai for the code in this post: https://processwire.com/talk/topic/8836-how-to-manage-delete-tab-for-user-groups/?p=85340.
  2. Hi, Thank you for the wonderful CMF. This is my first question to the PW community as I started with it. I am in the process of trying to create a module. The basic need is I want to change the content of the 404 page, if the route is something special. Eg : say the request is for http://processwire.localhost/hello and if I know the path doesn't exists I want to do something special. public function init() { $this->addHookBefore('ProcessController::execute', $this, 'someMethod'); } public function someMethod($event) { // also how do I access the $_SERVER variables from processwire point of view } Also how do I access the $_SERVER variables from a PW context. Something like $pages->get('SERVER').
  3. TemplateEngineFactory The main idea of this module is to support the developer separating logic from markup. This is achieved by turning ProcessWire templates into controllers which interact over a new API variable to template engines like Smarty or Twig. The TemplateEngineFactory ships with a default engine "ProcessWire" that uses the internal TemplateFile class to render the templates (some of you may already be familiar with this concept). However, the module is constructed in a way that any template engine can be used, implemented as separate modules. Please check out the readme on GitHub for more details how it works: https://github.com/wanze/TemplateEngineFactory ... or in the modules directory: http://modules.processwire.com/modules/template-engine-factory/ Implementation of Smarty: https://github.com/wanze/TemplateEngineSmarty Implementation of Twig: https://github.com/wanze/TemplateEngineTwig Implementation of Jade (by dreerr, thanks!): https://github.com/dreerr/TemplateEngineJade How does it work? A controller (aka ProcessWire template) can have an associated template file which contains the markup to render. The folder where those templates are stored is configurable for each installed engine. If the Factory finds a template file with the same name as the controller, an instance to access the template is provided with a new API variable (called "view" by default). Over this API variable, you can set the dynamic variables that should be rendered. Hopefully the following example makes things clearer: // In controller file: /site/templates/home.php if ($input->post->form) { // Do some processing, send mail, save data... $session->redirect('./'); } // Pass variable to the template $view->set('foo', 'bar'); $view->set('show_nav', true); $view->set('nav_pages', $pages->get('/')->children()); As you can see, there is no markup echoed out. The corresponding template file is responsible for this task: // In template file: /site/templates/view/home.php <h1><?= $page->title ?></h1> <p>Foo: <?= $foo ?></p> <?php if ($show_nav): ?> <ul> <?php foreach ($nav_pages as $p): ?> <li><a href="<?= $p->url ?>"><?= $p->title ?></a></li> <?php endforeach; ?> </ul> <?php endif; ?> In the example above, "ProcessWire" is used as engine. If Smarty is the active template engine, the corresponding template file could look like this: // In template file: /site/templates/smarty/home.tpl <h1>{$page->title}</h1> <p>Foo: {$foo}</p> {if $show_nav} <ul> {foreach $nav_pages as $p} <li><a href="{$p->url}">{$p->title}</a></li> {/foreach} </ul> {/if} Note that the API variable acts as a gateway which connects you to the activated template engine. We can switch the engine behind without changing the controller logic! (I know that this is probably not a very common need, but it's a cool thing anyway ) For further information, please check out the readmes on GitHub. Please ask questions if anything makes no sense - sometimes it's hard to get my explanations Cheers
  4. kongondo

    The Module Blog for ProcessWire replicates and extends the popular Blog Profile. Blog is now in version 2. Please read the README in the Github link below in its entirety before using this module As of 20 December 2017 ProcessWire versions earlier than 3.x are not supported Blog Documentation is here (Work in Progress!) See this post for new features in version 2 or the readme in GitHub. To upgrade from version 1, see these instructions. ################################################## Most of the text below refers to Blog version 1 (left here for posterity). Blog version 1 consists of two modules: ProcessBlog: Manage Blog in the backend/Admin. MarkupBlog: Display Blog in the frontend. Being a module, Blog can be installed in both fresh and existing sites. Note, however, that presently, ProcessBlog is not compatible with existing installs of the Blog Profile. This is because of various structural and naming differences in respect of Fields, Templates, Template Files and Pages. If there is demand for such compatibility, I will code a separate version for managing Blog Profile installs. In order to use the 'Recent Tweets Widget', you will need to separately install and setup the module 'MarkupTwitterFeed'. Please read the README in the Github link below in its entirety before using this module (especially the bit about the Pages, etc. created by the module). I'll appreciate Beta testers, thanks! Stable release works fine. Download Modules Directory: http://modules.processwire.com/modules/process-blog/ Github: https://github.com/kongondo/Blog You can also install from right within your ProcessWire install. Screenshots (Blog version 1) Video Demos ProcessBlog MarkupBlog Credits Ryan Cramer The Alpha Testers and 'Critics' License GPL2
  5. Hey guys, Thought I would share a quick preview of Designme. A module we (Eduardo @elabx and I) are building for visually laying out your templates/edit screens. This is a really quick, zero polish screen grab. FYI.
  6. tpr

    ProcessNetteTester Run Nette Tester tests within ProcessWire admin. (continued from here) Features AJAX interface for running Nette Tester tests, in bulk or manually display counter, error message and execution time in a table run all tests at once or launch single tests show formatted test error messages and report PHP syntax errors stop on first failed test (optional) hide passed tests (optional) display failed/total instead passed/total (optional) re-run failed tests only (optional) auto scroll (optional) include or exclude tests based on query parameters start/stop all tests with the spacebar reset one test or all tests (ctrl+click) https://modules.processwire.com/modules/process-nette-tester/ https://github.com/rolandtoth/ProcessNetteTester
  7. Hey guys, first, ProcessWire is a great piece of software. Thanks for that and the great community behind that. So, i'm realy new to ProcessWire, but i will present you my first module for SEO- and performance optimizing: AIOM+ (All In One Minify). AIOM+ (All In One Minify) for CSS, LESS, JS and HTML AIOM+ (All In One Minify) is a module to easily improve the performance of your website. By a simple function call Stylesheets, LESS and Javascript files can be parsed, minimized and combined into one single file. This reduces the server requests, loading time and minimizes the traffic. In addition, the generated HTML source code can be minimized and all generated files can be loaded over a cookieless domain (domain sharding). Install AIOM+ Download current release (link below) Extract and copy the files for this module to /site/modules/AllInOneMinify/ Login to PW backend and go to Modules > Check for new modules Install Module > AIOM+ (All In One Minify) for CSS, LESS, JS and HTML Alternative in ProcessWire 2.4 Login to PW backend and go to Modules Click tab "new" and enter Module Class Name: "AllInOneMinify" Click "Download and Install" Features Combining stylesheets / LESS files or JavaScripts Minimize the combined files No change to the .htaccess necessary (except for the domain sharding) Server-side LESS parsing without plugins HTML source code minimization Cookieless domain / domain sharding Automatic cache management (With changes to the source file, the cache is rebuilt) Configurable via the backend Automatic rewriting the paths in the stylesheet and LESS files. No changes are needed Optional developer mode (combining, but no minimize and browser cache prevention) Clear the cache on the backend Conditional loading for CSS, LESS and JS (since Version 3.1.1) How to use Minimize multiple stylesheet or LESS files into one file. You can even mix stylesheet and LESS files in parsing and combining process! <link rel="stylesheet" href="<?php echo AIOM::CSS(array('css/file-1.css', 'css/file-2.less', 'css/file-3.css', 'css/file-4.less')); ?>"> Minimize multiple javascript files into one file. <script src="<?php echo AIOM::JS(array('js/file-1.js', 'js/file-2.js', 'js/file-3.js', 'js/file-4.js')); ?>"></script> Conditional loading (same with Javascripts) <?php $stylesheets = array('css/reset.css', 'css/main.less', array('loadOn' => 'id|template=1002|1004|sitemap', // PW API selector 'files' => array('css/special.css', 'css/special-theme.less'))); ?> <link rel="stylesheet" type="text/css" href="<?php echo AIOM::CSS($stylesheets); ?>" /> More Information, Documentation and Download AIOM+ in ProcessWire repository AIOM+ on GitHub So, I hope you can do something with this module. Dave
  8. dadish

    NOTE: This thread originally started in the Pub section of the forum. Since we moved it into the Plugin/Modules section I edited this post to meet the guidelines but also left the original content so that the replies can make sense. ProcessGraphQL ProcessGraphQL seamlessly integrates to your ProcessWire web app and allows you to serve the GraphQL api of your existing content. You don't need to apply changes to your content or it's structure. Just choose what you want to serve via GraphQL and your API is ready. Warning: The module supports PHP version >= 5.5 and ProcessWire version >= 3. Links: Zip Download Github Repo ScreenCast PW modules Page Please refer to the Readme to learn more about how to use the module. Original post starts here... Hi Everyone! I became very interested in this GraphQL thing lately and decided to learn a bit about it. And what is the better way of learning a new thing than making a ProcessWire module out of it! For those who are wondering what GraphQL is, in short, it is an alternative to REST. I couldn't find the thread but I remember that Ryan was not very happy with the REST and did not see much value in it. He offered his own AJAX API instead, but it doesn't seem to be supported much by him, and was never published to official modules directory. While ProcessWire's API is already amazing and allows you to quickly serve your content in any format with less than ten lines of code, I think it might be convenient to install a module and have JSON access to all of your content instantly. Especially this could be useful for developers that use ProcessWire as a framework instead of CMS. GraphQL is much more flexible than REST. In fact you can build queries in GraphQL with the same patterns you do with ProcessWire API. Ok, Ok. Enough talk. Here is what the module does after just installing it into skyscrapers profile. It supports filtering via ProcessWire selectors and complex fields like FieldtypeImage or FieldtypePage. See more demo here The module is ready to be used, but there are lots of things could be added to it. Like supporting any type of fields via third party modules, authentication, permissions on field level, optimization and so on. I would love to continue to develop it further if I would only know that there is an interest in it. It would be great to hear some feedback from you. I did not open a thread in modules section of the forum because I wanted to be sure there is interest in it first. You can install and learn about it more from it's repository. It should work with PHP >=5.5 and ProcessWire 3.x.x. The support for 2.x.x version is not planned yet. Please open an issue if you find bugs or you want some features added in issue tracker. Or you can share your experience with the module here in this thread.
  9. ryan

    FieldtypeMapMarker Module for ProcessWire 2.1+ This Fieldtype for ProcessWire 2.1+ holds an address or location name, and automatically geocodes the address to latitude/longitude using Google Maps API. This Fieldtype was also created to serve as an example of creating a custom Fieldtype and Inputfield that contains multiple pieces of data. Download at: https://github.com/r...ldtypeMapMarker How to Use To use, install FieldtypeMapMarker like you would any other module (install instructions: http://processwire.c...wnload/modules/). Then create a new field that uses it. Add that field to a template and edit a page using that template. Enter an address, place or location of any sort into the 'Address' field and hit Save. For example, Google Maps will geocode any of these: 125 E. Court Square, Decatur, GA 30030 Atlanta, GA Disney World The address will be converted into latitude/longitude coordinates when you save the page. The field will also show a map of the location once it has the coordinates. On the front end, you can utilize this data for your own Google Maps (or anything else that you might need latitude/longitude for). Lets assume that your field is called 'marker'. Here is how you would access the components of it from the API: <?php echo $page->marker->address; // outputs the address you entered echo $page->marker->lat; // outputs the latitude echo $page->marker->lng; // outputs the longitude Of course, this Fieldtype works without it's Inputfield too. To geocode an address from the API, all you need to do is set or change the 'address' component of your field, i.e. <?php $page->marker->address = 'Disney Land'; $page->save(); // lat/lng will now be updated to Disney Land's lat/lng
  10. FieldtypeRuntimeMarkup and InputfieldRuntimeMarkup Modules Directory: http://modules.processwire.com/modules/fieldtype-runtime-markup/ GitHub: https://github.com/kongondo/FieldtypeRuntimeMarkup This module allows for custom markup to be dynamically (PHP) generated and output within a page's edit screen (in Admin). The value for the fieldtype is generated at runtime. No data is saved in the database. The accompanying InputfieldRuntimeMarkup is only used to render/display the markup in the page edit screen. The field's value is accessible from the ProcessWire API in the frontend like any other field, i.e. it has access to $page and $pages. The module was commissioned/sponsored by @Valan. Although there's certainly other ways to achieve what this module does, it offers a dynamic and flexible alternative to generating your own markup in a page's edit screen whilst also allowing access to that markup in the frontend. Thanks Valan! Warning/Consideration Although access to ProcessWire's Fields' admin pages is only available to Superusers, this Fieldtype will evaluate and run the custom PHP Code entered and saved in the field's settings (Details tab). Utmost care should therefore be taken in making sure your code does not perform any CRUD operations!! (unless of course that's intentional) The value for this fieldtype is generated at runtime and thus no data is stored in the database. This means that you cannot directly query a RuntimeMarkup field from $pages->find(). Usage and API Backend Enter your custom PHP snippet in the Details tab of your field (it is RECOMMENDED though that you use wireRenderFile() instead. See example below). Your code can be as simple or as complicated as you want as long as in the end you return a value that is not an array or an object or anything other than a string/integer. FieldtypeRuntimeMarkup has access to $page (the current page being edited/viewed) and $pages. A very simple example. return 'Hello'; Simple example. return $page->title; Simple example with markup. return '<h2>' . $page->title . '</h2>'; Another simple example with markup. $out = '<h1>hello '; $out .= $page->title; $out .= '</h1>'; return $out; A more advanced example. $p = $pages->get('/about-us/')->child('sort=random'); return '<p>' . $p->title . '</p>'; An even more complex example. $str =''; if($page->name == 'about-us') { $p = $page->children->last(); $str = "<h2><a href='{$p->url}'>{$p->title}</a></h2>"; } else { $str = "<h2><a href='{$page->url}'>{$page->title}</a></h2>"; } return $str; Rather than type your code directly in the Details tab of the field, it is highly recommended that you placed all your code in an external file and call that file using the core wireRenderFile() method. Taking this approach means you will be able to edit your code in your favourite text editor. It also means you will be able to type more text without having to scroll. Editing the file is also easier than editing the field. To use this approach, simply do: return wireRenderFile('name-of-file');// file will be in /site/templates/ If using ProcessWire 3.x, you will need to use namespace as follows: return ProcessWire\wireRenderFile('name-of-file'); How to access the value of RuntimeMarkup in the frontend (our field is called 'runtime_markup') Access the field on the current page (just like any other field) echo $page->runtime_markup; Access the field on another page echo $pages->get('/about-us/')->runtime_markup; Screenshots Backend Frontend
  11. Some of you might have followed the development of this module here: https://processwire.com/talk/topic/15524-previewdiscussion-rockdatatables/ . It is the successor of "RockDataTables" and requires RockFinder to get the data for the grid easily and efficiently. It uses the open source part of agGrid for grid rendering. WHY? ProcessWire is awesome for creating all kinds of custom backend applications, but where it is not so awesome in my opinion is when it comes to listing this data. Of course we have the built in page lister and we have ListerPro, but none of that solutions is capable of properly displaying large amounts of data, for example lists of revenues, aggregations, quick and easy sorts by the user, instant filter and those kind of features. RockGrid to the rescue Features/Highlights: 100k+ rows Instant (client side) filter, search, sort (different sort based on data type, eg "lower/greater than" for numbers, "contains" for strings) extendable via plugins (available plugins at the moment: fullscreen, csv export, reload, batch-processing of data, column sum/statistics, row selection) all the agGrid features (cell renderers, cell styling, pagination, column grouping etc) vanilla javascript, backend and frontend support (though not all plugins are working on the frontend yet and I don't plan to support it as long as I don't need it myself) Limitations: While there is an option to retrieve data via AJAX the actual processing of the grid (displaying, filtering, sorting) is done on the client side, meaning that you can get into troubles when handling really large datasets of several thousands of rows. agGrid should be one of the most performant grid options in the world (see the official example page with a 100k row example) and does a lot to prevent problems (such as virtual row rendering), but you should always have this limitation in mind as this is a major difference to the available lister options that do not have this limitation. Currently it only supports AdminThemeUikit and I don't plan to support any other admin theme. Download: https://gitlab.com/baumrock/RockGrid Installation: https://gitlab.com/baumrock/RockGrid/wikis/Installation Quikckstart: https://gitlab.com/baumrock/RockGrid/wikis/quickstart Further instructions: https://gitlab.com/baumrock/RockGrid/wikis/quickstart#further-instructions Module status: alpha, License: MIT Note that every installation and uninstallation sends an anonymous google analytics event to my google analytics account. If you don't want that feel free to remove the appropriate lines of code before installation/uninstallation. Contribute: You can contribute to the development of this and other modules or just say thank you by testing, reporting issues and making PRs at gitlab liking this post buying me a drink: paypal.me/baumrock/5 liking my facebook page: facebook.com/baumrock hiring me for pw work: baumrock.com Support: Please note that this module might not be as easy and plug&play as many other modules. It needs a good understanding of agGrid (and JavaScript in general) and it likely needs some looks into the code to get all the options. Please understand that I can not provide free support for every request here in the forum. I try to answer all questions that might also help others or that might improve the module but for individual requests I offer paid support for 60€ per hour. Changelog 180711 bugfix (naming issue) 180630 alpha realease Use Cases / Examples: Colored grid cells, Icons, Links etc. The Grid also has a "batcher" feature built in that helps communicating with the server via AJAX and managing resource intensive tasks in batches: Filters, PW panel links and instant reload on panel close: You can combine the grid with a chart library like I did with the (outdated) RockDataTables module:
  12. thetuningspoon

    Page Field Edit Links GitHub: https://github.com/thetuningspoon/AdminPageFieldEditLinks Direct Download: https://github.com/thetuningspoon/AdminPageFieldEditLinks/archive/master.zip This module is based on--and is the successor to--Macrura's AdminPageSelectEditLinks (https://processwire.com/talk/topic/8477-adminpageselecteditlinks-module-for-enabling-edit-links-on-multipage-selects/) Page Field Edit Links adds modal editing capability to ProcessWire's Page fields in the admin editor, allowing editors to easily view and edit the content of any page(s) that have been selected, as well as create new pages without leaving the current screen. Edit links are updated in real time when new pages are added to the field. Compatible with all available types of Inputfields including Select, SelectMultiple, Checkboxes, Radios, AsmSelect, PageListSelect, PageListSelectMultiple, and PageAutocomplete.
  13. kongondo

    Media Manager Released 31 March 2016 https://processwireshop.pw/plugins/media-manager/ Documentation (Work in Progress!) http://mediamanager.kongondo.com/ API Example (frontend; will be added to documentation site) Accessing and outputting the contents of the MediaManager field(s) in your template is quite simple. The fields are accessed like many other ProcessWire fields. The fields return an array of type MediaManagerArray that need to be looped to output each media within. Assuming you created a field of type MediaManager named 'media', you can loop through it for a given page as shown below. @note: Each MediaManager object has the following 5 basic properties: DATABASE (saved properties) 1. id => pageID of the page where the media lives (hidden in admin and not important to know about) 2. type => integer denoting media type (1=audio; 2=document; 3=image [for variations this will be 3x, where x is the number of the variation of an original image]; 4=video) RUNTIME 3. typeLabel => user friendly string denoting media type (audio, document, image, video) 4. media => a ProcessWire Image/File Object including all their properties (ext, filesizeStr, height, width, description, tags, filename, basename, etc.) 5. title => title of media (@note: this is the title of the page where the media lives; may or may not be the same as the name of the media file itself). This can be used as a user-friendly name for your media $media = $page->media;// returns a MediaManagerArray. Needs to be looped through foreach ($media as $m) { echo $m->id;// e.g. 1234 (hidden page in /admin/media-manager/media-parent/) echo $m->type;// e.g. 3 (a media of type image) OR 1 (a media of type audio) echo $m->typeLabel;// e.g. 'document' (i.e. type would be 2) echo $m->title;// e.g. 'My Nice Trip' (whose media file could be my-nice-trip.mp4) /* @note: - $m->media returns an object; either a ProcessWire Image (for image media) or File object (for audio, document and video media) - This means you have access to all the properties of that object, e.g. ext, tags, description, url, filename, basename, width, height, modified, created, filesize, filesizeStr, etc as well as associated methods, e.g. size() */ echo $m->media->tags; } // only output images foreach ($media as $m) { if($m->typeLabel =='image') { echo "<img src='" . $m->media->size(100,75)->url . "'><br>"; } } // There's also a toString() method so you can do: echo $page->media; /* All your media will be output wrapped in appropriate HTML tags, i.e.: audio: <audio></audio>; document: <a></a>; image: <img>; video: <video></video>; */ ******************************************************* ORIGINAL POST ******************************************************* The topic of a central media manager feature for ProcessWire has come up several times: https://processwire.com/talk/topic/4330-get-image-from-other-pages-via-images-field/ https://processwire.com/talk/topic/4330-get-image-from-other-pages-via-images-field/?p=42578 https://processwire.com/talk/topic/4330-get-image-from-other-pages-via-images-field/?p=42582 https://processwire.com/talk/topic/425-file-manager/ https://processwire.com/talk/topic/425-file-manager/?p=13802 https://processwire.com/talk/topic/425-file-manager/?p=13861 https://processwire.com/talk/topic/10763-asset-manager-asset-selector/ More recently, regarding my Visual Page Selector module, I have been asked several times why the module does not have an in-built feature to upload images. There's two camps on the topic of a central media manager: those who like them (especially those coming in to PW from other CMSes) and those who don't like them (primarily because of the chaotic way some CMSes (dis)organise their media management) . I think that we can have our cake and eat it too! If done the right way, closely following the principles of and harnessing the power of ProcessWire, we can have a well-implemented, organised, feature-rich, site-wide media manager. Introducing Media Manager: (a commercial module) Alongside a number of modules I am currently working on (both free and commercial), I have been developing a centralised Media Manager for ProcessWire. Before you cast the first stone, no, this is not going to be a one-large-media-bucket as in other CMS where it gets very messy very quickly . In the backend things are neatly stored away, yes, in pages. However, those are pages you will not see (just like repeater pages). Before anyone has a go at pages, remember a page is not that thing you see on the ProcessWire Tree (that's just its visual representation); A page is a record/row in the database . For the end-user of Media Manager, all they will see is the 'familiar media bucket' to select their media from. As long as it works efficiently, I don't think they care about the wizardry behind the scenes . The module allows for the comprehensive management of several media types: Audio Video Images Documents Each media type will be handled by its own sub-module so the user can pick and install/choose the type of media management they want. Features include: Access controls Centralized uploads of media Bulk management of media: tag, delete, describe, replace, etc. Bulk upload: zip; scan, single Quick upload in page edit mode Usage stats across pages (maybe?) Etc.. Would love to hear your thoughts and any feature suggestions. I think there's enough demand for such a module. If not, please let me know so that I can instead focus on other things , thanks. How other CMS do it The more efficient (PW) way of doing it
  14. Soma

    LogMaintenance A simple ProcessWire module to give some maintenance control over log files. I found myself often having lots of log files for different things that can grow more or less quickly to a size where they can be difficult to maintain. The built in Logger of PW does a good job of giving you the possibility to delete or prune logs. But it has to be done manually and sometimes a log grows into millions of lines, which makes it often impossible to even prune it as it's too large. LogMaintenance uses LazyCron to run the maintenance task and there's several settings you can setup on a global or per log basis. Archive: will create zip files for each log file in logs/archive/ folder and add the log each time the maintenance is run to a subfolder containing the datetime. Lines: keeps logs to a certain number of lines Days: keeps the log to a certain number of days Bytes: keeps the log to a certain amount of bytes Each setting is checked from top down, the first setting to contain something is used. So if you check the "Archive" option, all other settings are ignored and logs are archived everytime the LazyCron is executed. If you want to keep your logs to a certain amount of bytes just leave all other settings to 0 or blank. Per Log Settings There's a textarea that you can use to setup a config for a specific log file one per line. All the logs you define here ignore the global settings above. The syntax for the settings is: logname:[archive]:[lines]:[days]:[bytes] errors:1:0:0:0 // would archive the errors log messages:0:10000:0:0 // will prune the errors log to 10000 lines The module can be found on github for you to check out. It's still fresh and I'm currently testing. https://github.com/somatonic/LogMaintenance
  15. Robin S

    Some introduction... This module is experimental and there are probably bugs - so treat it as alpha and don't use it on production websites. I started on this module because there have been quite a few requests for "fake" or "invisible" parent functionality and I was curious about what is possible given that the idea sort of goes against the PW page structure philosophy. I'm not sure that I will use this module myself, just because I don't really see a long list of pages under Home (or anywhere else) as untidy or cluttered. I would tend to use Lister Pro when I want to see some set of pages as a self-contained group. But maybe others will find it useful. At the moment this module does not manipulate the breadcrumb menu in admin. So when you are editing or adding a virtual child the real location of the page is revealed in the breadcrumb menu. That's because I don't see the point in trying to comprehensively fool users about the real location of pages - I think it's better that they have some understanding of where the pages really are. But I'm open to feedback on this and it is possible to alter the breadcrumbs if there's a consensus that it would be better that way. Virtual Parents Allows pages in Page List to be grouped under a virtual parent. This module manipulates the page list and the flyout tree menu to make it appear that one or more pages are children of another page when in fact they are siblings of that page. Why would you do that instead of actually putting the child pages inside the parent? Mainly if you want to avoid adding the parent name as part of the URL. For example, suppose you have some pages that you want to be accessed at URLs directly off the site root: yourdomain.com/some-page/. But in the page list you want them to be appear under a parent for the sake of visual grouping or to declutter the page list under Home. Example of how the page structure actually is Example of how the page structure appears with Virtual Parents activated How it works This module identifies the virtual parents and virtual children by way of template. You define a single template as the virtual parent template and one or more templates as the virtual child templates. Anytime pages using the child template(s) are siblings of a page using the parent template, those child pages will appear as children of the virtual parent in the page list and tree menu. You will want to create dedicated templates for identifying virtual parents and virtual children and reserve them just for use with this module. Features Adjusts both page list and tree flyout menu to show the virtual parent/child structure, including the count of child pages. Works everywhere page list is used: Page List Select / Page List Select Multiple (and therefore CKEditor link dialog). Intercepts the "Add page" process in admin, so that when an attempt is made to add a child to a virtual parent, the child is added where it belongs (the next level up) and the template selection is limited to virtual child templates. Intercepts moving and sorting pages in the page list, to ensure only virtual children may be moved/sorted under the virtual parent. Superusers have a toggle switch at the bottom of the page list to easily disable/enable Virtual Parents in order to get a view of what the real page structure is. Usage Install the Virtual Parents module. In the module config, enter pairs of parent/child template names in the form virtual_parent_template=virtual_child_template. If needed you can specify multiple pipe-separated child templates: virtual_parent_template=child_template_1|child_template_2. One pair of template names per line. There is a checkbox in the module config to toggle Virtual Pages on and off, but it's more convenient to use this from the page list. Notes It's important to keep in mind the real location of the virtual child pages. This module is only concerned with adjusting the appearance of page list and tree menu for the sake of visual grouping and tidiness. In all other respects the virtual children are not children of the virtual parent at all. It's recommended to select an icon for the virtual parent template (Advanced tab) so virtual parents are marked out in the page list as being different from normal parent pages. Do not place real children under a virtual parent. There is some protection against this when moving pages in the page list, but when it comes to changing a page's parent via the Settings tab the only protection is common sense. https://github.com/Toutouwai/VirtualParents
  16. Update 2018-07-09: ProcessNetteTester module is available in the Modules Directory and on GitHub. This is a short tutorial on how to use Nette Tester with ProcessWire. As you will see it's very easy to setup and use and it's perfect for testing your code's functionality. With bootstrapping ProcessWire it's also possible to check the rendered markup of pages using the API, checking page properties, etc. It's also a great tool for module developers for writing better code. While there will be nothing extraordinary here that you couldn't find in Tester's docs this can serve as a good starting point. Prerequisites: PHP 5.6+ 01 Download Tester Go to https://github.com/nette/tester/releases and download the latest release (currently 2.0.2). Download from the link reading "Source code (zip)". You can use composer also if you wish. 02 Extract Tester files Create a new directory in your site root called "tester". Extract the zip downloaded here, so it should look like this: /site /tester/src /tester/tools /tester/appveyor.yml /tester/composer.json /tester/contributing.md /tester/license.md /tester/readme.md /wire ... 03 Create directory for test files Add a new directory in "/tester" called "tests". Tester recognizes "*.Test.php" and "*.phpt" files in the tests directory, recursively. 04 Create your first test In the "tests" directory create a new "MyTest.php" file. The first test is a very simple one that bootstraps ProcessWire and checks if the Home page name is "Home". This is not the smartest test but will show you the basics. Add this to "/tester/tests/MyTest.php": <?php namespace ProcessWire; use \Tester\Assert; use \Tester\DomQuery; use \Tester\TestCase; use \Tester\Environment; require __DIR__ . '/../src/bootstrap.php'; // load Tester require __DIR__ . '/../../index.php'; // bootstrap ProcessWire Environment::setup(); class MyTest extends TestCase { // first test (step 04) public function testHomeTitle() { $expected = 'Home'; // we expect the page title to be "Home" $actual = wire('pages')->get(1)->title; // check what's the actual title Assert::equal($expected, $actual); // check whether they are equal } // second test will go here (step 06) // third test will go here (step 07) } // run testing methods (new MyTest())->run(); I've added comment placeholders for the second and third tests that we will insert later. 05 Run Tester Tester can be run either from the command line or from the browser. The command line output is more verbose and colored while in the browser it's plain text only (see later). Running from the command line Navigate to the "/tester" directory in your console and execute this: php src/tester.php -C tests This will start "/tester/src/tester.php" and runs test files from the "/tester/tests" directory. The "-C" switch tells Tester to use the system-wide php ini file, that is required here because when bootstrapping ProcessWire you may run into errors (no php.ini file is used by default). You may load another ini file with the "-c <path>" (check the docs). If the title of your Home page is "Home" you should see this: If it's for example "Cats and Dogs", you should see this: Running from the browser First we need to create a new PHP file in ProcessWire's root, let's call it "testrunner.php". This is because ProcessWire doesn't allow to run PHP files from its "site" directory. The following code runs two test classes and produces a legible output. IRL you should probably iterate through directories to get test files (eg. with glob()), and of course it's better not allow tests go out to production. <?php ini_set('html_errors', false); header('Content-type: text/plain'); echo 'Starting tests.' . PHP_EOL; echo '--------------------------' . PHP_EOL; $file = __DIR__ . '/PATH_TO/FirstTest.php'; echo basename($file) . ' '; require $file; echo '[OK]' . PHP_EOL; $file = __DIR__ . '/PATH_TO/SecondTest.php'; echo basename($file) . ' '; require $file; echo '[OK]' . PHP_EOL; echo '--------------------------' . PHP_EOL; echo 'Tests finished.'; exit; Navigate to "DOMAIN/testrunner.php" in your browser to execute the file. If every test succeeds you should get this: If there are failed tests the execution stops and you can read the error message. If there were more tests (eg. ThirdTest), those won't be displayed under the failed test. 06 DOM test This test will check if a page with "basic-page" template has a "h1" element. We will create the page on the fly with ProcessWire's API. To keep things simple we will add the new test as a new method to our MyTest class. Add this block to the MyTest class: public function testBasicPageHeadline() { $p = new Page(); $p->template = 'basic-page'; $html = $p->render(); $dom = DomQuery::fromHtml($html); Assert::true($dom->has('h1')); } This will most likely be true but of course you can check for something more specific, for example "div#main". Note that we have used the DomQuery helper here (check the "use" statement on the top of the file). 07 Custom function test You will probably want to make sure your custom functions/methods will work as they should so let's write a test that demonstrates this. I don't want to complicate things so I'll check if the built-in "pageName" sanitizer works as expected. Add this to the myTest class: public function testPageNameSanitizer() { $expected = 'hello-world'; $actual = wire('sanitizer')->pageName('Hello world!', true); Assert::equal($expected, $actual); } This should also be true. Try to change the expected value if you are eager to see a failure message. 08 Next steps You can add more methods to the MyTest class or create new files in the "tests" directory. Check out the range of available Assertions and other features in the docs and see how they could help you writing more fail-safe code. Once you make a habit of writing tests you'll see how it can assist making your code more bulletproof and stable. Remember: test early, test often If you find out something useful or cool with Tester make sure to share.
  17. Macrura

    Basic implementation of the Simple MDE as an Inputfield. https://simplemde.com/ Module developed in reply to request from @OrganizedFellow (https://processwire.com/talk/topic/13474-found-a-handy-js-based-markdown-editor/) Modules Directory: http://modules.processwire.com/modules/inputfield-simple-mde/ Github: https://github.com/outflux3/InputfieldSimpleMDE Editor example: Preview mode: Frontend output (using Markdown/Parsedown textformatter and Image Tags) Limitations etc: This has been tested with multiple instances on 1 page and seems to work fine. Toolbar is not configurable, but you can edit the JS file; In the spirit of keeping this simple, there are no module settings. If you want the spellchecker, you can enable it in the JS file. If is seems that there is a need for configurable instances, it could be added, but so far this works fine and can't see any reason to complicate it further.
  18. I've been working on an experimental module set that adds 2-factor authentication to ProcessWire with the help of Steve Gibson's PPP one-time-pad system. This is split into two modules; a CryptoPPP library that implements the otp system and a 2-factor authentication module that uses it to add 2-factor authentication to ProcessWire. The 2-factor module adds an additional "Login Token" field to the login page into which the authenticating user will need to enter the next unused token from their one-time-pad. Pages from their pad can either be printed out in advance in a credit-card sized format (with codes being crossed out as they are used as shown here) or the required token can be sent to their registered email address so they don't need to print anything out. This second option requires a good email address be present in the user's account in order for them to be sent the token. Email Delivery To set up email delivery go to the 2-factor module's config page and choose "token delivery via email" and save the settings. Next, make sure that every user who will use the system has a valid email address set up in their account. Upon the first failed user login attempt, the required token will be emailed to the user’s email address and they should then be able to log in. Printing Pages From The Pad If you prefer to print the tokens in a handy credit-card sized format then… Go to your profile screen Expand the “PPP Initialisation Vector” field Hit the “Show Token Cards” button to open a new browser window with the next 3 useful cards Use your browser’s print option to print these out Trim them to size and store ...but make sure you print these out before you enable 2-factor authentication on your account. If you cross out your used codes, you will always know which code to use when logging back in -- and if you forget, the first login attempt will fail and the token field will then prompt you with the location of the correct code to use. Why would I ever want to use 2-factor authentication? If your site is only for you or for people you know use good passwords then you probably never will need a 2-factor authentication system. But it has been shown that many users use passwords that are, well, rubbish not very good and having a second factor can be useful in mitigating poor passwords. As the second factor in this system comes out of a one-time-pad system (meaning it will not be reused) then having the user's password leaked or guessed should not compromise their account nor will having someone spy out the token they are using to log-in as tokens are not re-used (well, not for a very long time.) Known Problems You need to hit the save button after you install the 2-factor module to get it to remember the initial settings. (I guess I'm not setting the defaults correctly at present but pressing the button will allow you to move forward for now) Uninstall of the 2-factor module leads to a lot of warnings. Attachments
  19. tpr

    AdminOnSteroids Various admin tweaks to enhance ProcessWire admin. http://modules.processwire.com/modules/admin-on-steroids/ https://github.com/rolandtoth/AdminOnSteroids
  20. This module adds a "SEO" tab to every page where you can define a special title, description, keywords, etc. Try it http://aluminum-j4f.lightningpw.com/processwire/ Name: demo Pass: demo123 How to use You can choose between include automatically or use the following methods: $config->seo // includes all the default values and configuration settings // e.g.: $config->seo->title $config->seo->keywords $page->seo // includes all the default values mixed with the page related seo data // e.g.: $page->seo->title $page->seo->keywords // for rendering: $page->seo->render . . Screenshot Download You can download it in the modules repository: http://modules.processwire.com/modules/markup-seo/
  21. Noel Boss

    Page Query Boss Build complex nested queries containing multiple fields and pages and return an array or JSON. This is useful to fetch data for SPA and PWA. You can use the Module to transform a ProcessWire Page or PageArray – even RepeaterMatrixPageArrays – into an array or JSON. Queries can be nested and contain closures as callback functions. Some field-types are transformed automatically, like Pageimages or MapMarker. Installation Via ProcessWire Backend It is recommended to install the Module via the ProcessWire admin "Modules" > "Site" > "Add New" > "Add Module from Directory" using the PageQueryBoss class name. Manually Download the files from Github or the ProcessWire repository: https://modules.processwire.com/modules/page-query-builder/ Copy all of the files for this module into /site/modules/PageQueryBoss/ Go to “Modules > Refresh” in your admin, and then click “install” for the this module. Module Methods There are two main methods: Return query as JSON $page->pageQueryJson($query); Return query as Array $page->pageQueryArray($query); Building the query The query can contain key and value pairs, or only keys. It can be nested and contain closures for dynamic values. To illustrate a short example: // simple query: $query = [ 'height', 'floors', ]; $pages->find('template=skyscraper')->pageQueryJson($query); Queries can be nested, contain page names, template names or contain functions and ProcessWire selectors: // simple query: $query = [ 'height', 'floors', 'images', // < some fileds contain default sub-queries to return data 'files' => [ // but you can also overrdide these defaults: 'filename' 'ext', 'url', ], // Assuming there are child pages with the architec template, or a // field name with a page relation to architects 'architect' => [ // sub-query 'name', 'email' ], // queries can contain closure functions that return dynamic content 'querytime' => function($parent){ return "Query for $parent->title was built ".time(); } ]; $pages->find('template=skyscraper')->pageQueryJson($query); Keys: A single fieldname; height or floors or architects The Module can handle the following fields: Strings, Dates, Integer… any default one-dimensional value Page references Pageimages Pagefiles PageArray MapMarker FieldtypeFunctional A template name; skyscraper or city Name of a child page (page.child.name=pagename); my-page-name A ProcessWire selector; template=building, floors>=25 A new name for the returned index passed by a # delimiter: // the field skyscraper will be renamed to "building": $query = ["skyscraper`#building`"] Key value pars: Any of the keys above (1-5) with an new nested sub-query array: $query = [ 'skyscraper' => [ 'height', 'floors' ], 'architect' => [ 'title', 'email' ], ] A named key and a closure function to process and return a query. The closure gets the parent object as argument: $query = [ 'architecs' => function($parent) { $architects = $parent->find('template=architect'); return $architects->arrayQuery(['name', 'email']); // or return $architects->explode('name, email'); } ] Real life example: $query = [ 'title', 'subtitle', // naming the key invitation 'template=Invitation, limit=1#invitation' => [ 'title', 'subtitle', 'body', ], // returns global speakers and local ones... 'speakers' => function($page){ $speakers = $page->speaker_relation; $speakers = $speakers->prepend(wire('pages')->find('template=Speaker, global=1, sort=-id')); // build a query of the speakers with return $speakers->arrayQuery([ 'title#name', // rename title field to name 'subtitle#ministry', // rename subtitle field to ministry 'links' => [ 'linklabel#label', // rename linklabel field to minlabelistry 'link' ], ]); }, 'Program' => [ // Child Pages with template=Program 'title', 'summary', 'start' => function($parent){ // calculate the startdate from timetables return $parent->children->first->date; }, 'end' => function($parent){ // calculate the endate from timetables return $parent->children->last->date; }, 'Timetable' => [ 'date', // date 'timetable#entry'=> [ 'time#start', // time 'time_until#end', // time 'subtitle#description', // entry title ], ], ], // ProcessWire selector, selecting children > name result "location" 'template=Location, limit=1#location' => [ 'title#city', // summary title field to city 'body', 'country', 'venue', 'summary#address', // rename summary field to address 'link#tickets', // rename ticket link 'map', // Mapmarker field, automatically transformed 'images', 'infos#categories' => [ // repeater matrix! > rename to categories 'title#name', // rename title field to name 'entries' => [ // nested repeater matrix! 'title', 'body' ] ], ], ]; if ($input->urlSegment1 === 'json') { header('Content-type: application/json'); echo $page->pageQueryJson($query); exit(); } Module default settings The modules settings are public. They can be directly modified, for example: $modules->get('PageQueryBoss')->debug = true; $modules->get('PageQueryBoss')->defaults = []; // reset all defaults Default queries for fields: Some field-types or templates come with default selectors, like Pageimages etc. These are the default queries: // Access and modify default queries: $modules->get('PageQueryBoss')->defaults['queries'] … public $defaults = [ 'queries' => [ 'Pageimages' => [ 'basename', 'url', 'httpUrl', 'description', 'ext', 'focus', ], 'Pagefiles' => [ 'basename', 'url', 'httpUrl', 'description', 'ext', 'filesize', 'filesizeStr', 'hash', ], 'MapMarker' => [ 'lat', 'lng', 'zoom', 'address', ], 'User' => [ 'name', 'email', ], ], ]; These defaults will only be used if there is no nested sub-query for the respective type. If you query a field with complex data and do not provide a sub-query, it will be transformed accordingly: $page->pageQueryArry(['images']); // returns something like this 'images' => [ 'basename', 'url', 'httpUrl', 'description', 'ext', 'focus'=> [ 'top', 'left', 'zoom', 'default', 'str', ] ]; You can always provide your own sub-query, so the defaults will not be used: $page->pageQueryArry([ 'images' => [ 'filename', 'description' ], ]); Overriding default queries: You can also override the defaults, for example $modules->get('PageQueryBoss')->defaults['queries']['Pageimages'] = [ 'basename', 'url', 'description', ]; Index of nested elements The index for nested elements can be adjusted. This is also done with defaults. There are 3 possibilities: Nested by name (default) Nested by ID Nested by numerical index Named index (default): This is the default setting. If you have a field that contains sub-items, the name will be the key in the results: // example $pagesByName = [ 'page-1-name' => [ 'title' => "Page one title", 'name' => 'page-1-name', ], 'page-2-name' => [ 'title' => "Page two title", 'name' => 'page-2-name', ] ] ID based index: If an object is listed in $defaults['index-id'] the id will be the key in the results. Currently, no items are listed as defaults for id-based index: // Set pages to get ID based index: $modules->get('PageQueryBoss')->defaults['index-id']['Page']; // Example return array: $pagesById = [ 123 => [ 'title' => "Page one title", 'name' => 123, ], 124 => [ 'title' => "Page two title", 'name' => 124, ] ] Number based index By default, a couple of fields are transformed automatically to contain numbered indexes: // objects or template names that should use numerical indexes for children instead of names $defaults['index-n'] => [ 'Pageimage', 'Pagefile', 'RepeaterMatrixPage', ]; // example $images = [ 0 => [ 'filename' => "image1.jpg", ], 1 => [ 'filename' => "image2.jpg", ] ] Tipp: When you remove the key 'Pageimage' from $defaults['index-n'], the index will again be name-based. Help-fill closures & tipps: These are few helpfill closure functions you might want to use or could help as a starting point for your own (let me know if you have your own): Get an overview of languages: $query = ['languages' => function($page){ $ar = []; $l=0; foreach (wire('languages') as $language) { // build the json url with segment 1 $ar[$l]['url']= $page->localHttpUrl($language).wire('input')->urlSegment1; $ar[$l]['name'] = $language->name == 'default' ? 'en' : $language->name; $ar[$l]['title'] = $language->getLanguageValue($language, 'title'); $ar[$l]['active'] = $language->id == wire('user')->language->id; $l++; } return $ar; }]; Get county info from ContinentsAndCountries Module Using the [ContinentsAndCountries Module](https://modules.processwire.com/modules/continents-and-countries/) you can extract iso code and names for countries: $query = ['country' => function($page){ $c = wire('modules')->get('ContinentsAndCountries')->findBy('countries', array('name', 'iso', 'code'),['code' =>$page->country]); return count($c) ? (array) $c[count($c)-1] : null; }]; Custom strings from a RepeaterTable for interface Using a RepeaterMatrix you can create template string for your frontend. This is usefull for buttons, labels etc. The following code uses a repeater with the name `strings` has a `key` and a `body` field, the returned array contains the `key` field as, you guess, keys and the `body` field as values: // build custom translations $query = ['strings' => function($page){ return array_column($page->get('strings')->each(['key', 'body']), 'body', 'key'); }]; Multilanguage with default language fallback Using the following setup you can handle multilanguage and return your default language if the requested language does not exist. The url is composed like so: `page/path/{language}/{content-type}` for example: `api/icf/zurich/conference/2019/de/json` // get contenttype and language (or default language if not exists) $lang = wire('languages')->get($input->urlSegment1); if(!$lang instanceof Nullpage){ $user->language = $lang; } else { $lang = $user->language; } // contenttype segment 2 or 1 if language not present $contenttype = $input->urlSegment2 ? $input->urlSegment2 : $input->urlSegment1; if ($contenttype === 'json') { header('Content-type: application/json'); echo $page->pageQueryJson($query); exit(); } Debug The module respects wire('config')->debug. It integrates with TracyDebug. You can override it like so: // turns on debug output no mather what: $modules->get('PageQueryBoss')->debug = true; Todos Make defaults configurable via Backend. How could that be done in style with the default queries? Module in alpha Stage: Subject to change This module is in alpha stage … Query behaviour (especially selecting child-templates, renaming, naming etc) could change
  22. @Sergio asked about the pdf creation process in the showcase thread about my 360° feedback/survey tool and so I went ahead and set my little pdf helper module to public. Description from PW Weekly: Download & Docs: https://gitlab.com/baumrock/RockPdf You can combine it easily with RockReplacer: See also a little showcase of the RockPdf module in this thread:
  23. Robin S

    If you've ever needed to insert links to a large number of files within CKEditor you may have found that the standard PW link modal is a somewhat slow way to do it. This module provides a quicker way to insert links to files on the page being edited. You can insert a link to an individual file, or insert an unordered list of links to all files on the page with a single click. CKEditor Link Files Adds a menu to CKEditor to allow the quick insertion of links to files on the page being edited. Features Hover a menu item to see the "Description" of the corresponding file (if present). Click a menu item to insert a link to the corresponding file at the current cursor position. The filename is used as the link text. If you Alt-click a menu item the file description is used as the link text (with fallback to filename if no description entered). If text is currently selected in the editor then the selected text is used as the link text. Click "* Insert links to all files *" to insert an unordered list of links to all files on the page. Also works with the Alt-click option. Menu is built via AJAX so newly uploaded files are included in the menu without the page needing to be saved. However, descriptions are not available for newly uploaded files until the page is saved. Installation Install the CKEditor Link Files module. For any CKEditor field where you want the "Insert link to file" dropdown menu to appear in the CKEditor toolbar, visit the field settings and add "LinkFilesMenu" to the "CKEditor Toolbar" settings field. http://modules.processwire.com/modules/cke-link-files/ https://github.com/Toutouwai/CkeLinkFiles
  24. adrian

    Hi everyone, Here's a new module that I have been meaning to build for a long time. http://modules.processwire.com/modules/process-admin-actions/ https://github.com/adrianbj/ProcessAdminActions What does it do? Do you have a bunch of admin snippets laying around, or do you recreate from them from scratch every time you need them, or do you try to find where you saw them in the forums, or on the ProcessWire Recipes site? Admin Actions lets you quickly create actions in the admin that you can use over and over and even make available to your site editors (permissions for each action are assigned to roles separately so you have full control over who has access to which actions). Included Actions It comes bundled with a several actions and I will be adding more over time (and hopefully I'll get some PRs from you guys too). You can browse and sort and if you have @tpr's Admin on Steroid's datatables filter feature, you can even filter based on the content of all columns. The headliner action included with the module is: PageTable To RepeaterMatrix which fully converts an existing (and populated) PageTable field to either a Repeater or RepeaterMatrix field. This is a huge timesaver if you have an existing site that makes heavy use of PageTable fields and you would like to give the clients the improved interface of RepeaterMatrix. Copy Content To Other Field This action copies the content from one field to another field on all pages that use the selected template. Copy Field Content To Other Page Copies the content from a field on one page to the same field on another page. Copy Repeater Items To Other Page Add the items from a Repeater field on one page to the same field on another page. Copy Table Field Rows To Other Page Add the rows from a Table field on one page to the same field on another page. Create Users Batcher Allows you to batch create users. This module requires the Email New User module and it should be configured to generate a password automatically. Delete Unused Fields Deletes fields that are not used by any templates. Delete Unused Templates Deletes templates that are not used by any pages. Email Batcher Lets you email multiple addresses at once. Field Set Or Search And Replace Set field values, or search and replace text in field values from a filtered selection of pages and fields. FTP Files to Page Add files/images from a folder to a selected page. Page Active Languages Batcher Lets you enable or disable active status of multiple languages on multiple pages at once. Page Manipulator Uses an InputfieldSelector to query pages and then allows batch actions on the matched pages. Page Table To Repeater Matrix Fully converts an existing (and populated) PageTable field to either a Repeater or RepeaterMatrix field. Template Fields Batcher Lets you add or remove multiple fields from multiple templates at once. Template Roles Batcher Lets you add or remove access permissions, for multiple roles and multiple templates at once. User Roles Permissions Batcher Lets you add or remove permissions for multiple roles, or roles for multiple users at once. Creating a New Action If you create a new action that you think others would find useful, please add it to the actions subfolder of this module and submit a PR. If you think it is only useful for you, place it in /site/templates/AdminActions/ so that it doesn't get lost on module updates. A new action file can be as simple as this: class UnpublishAboutPage extends ProcessAdminActions { protected function executeAction() { $p = $this->pages->get('/about/'); $p->addStatus(Page::statusUnpublished); $p->save(); return true; } } Each action: class must extend "ProcessAdminActions" and the filename must match the class name and end in ".action.php" like: UnpublishAboutPage.action.php the action method must be: executeAction() As you can see there are only a few lines needed to wrap the actual API call, so it's really worth the small extra effort to make an action. Obviously that example action is not very useful. Here is another more useful one that is included with the module. It includes $description, $notes, and $author variables which are used in the module table selector interface. It also makes use of the defineOptions() method which builds the input fields used to gather the required options before running the action. class DeleteUnusedFields extends ProcessAdminActions { protected $description = 'Deletes fields that are not used by any templates.'; protected $notes = 'Shows a list of unused fields with checkboxes to select those to delete.'; protected $author = 'Adrian Jones'; protected $authorLinks = array( 'pwforum' => '985-adrian', 'pwdirectory' => 'adrian-jones', 'github' => 'adrianbj', ); protected function defineOptions() { $fieldOptions = array(); foreach($this->fields as $field) { if ($field->flags & Field::flagSystem || $field->flags & Field::flagPermanent) continue; if(count($field->getFieldgroups()) === 0) $fieldOptions[$field->id] = $field->label ? $field->label . ' (' . $field->name . ')' : $field->name; } return array( array( 'name' => 'fields', 'label' => 'Fields', 'description' => 'Select the fields you want to delete', 'notes' => 'Note that all fields listed are not used by any templates and should therefore be safe to delete', 'type' => 'checkboxes', 'options' => $fieldOptions, 'required' => true ) ); } protected function executeAction($options) { $count = 0; foreach($options['fields'] as $field) { $f = $this->fields->get($field); $this->fields->delete($f); $count++; } $this->successMessage = $count . ' field' . _n('', 's', $count) . ' ' . _n('was', 'were', $count) . ' successfully deleted'; return true; } } This defineOptions() method builds input fields that look like this: Finally we use $options array in the executeAction() method to get the values entered into those options fields to run the API script to remove the checked fields. There is one additional method that I didn't outline called: checkRequirements() - you can see it in action in the PageTableToRepeaterMatrix action. You can use this to prevent the action from running if certain requirements are not met. At the end of the executeAction() method you can populate $this->successMessage, or $this->failureMessage which will be returned after the action has finished. Populating options via URL parameters You can also populate the option parameters via URL parameters. You should split multiple values with a “|” character. You can either just pre-populate options: http://mysite.dev/processwire/setup/admin-actions/options?action=TemplateFieldsBatcher&templates=29|56&fields=219&addOrRemove=add or you can execute immediately: http://mysite.dev/processwire/setup/admin-actions/execute?action=TemplateFieldsBatcher&templates=29|56&fields=219&addOrRemove=add Note the “options” vs “execute” as the last path before the parameters. Automatic Backup / Restore Before any action is executed, a full database backup is automatically made. You have a few options to run a restore if needed: Follow the Restore link that is presented after an action completes Use the "Restore" submenu: Setup > Admin Actions > Restore Move the restoredb.php file from the /site/assets/cache/AdminActions/ folder to the root of your site and load in the browser Manually restore using the AdminActionsBackup.sql file in the /site/assets/cache/AdminActions/ folder I think all these features make it very easy to create custom admin data manipulation methods that can be shared with others and executed using a simple interface without needing to build a full Process Module custom interface from scratch. I also hope it will reduce the barriers for new ProcessWire users to create custom admin functionality. Please let me know what you think, especially if you have ideas for improving the interface, or the way actions are defined.
  25. justb3a

    This module allows users to subscribe and unsubscribe to a newsletter, it doesn't handle newsletter creation and delivery (I use a foreign service for this). There is one method to subscribe (by using a form) and there are two methods to unsubscribe (by using a form or by providing a link in the newsletter). Furthermore you can notify any person e.g. an administator via email when an user has subscribed/unsubscribed. For detailed information have a look at Github.