Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 01/15/2020 in all areas

  1. Hi all. Just thought I'd add the updated site I made for the Judo/BJJ club I run. For some odd reason I decided I wanted to try making a single-page website but still use ProcessWire's great page management tools. The site uses the excellent Template Engine Twig module (slightly modified to work with Twig 3) and dynamically builds itself using the page tree (no hard-coded sections). I'm no great designer, but using the above along with Bootstrap 4 and some probably-excessive animate-on-scroll effects I think it looks clean enough to differentiate itself from more standard martial arts websites. Anyways, you can visit the site at http://jkma.club and hopefully enjoy!
    6 points
  2. Hello all, I'm in the process of updating some websites to comply to the new GDPR opt-in regulations. Doing some resarch, I found this open source tool: https://klaro.kiprotect.com/ It looks quite promising and implementation seems quite easy. Have you used this tool? What is your experience so far? I saw that @Jens Martsch - dotnetic made some comments to the klaro GH issues. Did you implement this with PW?
    5 points
  3. ProcessWire Dashboard Download You can find the latest release on Github. Documentation Check out the documentation to get started. This is where you'll find information about included panel types and configuration options. Custom Panels The goal was to make it simple to create custom panels. The easiest way to do that is to use the panel type template and have it render a file in your templates folder. This might be enough for 80% of all use cases. For anything more complex (FormBuilder submissions? Comments? Live chat?), you can add new panel types by creating modules that extend the DashboardPanel base class. Check out the documentation on custom panels or take a look at the HelloWorld panel to get started. I'm happy to merge any user-created modules into the main repo if they might be useful to more than a few people. Roadmap Panel types Google Analytics Draft At a glance / Page counter 404s Layout options Render multiple tabs per panel Chart panel load chart data from JS file (currently passed as PHP array)
    3 points
  4. Hello all, sorry for getting off-topic, but I am curious: I have read about those new regulations but my understanding was, that this was just about a special case (a gambling website), so that nothing would change for normal websites. But now everybody seems to jump on the train just to be safe, even though it is not necessary. Could somebody please explain to me, why you have to add this new cookie banner to your website? Are you saving personal informations of users in cookies? Or could somebody please point me to a reliable source, that explains or states that you have to add this new cookie banner? I only have cookies from ProcessWire and Google Analytics (with anonymized IPs). I have never read a clear statement, that I have to add a cookie banner and never has somebody complaint that I don't have a banner. In my opinion, everybody adds those banners because they are not sure and jump on the bandwagon. But I am no lawyer, so maybe I am completely wrong. But those new banners are really worse. I saw some that covered the whole website before you could get to the content. Its like we are back in the 90s, where you have a start page for the homepage. ? Thank god there a browser extensions like I don't care about cookies. Regards, Andreas
    2 points
  5. @matjazp I added fixes for both issues you're describing. Check out the latest commit on the develop branch. These will be part of the next release.
    2 points
  6. I'm not familiar enough with Carbon to make a guess how well DateTimeAdvanced works with it. Generally, every operation/function call that expects a string should still work the same as with a regular Datetime field when output formatting is off, since my helper object has a ___toString() method that returns the unix timestamp. If you just want to add database subfield selectors to your system and don't want to search arrays or plug in your own subfield patterns, you can use this stripped-down module: <?php /** * ## Enhanced Datetime Field * * Allows searching for individual components of datetime fields in * standard subfield syntax in the database. * * Note that this doesn't work for searching in PageArrays. For that, * use the DatetimeAdvanced Fieldtype instead. * * ## Possible subfields * * - day * - month * - year (4-digit) * - hour (0..23) * - minutes * - seconds * - day_of_week (0..6, 0 = Sunday) * - day_of_year (0..365) * - week_of_year (1..53) * - date (just the date part, yyyy-mm-dd) * - time (just the time part, hh:mm:ss) * * ## Example * * ``` * $pagelist = $pages->find("mydatefield.year=2016"); * ``` **/ class FieldtypeDatetimePlus extends FieldtypeDatetime implements Module, ConfigurableModule { public static function getModuleInfo() { return array( "title" => "Datetime Plus", "summary" => wire()->_("Datetime field with extended search syntax. Needs timezone support enabled in MySQL, see http://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html for details."), "version" => "0.0.1" ); } protected static $_operators = array( "day" => array("d", "d"), "month" => array("c", "m"), "year" => array("Y", "Y"), "hour" => array("H", "H"), "minutes" => array("i", "i"), "seconds" => array("s", "s"), "day_of_week" => array("w", "w"), "day_of_year" => array("j", "z"), "week_of_year" => array("v", "W"), "date" => array("%Y-%m-%d", "Y-m-d"), "time" => array("T", "H:i:s"), ); /** * Match a date/time value in the database, as used by PageFinder * */ public function getMatchQuery($query, $table, $subfield, $operator, $value) { if($subfield != "data") { if(! $this->isAllowedSubfield($subfield)) { throw new WireException(sprintf($this->_("Unknown subfield name for datetime field: %s"), $subfield)); } if($subfield == "date" || $subfield == "time") { $value = preg_replace('/[^0-9:-]/', '', $value); } else { $value = $this->sanitizer->int($value); } if($operator == "day_of_year") { $value += 1; } $database = $this->wire("database"); if($database->isOperator($operator)) { $table = $database->escapeTable($table); $value = $database->escapeStr($value); $formatarg = self::$_operators[$subfield][0]; $formatarg = preg_replace('/([a-zA-Z])/', '%$1', $formatarg); $query->where("DATE_FORMAT({$table}.data, '{$formatarg}'){$operator}'$value'"); } } else { $value = (int) $this->_sanitizeValue($value); if($value) $value = date('Y-m-d H:i:s', $value); else $value = ''; $database = $this->wire('database'); if($database->isOperator($operator)) { $table = $database->escapeTable($table); $subfield = $database->escapeCol($subfield); $value = $database->escapeStr($value); $query->where("$table.{$subfield}{$operator}'$value'"); } } return $query; } public function isAllowedSubfield($subfield) { return array_key_exists($subfield, self::$_operators); } public function getInputfield(Page $page, Field $field) { $inputfield = $this->modules->get('InputfieldDatetime'); $inputfield->class = $this->className(); return $inputfield; } /** * Return array with information about what properties and operators can be used with this field. * * #pw-group-finding * * @param Field $field * @param array $data Array of extra data, when/if needed * @return array See `FieldSelectorInfo` class for details. * */ public function ___getSelectorInfo(Field $field, array $data = array()) { if($data) {} $selectorInfo = $this->wire(new FieldSelectorInfo()); $info = $selectorInfo->getSelectorInfo($field); foreach(array_keys(self::$_operators) as $op) { $info["subfields"][$op] = array( "name" => $op, "label" => $op, "operators" => $info["operators"], "input" => "text", "hint" => "", "options" => array() ); } return $info; } public function ___getModuleConfigInputfields() { $ifs = new InputfieldWrapper(); $cmd = $this->config->dbInitCommand; $off = date('O'); $needUpdate = false; if(strlen($off) > 0) { if(preg_match('/time_zone/i', $cmd)) { $needUpdate = false; return $ifs; } // PHP returns +0200, MySQL wants +02:00 $off = preg_replace('/(\d\d)$/', ':$1', $off); // Append timezone set statement $cmd .= sprintf(", time_zone = '%s' ", $off); } $f = $this->modules->get("InputfieldMarkup"); $f->label = $this->_("Enable timezone support in MySQL"); $f->description = $this->_("For datetime plus database selectors to be reliable, PHP and MySQL need to add/subtract the same offsets for datetime and timestamp values.") . " " . $this->_("To accomplish that, the timezone setting in MySQL needs to be set to the same value as in PHP.") . " " . $this->_("Copy the following line to site/config.php:") ; $f->attr( 'value', "<code>" . "\$config->dbInitCommand = \"$cmd\";" . "</code>" ); $f->notes = $this->_("Important: timezone data must be loaded in MySQL! See [this link](http://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html) for details."); $ifs->append($f); return $ifs; } }
    2 points
  7. You're right of course ? I have a custom panel that already includes the modal script, so I never noticed. I pushed a fix that should work. Thanks for debugging!
    2 points
  8. Hello @Brett. Thank you for your feedback! I was able to reproduce your issue and hopefully tracked down the bug. Please, install the latest version and give it a try. Let me know if the issue is resolved for you. New Release 1.1.3 - Fixed bug with FieldtypePage returning only single value.
    2 points
  9. Yes, the legal situation in Germany / Europe is getting harder. I'm also still struggling with a good solution. Our wordpress developer uses https://borlabs.io/ which is a quite complete solution for cookie management (and external scripts / media blocker). Thanks for the links to klaro & oil.js - both are looking really promising. I'll definetely take a deeper look. I'm still behind my updates of the fork but was thinking about extending the features (as our german customers are asking for features as choosing the cookie groups, blocking external scripts, if not opted in ...). Maybe it'll also be a complete rewrite, as the intended use changes. Edit: My current draft work of a rewrite you'll find here: https://github.com/blaueQuelle/privacywire/tree/dev
    2 points
  10. Couldn't you loop over all templates(excluding system templates) and use the template's name along with a count? For example: Basic Page (55) Calendar Postings (77) Job Postings (88) community-event (55) <- this one doesn't have a friendly template name, the others above do Total Pages (400) It would probably be helpful to show file information as well. Like: Documents (1,000) Images (2,000) Audio (30) Videos (40) Total Files (3,000) The number of users would be helpful per role Editors (20) Contributors (25) Vendors (22) System Admins (2) Total Users (60) All of that would probably need to be cached so isn't too taxing on the server. Maybe only displayed to admins as well? I thought I remembered a module that already provides similar counts? I can't remember the name. Maybe I'll remember it later?
    2 points
  11. Attention: please don't install this module at the time being! It is not compatible with current PW versions, and it will be some time until I can work in all the changes. Due to a discussion here in the forums, I was inspired to finally have a take on datetime fields and see if I couldn't get them to be searched a little more conveniently. Here's a small module - still in alpha state, but I'd be happy to get some feedback - that allows searching for individual components of a date like year, month, day, hour or even day_of_week or day_of_year, and also returning them. Github repo: DatetimeAdvanced Current version: 0.0.5 Tested in: ProcessWire 2.8 + 3.0 Possible subfields: day month year hour minute second day_of_week day_of_year week_of_year Examples: // Database search: $pagelist = $pages->find("mydatefield.year=2016"); // Filtering PageArray in memory: $maypages = $pagelist->filter("mydatefield.month=5"); // Back to our starting point: $start = date('z'); $end = $start + 7; $sevendays = $pages->find("mydatefield.day_of_year>=$start, mydatefield.day_of_year<$end"); // Nice side effect: subfields are now directly accessible $blogentry = $pages->get('blog-entry-1'); echo $blogentry->title . "(" . $blogentry->publishdate->year . ")"; // New in 0.0.4: shorthand methods echo $blogentry->publishdate->strftime("%Y-%m-%d %H:%M:%S") . PHP_EOL; echo $blogentry->publishdate->date("Y-m-d H:i:s") . PHP_EOL; ToDos for the future: See if there's a possibility to specify ranges more conveniently Check if this can perhaps wiggle its way into the PW core Changes: example for direct subfield access and shorthand methods to strftime() and date() added.
    1 point
  12. I'm using the standard AdminThemeFramework::getUserNavArray hook. Looks like that's a newer addition and not available on default. Any particular reason you're still using the default theme? I switched all of my client sites over to UiKit and I don't regret it. The old one looks so... old.
    1 point
  13. I fixed the issue (thanks for reporting it) so you could access the process module again, but I don't have idea at this moment where is or what's the error. Could you try to make others AWS backups with different website and post the result ? Meanwhile I will re-read the code to see if I can catch something.
    1 point
  14. <?php $projects = $pages->find("template=project-details, sort=random, limit=3"); if($projects) { $first_project = $projects->child(); // Got the first child // Do something with it foreach($projects->remove($first_project) as $p) { // Do something else with the other projects... } } ?> Not tested but it should work, there are several other methods indeed. Or... <?php $projects = $pages->find("template=project-details, sort=random, limit=3"); if($projects) { $i = 0; foreach($projects as $p) { if ($i == 0) { // First project } else { // Other projects } $i++; } } ?>
    1 point
  15. @zoeck Slow day in the office — I added the editMode and viewMode options to the PageList panel as well. See the latest release. $panels->add([ 'panel' => 'page-list', 'title' => 'Information', 'data' => [ 'parent' => 'template=basic-page, name=info', 'editMode' => 'modal', 'viewMode' => 'blank', ], ]);
    1 point
  16. Hi @gebeer, you are right - there is no detailed opt-in like Borlabs or Klaro have by now. I played with something like that in an experimental version of that plugin but it's far from ready to use - maybe a proof-of-concept maybe even less. For the time being I use the manage/opt-in/consent solution to let the user opt-in to allow cookies/scripts/trackers. They are all listed on the privacy page. Until the visitor gives its ok, I block everything - or better to say: I don't load anything until that point. if (localStorage.getItem('pwcmbAllowCookies') === 'y') { // load Google Analytics // load Matomo // load whatever } I have to add the detail that most of my clients don't use Google Analytics and weird tracking/post-view trackers anymore. They never looked into their analytics before and drop them now. They get their metrics from Google My Business, Bing Webmaster and in most cases that's all they need. Fair enough.
    1 point
  17. You Added it to "renderButton" in the "DashboardPanel" Class, but the Modal is used in the "renderPageActions" Function in the "DashboardPanelCollection.module" (The renderButton/renderFooterButton isn't used in the Collection) When you add "$this->includeModalScripts();" to "if (self::windowModeModal === $mode) {" (Line 300) it works ?
    1 point
  18. Thanks Robin, just tested and it does work. Man, you're fast!
    1 point
  19. I just tested it and the process ended without error ??‍♂️ What's the version of your Duplicator ? Edit1: Ok got it. Will push a fix. Edit2: You can update the module to the version 1.3.15
    1 point
  20. @Jens Martsch - dotnetic @Macrura Adding multiple panels via $panels->add([]) should work now.
    1 point
  21. This was due to $config->fileContentTypes not having up-to-date MIME types. I created an issue here and decided it would be better to make the MIME type > file extension mapping configurable in v0.2.2 rather than using $config->fileContentTypes. Please update the module and the problem should be fixed. P.S. This page is a useful resource if anyone wants to set additional MIME type mappings: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types
    1 point
  22. @Jens Martsch - dotnetic @Macrura Come to think of it, I could check if the config array has numerical keys, and in that case treat them as an array of configs.
    1 point
  23. Haven't tried out the module **yet**, but I love the look of these dashboards. One panel that could be useful is a content overview panel like in Wordpress. It would show the amount of pages for each type of page with a link to the built in pages lister that shows all pages filter for that page type. Another feature that might be useful would be the ability to create multiple dashboard pages, or tabs within dashboards like what is shown in the Drupal Workbench module? This could be a dashboard for the user? Maybe you could have a site dashboard(displayed when clicking on the main logo or the Processwire logo or visiting the main processwire admin page at /processwire) and a user dashboard(displayed when a user first logs into the Processwire Admin)? Here is what a "My dashboard"(from drupal.org) for users could look like If we had the ability to create multiple dashboard pages then while creating/editing each dashboard page, you can choose which roles are allowed to view the page. If you do not choose any roles, then only admins can view the dashboard page. For obvious reasons, anonymous users will not be able to save pages or add custom items. All of this might be too complex, but I thought would just get these thoughts out of my head in case anybody liked them. Here is another dashboard I found just to give others some ideas of what could probably be created with this module. Anyways, thanks for making this module. Look forward to trying it soon.
    1 point
  24. Just another thing, the next minor version will contain an encryption setting, trying to make Duplicator a bit GDPR compliant.
    1 point
  25. I think providing an option for this would indeed be sensible ? While testing the module I found it quite simple to regenerate the template stubs content on the local environment – this way there's no real need to sync stub files, and if you've got a full environment locally you can do this just by changing the prefix for something else and then restoring the old value. I'm currently running a slightly modified version of the module with a regenerate option in module config; seemed like a good idea at first, but not sure anymore. Might send a PR and let Robin decide ? Also, just in case there are other VSCode users here, a couple of pointers for getting things up and running: If you've excluded the /site/assets/cache/ directory (I had), you'll have to change the exclude setting. Sadly VSCode doesn't support full glob syntax, but ignoring everything except certain subdirectories is still doable with a hacky workaround (more discussion here) : "files.exclude": { "**/site/assets/cache/{[^A],?[^u],??[^t],???[^o],????[^T],?????[^e],??????[^m],???????[^p],????????[^l]}*": true, }, Suggested syntax for var (/* @var tpl_basic_page $page */) won't work, since VSCode expects valid PHPDoc syntax. Use /** @var tpl_basic_page $page */ instead. I'm using the PHP Intelephense plugin (bmewburn.vscode-intelephense-client), and after resolving aforementioned inconveniences things are working just fine ? Edit: sent a PR for the regenerate stubs option (https://github.com/Toutouwai/AutoTemplateStubs/pull/4).
    1 point
  26. dadish, First, thank you for this wonderful module, it's been awesome working with GraphQL. The problem: I have a field where the type is "Page Reference" and the input field type is "Page Auto Complete". In the details tab, the "Multiple pages PageArray" is selected. If I only have one page reference, then it will return the result as expected using the "list". However, if I have multiple page references, then it will not display any results at all. Can you let me know if there is something I am doing wrong or is this is a bug/feature that needs to be worked? All the best!
    1 point
  27. Yes the PaymentStripeIntents module does implement their new Intents API and is therfore SCA ready.
    1 point
  28. thanks - and i guess the version file needs to be updated (?).. this is working well for me; I have my own dashboard module, but it uses templates, pages and fields, and is thus cumbersome for smaller/low budget sites. My dashboard module uses AdminLTE, so it has stuff like collapsible panels with state recall; For some of the more complex panels like Formbuilder entries, etc, i'll just build custom panels and hook into this module. Thanks again for building this! This is very extensible, looks and works great, and seems like it will be a very popular module! Here's the dashboard i just threw together...
    1 point
  29. Please point me to some examples, thanks. Hi Kongondo... So I'm not sure if this is what B3ta is referring to - one solid piece that has gone through a bit of a wringer in terms of testing and configuration/transformation over the years is CS-Cart, which was originally in itself an offshoot of X-Cart. I believe both carts now have multishop setups. I am more familiar with the CS-Cart edition. Its a bit tricky, because on some level the owner needs to be able to decide if they want to have one unified database in the backend for various shops (the 'food court') model where you have multiple shops for different types of food but they all share one big common kitchen in the back and also share the credit card processing. Or the subcontract model where each store on the back end has its own unique instance in place with a universal dashboard that allows an admin to oversee everything. My advice, do not touch it with a 10-foot pole. As much as I love the idea, in practice the coding and debugging required has been a real nightmare/evolution for other products. How deep will admin go? Will customers be shared? Will customers use different logins for each storefront? Do cart contents carry over from one store to another? Do all storefronts have the same shipping and tax rules? Is there a shared pool of inventory that only the admin sees and that sub-storefront admins can pull from? Are products added by sub-storefront owners shareable? There are just a ton of variables laid on top of the shopping cart platform which already has a tendency to become super bloaty and confusing. CS-Cart made some serious errors during the evolution of their product, it has taken many years for them to iron own the kinks and hurt feelings that multi-vendor has created. I'd love to see a step up from padloper in terms of interface-in-place. Looking forward to the alphabetagamma.
    1 point
  30. I am currently building first site using Wireframe. I really like it so far. I have almost done with the site (pretty simple one) and I didn't use any controllers... until now when I noticed that homepage shows feed that mixes news and events. Usually nothing too complex (just add both templates to selector), but in this case events are from separate system, pulled from REST API. So this was perfect case where I use controller for: pulling data from external API caching that data, so that we fetch only once in hour merging and sorting it to one PageArray with local news items passing that final PageArray to view file for easy rendering Without Wireframe I would probably build much of that logic into functions, but I really like that there is "documented place where this kind of stuff should live". In future if I (or some other lucky fellow) need to make changes to layout - it is simple and one doesn't have to think about that "wow, all kinds of stuff is happening here", maybe remove that events stuff or add even more sources - I can do it easily without messing with layout. Also this model usually helps to produce clearer code: instead of many ifs (showing little bit different data for events vs. news) while rendering, I have that kind of logic separate from actual markup. One downside is of course that one have to "understand" the mvc-framework and it's logic. You have to know that there might be controller involved and where it lives for example.
    1 point
  31. Hey @Robin S. First of all thanks for your thoughtful message! I'll have to get back to some of your points later, but just wanted to share a few initial thoughts ? About using Markup Regions and Wirerame together: I honestly don't know. I'm aware on a basic level of how Markup Regions work, but I've never used it. I will definitely dig into the specifics, though – this is an interesting area. On a more general note I've intentionally kept to the "alternate template file" strategy (instead of hooking into Page rendering or something similar) so that Wireframe can be used for some parts of the site (some templates), while other parts use whatever other approach makes sense. So yeah, you can use them together, I'm just not yet sure to what extent that would make sense... if that makes sense to you? ? I don't really want to preach the superiority of MVC (or any other three or four letter architecture), but apart from some of the simplest sites I've built – isit.pw has one file with one form, so it for an example doesn't benefit from a whole lot of structure – I do generally prefer to separate "code" from "markup". This is a topic I'd love to cover in more detail later, but your two points summarise very well what it is all about. Project scope (and complexity) and working with or without a team are definitely key factors there. After that it comes down to personal preference. TL;DR: I wouldn't use Wireframe for everything, but I do think that it fits nicely just about any project. I often end up with multiple "views" for the same data – not sure if this is really a common need, but it has been in my projects, which is another reason to keep the views as basic (and as markup-y) as possible, and instead move all the business logic, data structuring, etc. somewhere else. Overall I've found that this sort of structure helps me keep things neat so that when things eventually grow and scale it doesn't become a mess, and allows me to make changes and additions with little extra overhead once they are due. That being said, there's a good reason why Controllers – for an example – are actually optional components in Wireframe. Some of my templates make use of the whole package – Controller, layout, view file(s), and partials – yet others have just a single view file, and that's all. I like that I don't have to use more than I really need, but if I do need more later, I can just bolt it in without a whole lot of refactoring ? It's true that you can use ProcessWire's built-in features to do everything that Wireframe does. That's exactly what Wireframe itself does: I've tried not to reinvent the wheel where possible, so the View (for an example) is a light-weight wrapper for TemplateFile, etc. Originally the predecessor of this project (pw-mvc) was all about standardising some best practices so that as we (as a team) build a project after project there's some common ground there. In a perfect world you could jump into a new project you've never touched before and instantly see what's going on in there. It's a bit more than that now, though. ... and this is the point where I realise that my "few initial thoughts" are already getting quite long-winded ?
    1 point
  32. The module source is below. Example usage: a checkbox on a contact form (using Form Builder) for the user to subscribe. It's used on https://ricardo-vargas.com/contact/ EXAMPLE A method on _hooks.php. If you don't use Form Builder, use this code on your form page. $forms->addHookBefore('FormBuilderProcessor::emailForm', function($event) { $processor = $event->object; if ($processor->formName == 'contact-form') { $formData = $event->arguments(1); $contact_name = $event->sanitizer->text($formData['contact_name']); $contact_name = substr($contact_name, 0, 30); // limit length further $contact_name = $event->sanitizer->emailHeader($contact_name); $contact_email = $event->sanitizer->text($formData['contact_email']); $contact_email = $event->sanitizer->emailHeader($contact_email); $processor->emailFrom = $contact_email; //reply to $processor->emailSubject = 'Message from '.$contact_name; $form = $event->object->getInputfieldsForm(); $subscribe = $form->get('receive_updates'); $list_id = $form->get('sendy_list_id')->attr('value'); // check to see if they subscribed if ($subscribe->attr('checked')) { $success_url = '/contact'; // $fail_url = '/contact?error=1'; $ProcessSendyAPI = wire('modules')->getModule('ProcessSendyAPI'); $ProcessSendyAPI->subscribeInSendy($contact_name, $contact_email, $list_id, $success_url); } } }); MODULE https://gist.github.com/sjardim/2d834ebb0bd66d4da1ac16072f4075cd <?php namespace ProcessWire; class ProcessSendyAPI extends WireData implements Module, ConfigurableModule { public static function getModuleInfo() { return array( 'title' => __('Process Sendy API'), 'summary' => __('Handle API calls to a Sendy installation'), 'author' => 'Sérgio Jardim', 'version' => '001', 'singular' => true, 'autoload' => false, 'icon' => 'envelope' ); } /** * Data as used by the get/set functions * */ protected $data = array(); /** * Default configuration for module * */ static public function getDefaultData() { return array( "sendy_api_key" => '', "sendy_installation_url" => 'http://www.example.com/sendy' ); } /** * Populate the default config data * */ public function __construct() { foreach(self::getDefaultData() as $key => $value) { $this->$key = $value; } } public static function getModuleConfigInputfields(array $data) { $data = array_merge(self::getDefaultData(), $data); $wrapper = new InputfieldWrapper(); $f = wire('modules')->get('InputfieldText'); $f->attr('name', 'sendy_api_key'); $f->label = __('Sendy API Key', __FILE__); $f->description = __('Further instructions at https://sendy.co/api', __FILE__); $f->notes = __('Get your key at http://your_sendy_installation/settings.', __FILE__); $f->value = $data['sendy_api_key']; $wrapper->add($f); $f = wire('modules')->get('InputfieldURL'); $f->attr('name', 'sendy_installation_url'); $f->label = __('Sendy instalation URL', __FILE__); $f->description = __('Your Sendy installation URL without a trailing slash', __FILE__); $f->notes = 'http://www.example.com/sendy'; $f->value = $data['sendy_installation_url']; $wrapper->add($f); return $wrapper; } /** * [subscribeUserOrGuest description] * @param [type] $name [description] * @param [type] $email [description] * @param [type] $list_id [description] * @param [type] $success_url [description] * @param [type] $fail_url [description] * @return [type] [description] */ public function subscribeInSendy($name, $email, $list_id, $success_url = null, $fail_url = null) { $api_key = $this->data['sendy_api_key']; $sendy_url = $this->data['sendy_installation_url']; $postdata = http_build_query( array( 'name' => $name, 'email' => $email, 'list' => $list_id, 'boolean' => 'true' //set this to "true" so that you'll get a plain text response ) ); $opts = array('http' => array('method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => $postdata)); $context = stream_context_create($opts); $result = file_get_contents($sendy_url.'/subscribe', false, $context); //check result and redirect if($result) { $this->wire('log')->save("newsletter", 'A new user subscribed to the site mailing list: '.$email); if($success_url) { header("Location: $success_url"); } } else { $this->wire('log')->save("error", 'Error occurred on subscribing '.$email); if($fail_url) { header("Location: $fail_url"); } } } }
    1 point
  33. @SamC it's really as simple as that: https://processwire.com/blog/posts/new-ajax-driven-inputs-conditional-hooks-template-family-settings-and-more/#new-conditional-hooks Update 2022: $wire->addHookAfter('Pages::saved', function(HookEvent $event) { $page = $event->arguments('page'); bd('page saved'); bd($event, 'event'); bd($event->object, 'event->object'); bd($event->arguments(), 'event->arguments'); }); in the beginning it can be a little confusing when to use event->object, event->arguments and event->return but with the help of tracy you can quickly bring light into the dark: add the code above to the tracy console, set the radio on the right to load it on "ready" (same as placing the code in the site/ready.php file) and save any page: $event->arguments('page') is the same as using $event->arguments(0) that you will see very often and in the tracy dump you see that 0 is simply the key for the first argument in that hookevent. you can also collapse the "data" property of the hookevent and you would see the same: You can also use your IDE to quickly find what the HookEvent is returning/containing in which hook. Let's take the common saveReady hook as an example: We know that the hook is attached as Pages::saveReady (eg because we have read that somewhere) That means that the hook is part of the "Pages" class, which is located at "/wire/core/Pages.php" - that's easy to find out using CTRL+P in VSCode: Searching for "___saveReady" lets us find the corresponding method: Now we see, that we have ONE "arguments", being Page $page - this means $event->arguments(0) would return the page being ready for saving $event->object would be the class, here "Pages" $event->return is the return value of that method, here $data (line 1739) Edit: There's some additional explanations in this post: https://processwire.com/talk/topic/27248-pagestrashtemplatefoo-vs-pagestemplatefootrash/?do=findComment&comment=224659 #search afraid of hooks
    1 point
  34. You could also look at this code/module by @Soma for the live search feature: https://github.com/somatonic/AjaxSearch/blob/master/AjaxSearch.js Then its up to you to do your logic in the search.php template. To filter the data, check the doc/example : - https://datatables.net/examples/plug-ins/range_filtering.html - https://datatables.net/examples/api/multi_filter.html - https://www.google.fr/search?q=jquery+datatables+filter
    1 point
  35. For a project I've posted yesterday I built a basic module to subscribe users to a Sendy installation. I love Sendy and my client too as we use it to send lots of emails using Amazon SES costing almost nothing at all. Do guys think that's worth to post about? It's very basic now, it doesn't use Sendy's API at all, it just send the data using POST to subscribe the users to different lists.
    1 point
×
×
  • Create New...