Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation since 03/22/2019 in all areas

  1. 28 points
    Good Morning ProcessWIre Community, PW Review is a website that has a lofty goal of covering ProcessWire on a regular basis. That may seem like an impossible task, however I believe I'm up to the challenge. First, this is a strictly non-commercial endeavor and a project I believe in. This is not Wired Magazine or anything like that. I'm not a serious programmer or pretending to be one. My goal is to cover the modules (commercial and non-commercial) that may not get that much press or attention. I will also be covering modules that maybe you haven't heard about in awhile. There will also be screenshots, information and videos regarding the Commercial modules. I've been with this community since 2012 and have benefitted tremendously from ProcessWire. So this is my way of giving back, which is important to me. It's my hope that over time that what I'm doing myself will get some community participation. One person that I've had nothing but positive support from is Ryan Cramer. That's enough to keep me going at this for some time. That's it. Have a nice day and I hope you find something to like with PW Review. If not, please send me an email. I'm a great listener. Best Regards, Charles
  2. 25 points
    Like in recent weeks past, the primary focus this week in core development was working through the queue of older issue reports. Relative to 3.0.128, ProcessWire 3.0.129 contains 17 commits over 1 week, most of which are focused on resolving and closing out older issue reports. However, there have also been a few very useful additions too, and I’m going to cover them in a blog post next week. In terms of our issues repository, we are now down to 65 open issues and 777 closed (the closed number is a total over the life of this repo). If we subtract issues that are tagged as being fixed, not a bug or ready to close, we’re around 55 open issue reports (give or take a couple depending on when we check). Which is to say, there’s a lot of great progress here. And many of the remaining issues are minor things that might only affect one person, though still important nonetheless. Thanks to everyone that’s helping figure things out (such as Toutouwai, Matjazpotocnik, Netcarver and others), your help is greatly appreciated. Just now I also released a new version of ProMailer (v7) which accommodates many of the recent feature requests and fixes a few minor issues as well. There has been a lot of enthusiasm for ProMailer, pleasantly more than expected—thanks for your interest and support. Here’s the changelog for the latest version (v7) below. There is also more good stuff in the works for v8 as well. Changed subscribers list interface to use tabs. Added ability to remove all subscribers from a list. Added ability to remove filtered subscribers from a list (matching find query). Added ability to import subscribers from another list (creating a merged list). Added support for single, multi-select and checkbox custom fields. Added support for PW 3.0.129+ core WireMail blacklist (more details in next week’s blog post). Added several new options for custom fields (see new custom fields reference). Added documentation for conditional placeholders. Split the rather large ProcessProMailer.module into separate files/classes. Fix some display issues in AdminThemeDefault and AdminThemeReno. Various minor bug fixes and other minor tweaks, additions and improvements. Thanks for reading this quick update and hope that you have a great weekend.
  3. 25 points
    Relative to the last dev branch version (3.0.127) version 3.0.128 contains 40 commits, mostly specific to resolving older GitHub issue reports. If you are interested, here is the commit log: https://github.com/processwire/processwire/commits/dev — version 3.0.128 covers commits between March 2nd and today. We're down to about 77 remaining issue reports, mostly older stuff that didn't get covered in the past for one reason or another, but we're making good progress. Similar updates will be continuing next week, and I've also got several ProMailer updates coming out next week too. Hope you all have a great weekend!
  4. 22 points
    File Info A textformatter module for ProcessWire. The module can add information to local Pagefile links in two ways: As extra markup before, within or after the link As data attributes on the link (handy if you want to use a Javascript tooltip library, for instance) Screenshots Module config Example of output Installation Install the File Info module. Add the textformatter to one or more CKEditor fields. Configuration Add markup action (and general) Select "Add markup to links" Select the Pagefile attributes that will be retrieved. The attribute "filesizeStrCustom" is similar to the core "filesizeStr" attribute but allows for setting a custom number of decimal places. If you select the "modified" or "created" attributes then you can define a date format for the value. Enter a class string to add to the links if needed. Define the markup that will be added to the links. Surround Pagefile attribute names in {brackets}. Attributes must be selected in the "Pagefile attributes" section in order to be available in the added markup. If you want include a space character at the start or end of the markup then you'll need >= PW 3.0.128. Select where the markup should be added: prepended or appended within the link, before the link, or after the link. Add data attributes action Select "Add data attributes to links" Select the Pagefile attributes that will be retrieved. These attributes will be added to the file links as data attributes. Attributes with camelcase names will be converted to data attribute names that are all lowercase, i.e. filesizeStrCustom becomes data-filesizestrcustom. Hook If you want to customise or add to the attributes that are retrieved from the Pagefile you can hook TextformatterFileInfo::getFileAttributes(). For example: $wire->addHookAfter('TextformatterFileInfo::getFileAttributes', function(HookEvent $event) { $pagefile = $event->arguments(0); $page = $event->arguments(1); $field = $event->arguments(2); $attributes = $event->return; // Add a new attribute $attributes['sizeNote'] = $pagefile->filesize > 10000000 ? 'This file is pretty big' : 'This file is not so big'; $event->return = $attributes; }); https://github.com/Toutouwai/TextformatterFileInfo https://modules.processwire.com/modules/textformatter-file-info/
  5. 19 points
    Work continued in closing out issue reports this week. We’re down to about 60 of them now, though if we subtract issues that aren’t reproducible, are already marked as resolved (close pending), may be moved to the request repo, or are a discussion (rather than something to fix), then we’re closer to half that number. Over these last few weeks we’ve been working on issue reports, but I’ve also been enhancing the core in small ways as well. This post will cover a few of the useful enhancements that have been made in recent weeks— https://processwire.com/blog/posts/pw-3.0.130/
  6. 18 points
    Quietly and without interruption this week, our whole website (and all subdomains) moved from a single static server to a load-balanced multi-server environment, giving us even more horsepower and redundancy than before— https://processwire.com/blog/posts/processwire-hosting-upgrades/
  7. 16 points
    Mystique Module for ProcessWire CMS/CMF Github repo : https://github.com/trk/Mystique Mystique module allow you to create dynamic fields and store dynamic fields data on database by using a config file. Requirements ProcessWire 3.0 or newer PHP 7.0 or newer FieldtypeMystique InputfieldMystique Installation Install the module from the modules directory: Via Composer: composer require trk/mystique Via git clone: cd your-processwire-project-folder/ cd site/modules/ git clone https://github.com/trk/Mystique.git Module in live reaction with your Mystique config file This mean if you remove a field from your config file, field will be removed from edit screen. As you see on youtube video. Using Mystique with your module or use different configs path, autoload need to be true for modules Default configs path is site/templates/configs/, and your config file name need to start with Mystique. and need to end with .php extension. // Add your custom path inside ready or init function, didn't tested outside Mystique::add('your-configs-path'); All config files need to return a php array like examples. Same as ProcessWire Inputfield Api, only difference is set and showIf usage <?php namespace ProcessWire; /** * Resource : testing-mystique */ return [ 'title' => __('Testing Mystique'), 'fields' => [ 'text_field' => [ 'label' => __('You can use short named types'), 'description' => __('In file showIf working like example'), 'notes' => __('Also you can use $input->set() method'), 'type' => 'text', 'showIf' => [ 'another_text' => "=''" ], 'set' => [ 'showCount' => InputfieldText::showCountChars, 'maxlength' => 255 ], 'attr' => [ 'attr-foo' => 'bar', 'attr-bar' => 'foo' ] ], 'another_text' => [ 'label' => __('Another text field (default type is text)') ] ] ]; Example: site/templates/configs/Mystique.seo-fields.php <?php namespace ProcessWire; /** * Resource : seo-fields */ return [ 'title' => __('Seo fields'), 'fields' => [ 'window_title' => [ 'label' => __('Window title'), 'type' => Mystique::TEXT, // or InputfieldText 'useLanguages' => true, 'attr' => [ 'placeholder' => __('Enter a window title') ] ], 'navigation_title' => [ 'label' => __('Navigation title'), 'type' => Mystique::TEXT, // or InputfieldText 'useLanguages' => true, 'showIf' => [ 'window_title' => "!=''" ], 'attr' => [ 'placeholder' => __('Enter a navigation title') ] ], 'description' => [ 'label' => __('Description for search engines'), 'type' => Mystique::TEXTAREA, 'useLanguages' => true ], 'page_tpye' => [ 'label' => __('Type'), 'type' => Mystique::SELECT, 'options' => [ 'basic' => __('Basic page'), 'gallery' => __('Gallery'), 'blog' => __('Blog') ] ], 'show_on_nav' => [ 'label' => __('Display this page on navigation'), 'type' => Mystique::CHECKBOX ] ] ]; Searching data on Mystique field is limited. Because, Mystique saving data to database in json format. When you make search for Mystique field, operator not important. Operator will be changed with %= operator. Search example $navigationPages = pages()->find('my_mystique_field.show_on_nav=1'); $navigationPages = pages()->find('my_mystique_field.page_tpye=gallery');
  8. 15 points
    Access By Query String Grant/deny access to pages according to query string. Allows visitors to view protected pages by accessing the page via a special URL containing an "access" GET variable. This allows you to provide a link to selected individuals while keeping the page(s) non-viewable to the public and search engines. The recipients of the link do not need to log in so it's very convenient for them. The view protection does not provide a high level of security so should only be used for non-critical scenarios. The purpose of the module was to prevent new websites being publicly accessible before they are officially launched, hence the default message in the module config. But it could be used for selected pages on existing websites also. Once a visitor has successfully accessed a protected page via the GET variable then they can view any other page protected by the same access rule without needing the GET variable for that browsing session. Superusers are not affected by the module. Usage Install the Access By Query String module. Define access rules in the format [GET variable]??[selector], one per line. As an example the rule... rumpelstiltskin??template=skills, title~=gold ...means that any pages using the "skills" template with the word "gold" in the title will not be viewable unless it is accessed with ?access=rumpelstiltskin in the URL. So you could provide a view link like https://domain.com/skills/spin-straw-into-gold/?access=rumpelstiltskin to selected individuals. Or you could limit view access to the whole frontend with a rule like... 4fU4ns7ZWXar??template!=admin You can choose what happens when a protected page is visited without the required GET variable: Replace the rendered markup Throw a 404 exception If replacing the rendered markup you can define a meta title and message to be shown. Or if you want to use more advanced markup you can hook AccessByQueryString::replacementMarkup(). $wire->addHookAfter('AccessByQueryString::replacementMarkup', function(HookEvent $event) { // Some info in hook arguments if needed... // The page that the visitor is trying to access $page = $event->arguments(0); // An array of access keys that apply to the page $access_keys = $event->arguments(1); // The title $title = $event->arguments(2); // The message $message = $event->arguments(3); // Return some markup $event->return = 'Your markup'; }); Screenshot https://github.com/Toutouwai/AccessByQueryString https://modules.processwire.com/modules/access-by-query-string/
  9. 13 points
    Why Migrations? Benjamin Milde wrote a great blog post about that: https://processwire.com/blog/posts/introduction-migrations-module/ Why another migrations module? Benjamin's Migrations Module is great (https://modules.processwire.com/modules/migrations/), but there were two things that I didn't like: For me, it didn't feel easy to use You have to define Migrations in a central place and I wanted to be able to use Migrations in my Modules The second point does bring downsides with it, so this might have been intended by him. Anyhow - I like when things work "my way" Example See this example of how it works and how easy it is to use. Let's start with a very simple Migration that only creates (on upgrade) or deletes (on downgrade) one field: $upgrade = function(RockMigrations $rm) { $rm->createField('yournewfield', 'text'); }; $downgrade = function(RockMigrations $rm) { $rm->deleteField('yournewfield'); }; -------- I have to leave, but want to share my Migrations module with you. It's alpha and you have to make sure to have backups!! But I'm using it since several weeks now and it's a joy so far. Please see the detailed readme files and this screencast: https://github.com/BernhardBaumrock/RockMigrations Sorry, I'm in a hurry and have to leave, but I'm happy to hear your thoughts!
  10. 13 points
    I'm so lazy That's why I created RockModuleCreator some time ago... I didn't want to copy files, rename them, rename the class, lookup icon names etc... Not a lot to say... Simply upload your skeleton to github or similar, add placeholder tags like `#author#` or `#date#` and create modules quickly and easily. I'm happy to accept PRs if anyone wants to take this further... https://github.com/BernhardBaumrock/RockModuleCreator Available skeletons: https://github.com/BernhardBaumrock/RockMigrationsDemo https://github.com/BernhardBaumrock/RockProcessHello
  11. 13 points
    I recently mentioned that I was working (more like messing about quickly :-)) on a Visualisation module based on the awesome chart lib Vega. I haven't touched this module in a while. I only realised today as I was transferring my dev setup to WampServer and testing things out that I'd left this off at a stage where one could view a basic Viz. See the screenshots below. Word of warning: this does not even qualify as pre-alpha in my opinion. It is very early days. It is more of a playground to test ideas. It's also not high in my list of priorities so I don't know when it will be ready... Screenshots Create new viz from list of pre-built visualisations/charts Editing a single visualisation/chart
  12. 12 points
    Saturday morning I wrote in the the latest weekly issue this: And here's the view from my front door just now, Tuesday morning: I'm not particularly superstitious, but kinda feels like I dropped the ball on this one. To my defence, on Saturday there was literally zero snow here, and the whole day was sunny and warm and all. Proper shorts and T-shirt weather. I guess the lesson here is that it's always too early to say that the winter is over. Have a great day, folks!
  13. 11 points
    A terminal for running server commands: http://modules.processwire.com/modules/process-terminal/ https://github.com/adrianbj/ProcessTerminal NOTE: It does not support interactive commands like vi, nano, apt, etc. DO NOT attempt to use these as they may result in you needing to restart apache. This is a bash terminal that lets you quickly execute commands on a server. In addition to normal commands like: ls, cd, cat, mkdir, rm, chmod, chown, etc, you can also do mysql command line calls which is very handy if you need to add a new user, create a mysqldump etc. Note that for mysql commands you need to issue them individually - you can't simply start "mysql" and issue commands from there - each call needs to include your username and password and the command to be run, eg: mysql -u root -p mypassword -e "CREATE DATABASE newtablename"; There is also an upload and download command, eg "upload test.txt" which will spawn a file selector dialog on your machine to upload that file to your server with the given name. It also has arrow up and down for command history as well as tab autocompletion of commands and file names. This module was separated from Tracy because some shared hosts were flagging it as spam. This is because it uses system_exec to run server commands. This can certainly be dangerous, but in my opinion it is no more dangerous than the HannaCode module or the Tracy Console panel which both allow you to run system_exec. The key thing is that ProcessWire's htaccess rules prevent the shell.php file from being run directly and because this is a process module it uses PW's permissions to restrict usage to superusers.
  14. 10 points
    If you're not harnessing the backend from ProcessWire I'd personally tend to not use ProcessWire. While it's entirely possible to do so (maybe also search for prev. discussions on the topic) there are some parts, which in my opinion discourage that kind of usage: Lack of proper testing capabilities. There are topics on how to do TDD with processwire, but the options on managing db state or handling requests in tests are not there. If you need to manage a lot of diverse data the autoloading of every template/field on each request can become a bottleneck. Working around it by reusing more fields/templates can work, but isn't great either. The selector engine for pages is great for light to medium complex stuff, but complex selections and especially aggregations need custom SQL or third party solutions like RockFinder. Also if you're not careful it's tempting to fall into n+1 query problems with fields / relationships being lazy loaded by default. Transactions are hardly used by the core, so if you want/need to prevent partial updates from happening you need to ensure that on your own by wrapping stuff into transactions. Not to say ProcessWire isn't otherwise a nice system, but those are the things I'd urge anyone to evaluate before using ProcessWire in a web application project.
  15. 9 points
    As @szabesz mentioned, why not simply add the .php to the page name and disable "Should page URLs end with a slash?" in the template? Just tried, works well. You may even have a /index.php...
  16. 9 points
    Fixed a lot of these. I don't really want to change much else as it's a massive pain in the ass when they change the forum templates every other upgrade. Things like UIKit styles adding big padding on quotes - I could spend a long time tweaking UIKit to just target the header element only somehow I guess but it's easier to just include Ryan's stylesheets and override a single class (done, padding is now 20px) Accessibility - if someone wants to give me the CSS changes I can just plug in I'd be happy to do so. I don't know enough about accessibility to tackle that myself. Forum width is same as the site width which makes sense visually, though perhaps we're missing a trick nowadays and could have a helpful sidebar at larger screen widths? Maybe some sort of quick links for docs etc? I'm not sure - it's more work and it's taken me this long just to tweak a dozen styles - I don't get paid for this and have to prioritise client work to pay the bills
  17. 9 points
    A recent GitHub request got me thinking about ways to get an overview of which fields are using which Textformatter modules. Here are a couple of approaches... 1. For all Textformatter modules that are in use, show the fields they are applied to Execute the following code in the Tracy Debugger console: // Loop over fields and get their Textformatters $textformatters = array(); foreach($fields as $field) { if(empty($field->textformatters)) continue; foreach($field->textformatters as $textformatter) { $textformatters[$textformatter][] = $field->name; } } d($textformatters); Any Textformatter modules that are not included in the dump output are not applied to any fields. 2. In the config screen for a Textformatter module, show the fields where the module is applied Add the following to /site/ready.php $wire->addHookBefore('ProcessModule::executeEdit', function(HookEvent $event) { // Get the module name $module_name = $this->wire('input')->get->name('name'); // Return if it's not a Textformatter module if(strpos($module_name, 'Textformatter') !== 0) return; // Add field to module edit form $event->wire()->addHookBefore('InputfieldForm(id=ModuleEditForm)::render', function(HookEvent $event) use ($module_name) { $value = ''; // Find any fields using this Textformatter and build markup value foreach($this->wire('fields') as $field) { if(empty($field->textformatters)) continue; foreach($field->textformatters as $textformatter) { if($textformatter === $module_name) { $value .= "<a href='{$this->wire('config')->urls->admin}setup/field/edit?id={$field->id}#fieldtypeConfig' target='_blank'>$field->name</a><br>"; } } } if(!$value) $value = 'No fields are using this Textformatter module'; // Add markup field to form $form = $event->object; $f = $this->wire('modules')->InputfieldMarkup; $f->label = 'Fields using this Textformatter module'; $f->value = $value; $form->insertAfter($f, $form->children->get('id=ModuleInfo')); }); });
  18. 8 points
    Super cool, congratulations on the upgraded infrastructure. I definitely would like to read more details about how you two setup ProcessWire in that environment. That would make for a good, enterprise-y tutorial here on the page too.
  19. 8 points
    This is awesome Ryan, keep it up! I can imagine going through the issue reports is not as exciting as developing new features but it's definitely more important in terms of maintainability and long-term user happiness. Happy that these issues are being tackled. I wish you and everyone in the community a great weekend too.
  20. 8 points
    Hi @sambadave, if the available solutions do not fit, you can modify the markup of any field as you want quite easily. One option is the Inputfield::render hook. First, start with a general hook to check if everything works: // /site/ready.php $wire->addHookAfter("Inputfield::render", function(HookEvent $event) { bd('fired'); }); You should get lots of dumps when opening your page (using TracyDebugger of course): Make it conditional to only fire for your field and change the class to InputfieldSelect to be more specific: $wire->addHookAfter("InputfieldSelect(name=availability)::render", function(HookEvent $event) { bd('fired'); }); It will fire only once: The HTML is in the "return" property of the $event: $wire->addHookAfter("InputfieldSelect(name=availability)::render", function(HookEvent $event) { bdb($event->return); }); You can then modify this html like this: $wire->addHookAfter("InputfieldSelect(name=availability)::render", function(HookEvent $event) { $html = $event->return; $html = str_replace("value='1'", "value='1' style='background: red; color: white;'", $html); $html = str_replace("value='2'", "value='2' style='background: blue; color: white;'", $html); $html = str_replace("value='3'", "value='3' style='background: green; color: white;'", $html); $event->return = $html; }); For more complex modifications it's better to hook the field before it get's rendered (search the forum via google for ProcessPageEdit::buildForm). You can also see https://github.com/BernhardBaumrock/TemplatePreviewImages for a simple example of modifying inputfields and applying an additional library.
  21. 7 points
    I am using this module for SEO, LANGUAGE and ELEMENTS (uikit components) USAGE EXAMPLE : LANGUAGE On my private module, i added my custom configs path to Mystique module by using : Mystique::add('my-module-configs-path'); - Create config file <?php namespace ProcessWire; // Filename: MyModule/configs/Mystique.language.php // This options normally coming from a file array, i added 2 options for example $options = [ 'tr' => 'Türkçe', 'en' => 'English' ]; $defaultValue = 'en'; /** * Resource : MyModule => Language */ return [ 'title' => __('MyModule: Language'), 'fields' => [ 'title' => [ 'label' => __('Language title'), 'description' => __('Title of language'), 'type' => Mystique::TEXT, 'columnWidth' => 50 ], 'code' => [ 'label' => __('Code'), 'description' => __('Language short code'), 'type' => Mystique::SELECT, 'options' => $options, 'defaultValue' => $defaultValue, 'required' => true, 'columnWidth' => 50 ], 'flag' => [ 'label' => __('Flag'), 'description' => __('Language flag code'), 'type' => Mystique::TEXT, 'columnWidth' => 50 ], 'direction' => [ 'label' => __('Direction'), 'checkboxLabel' => __('Right to left'), 'description' => __('Direction of language'), 'type' => Mystique::TOGGLE_CHECKBOX, 'type_fallback' => Mystique::CHECKBOX, 'columnWidth' => 50 ], 'currency' => [ 'label' => __('Currency'), 'description' => __('Code of currency'), 'type' => Mystique::TEXT, 'columnWidth' => 50 ], 'symbol' => [ 'label' => __('Symbol'), 'description' => __('Symbol of currency'), 'type' => Mystique::TEXT, 'columnWidth' => 50 ], 'grouping_separator' => [ 'label' => __('Grouping separator'), 'description' => __('Thousand separator for amount'), 'type' => Mystique::TEXT, 'columnWidth' => 50 ], 'decimal_separator' => [ 'label' => __('Decimal separator'), 'description' => __('Decimal separator for amount'), 'type' => Mystique::TEXT, 'columnWidth' => 50 ], 'separator' => [ 'label' => __('Use separator'), 'checkboxLabel' => __('YES'), 'description' => __('Apply space between amount and currency symbol ?'), 'type' => Mystique::TOGGLE_CHECKBOX, 'type_fallback' => Mystique::CHECKBOX, 'columnWidth' => 33 ], 'show_decimal' => [ 'label' => __('Decimal'), 'checkboxLabel' => __('YES'), 'description' => __('Show amount decimals ?'), 'type' => Mystique::TOGGLE_CHECKBOX, 'type_fallback' => Mystique::CHECKBOX, 'columnWidth' => 33 ], 'symbol_after' => [ 'label' => __('Symbol after'), 'checkboxLabel' => __('YES'), 'description' => __('Display symbol after amount ?'), 'type' => Mystique::TOGGLE_CHECKBOX, 'type_fallback' => Mystique::CHECKBOX, 'columnWidth' => 33 ], ] ]; - Select config file from Mystique field settings - Add Mystique field to language template Access data via api (in this example mystique field name is : lang) <?php $language = $user->language; // lang is Mystique field echo 'Title : ' . $language->lang->title . '<br>'; echo 'Code : ' . $language->lang->code . '<br>'; echo 'Flag : ' . $language->lang->flag . '<br>'; echo 'Direction : ' . $language->lang->direction . '<br>'; echo 'Currency : ' . $language->lang->currency . '<br>'; echo 'Symbol : ' . $language->lang->symbol . '<br>'; echo 'Grouping separator : ' . $language->lang->grouping_separator . '<br>'; echo 'Decimal separator : ' . $language->lang->decimal_separator . '<br>'; echo 'Separator between amount and symbol : ' . $language->lang->separator . '<br>'; echo 'Show decimal : ' . $language->lang->show_decimal . '<br>'; echo 'Show symbol after amount : ' . $language->lang->symbol_after . '<br>'; Output: Title : English Code : en Flag : gb Direction : 0 Currency : GBP Symbol : £ Grouping separator : , Decimal separator : . Separator between amount and symbol : 1 Show decimal : 1 Show symbol after amount : 0
  22. 7 points
    $page->find()start from $page if $page != home { $page->find( 'parnet=/blog/' ) will.alwayse return NO things } so >>> u.must use $pages->find() noT $page->find() !! OAR u can.uses $pages->get('/blog/')->children( 'limit=3, include=all' ) if usesing $pages say shits bout array it mean yoU write-over it some where >>> u did a $pages = array some.where ! fix that.or u can uses wire( 'pages ')->find(' you.selectoro stuff here '); or functiones api pages()->find( 'selectros in this' ) amen
  23. 7 points
    Also worth noting that there is a 7 page book related to the rejection craze of jQuery and other libraries: https://www.oreilly.com/programming/free/native-javascript-apis.csp Quotes: "If you’re using native APIs in your application logic, you can’t help but know what browser is being used because you need to account for browser differences. That means your application logic will always need to be updated as new browsers and new browser versions are released. That’s a recipe for disaster. ... You should absolutely be using a JavaScript library to abstract away browser differences for you. ... Libraries like jQuery, YUI, and Dojo abstract away browser differences behind facades, which allow you to focus on building your application logic in a browser-agnostic way. ... So, keep using your favorite JavaScript library. Don’t be tempted by the draw of native APIs simply because you can avoid downloading an external library. Using native APIs comes with a high cost of maintainability down the road." People write spaghetti code because they do not know JavaScript well enough and/or do not use appropriate design patterns, which is not jQuery's or other libraries' fault. One can just as well produce unmaintainable code by using any framework out there. Here is the case of UIkit 3 which relies on its own 132k JS library which is only partially documented: https://github.com/uikit/uikit-site/blob/feature/js-utils/docs/pages/javascript-utilities.md They say: "...allow you to write simplified Vanilla JavaScript and replace the most common functions of jQuery" So they got rid of jQuery by partially re-implementing its features. Good to know... Now if I add jQuery I have overlapping feature sets and the visitor of the site has to download more assets Is it an improvement? At the same time the current full version of jQuery (3.3.1) is 87k and one can use versions leaving out features not needed (say AJAX or effects if not used on a site), so it can further be trimmed if the projects allows. Introducing a mature and maintained JS library called JsViews: Currently, I have started to build upon a library which can either be used along with jQuery or without it: https://www.jsviews.com/ It is from one of the jQuery authors. Worth checking out the examples, eg.: https://www.jsviews.com/#samples/computed/team-manager JsViews can be used without precompiled JS templating – so it is easy to get started – and it is still very performant that way. One can also use a builder to precompile the templates if needed (think of the needs of overly complex JS apps and NOT websites). By using JsViews one can rely on declarative programming and build upon design patterns built in. By adding jQuery to it, code becomes shorter, easier to read and maintain.
  24. 7 points
    @wbmnfktr, @Valery, @pwired Thanks for suggestions. I managed to get the desired result with HTML Purifier. $dirty = pages(11896)->archive_wysiwyg; $purifier = $sanitizer->purifier(); $purifier->set('AutoFormat.RemoveEmpty', true); $purifier->set('AutoFormat.AutoParagraph', true); $purifier->set('AutoFormat.RemoveEmpty.RemoveNbsp', true); $purifier->set('CSS.AllowedProperties', array()); $purifier->set('HTML.ForbiddenAttributes', array('*@class', 'img@width', 'img@height')); $purifier->set('HTML.ForbiddenElements', array('span', 'strong')); $settings = $purifier->getConfig(); $def = $settings->getHTMLDefinition(); $def->info_tag_transform['h1'] = new HTMLPurifier_TagTransform_Simple('p'); $def->info_tag_transform['h2'] = new HTMLPurifier_TagTransform_Simple('p'); $def->info_tag_transform['h3'] = new HTMLPurifier_TagTransform_Simple('p'); $def->info_tag_transform['h4'] = new HTMLPurifier_TagTransform_Simple('p'); $def->info_tag_transform['h5'] = new HTMLPurifier_TagTransform_Simple('p'); $def->info_tag_transform['h6'] = new HTMLPurifier_TagTransform_Simple('p'); $clean = $purifier->purify($dirty); // do something
  25. 7 points
    The final verdict is in! Thanks to everyone, I have moved the site to the new domain (actually it's duplicated but that's OK since I can erase the old one). When I started to act on the recommendations, I sort of accidentally discovered a 4th option (explained below) which worked. But I wish I'd done it the way suggested by @Robin S, @Autofahrn and @jens.martsch (updating $config->httpHosts in site/config.php). I'm sure that would have been even faster. So anyone else who comes across this thread looking to do the same sort of thing (moving site to new domain on same host), you might like to try that solution of $config->httpHosts in site/config . What I wound up doing However, I had not yet read those 2 latest responses at the time, so I was thinking about all the different methods and was looking to try the Duplicator module. Desiring to be a responsible site owner, I went to create a Softaculous backup of my site before trying the Duplicator module. This way I can restore my original site in 1 click if I do anything wrong. To my happy surprise, in the backup menu in Softaculous, one of the other options besides back up was "Clone site". Well, being curious, I thought "Let's try that, and if it doesn't work out, I can use one of the other methods people suggested". So, I tried Clone Site, and it worked perfectly! I just had to do point and click and tell it which of my domains to put the cloned copy of the site in, and boom, there it is at the new domain! After doing that, I then read the newest responses to my thread and realized that it would have been even faster to use the solution of Robin S, Autofarn and jens.martsch, but anyhow, the Softaculous method works too in case anyone has it available to them and was wondering about it. And after the site is in the new domain... A big thank-you to pwired for the advice given This turned out to be really helpful - I tried the search function in phpMyAdmin and found a few mentions of my old domain name still in there. It was clear from the results which pages I needed to edit in the processwire editor. So it may be a useful step for others too who are looking to do a similar type of domain move. Thank you again to everyone who responded in this thread. All of the suggestions were very useful. I really appreciate the sense of community here.
  26. 7 points
    Maybe I don't understand your problem correctly, but if you don't want to use a package manager, can't you just inject the css file for the theme directly as well? There's a CDN link on the themes page: https://unpkg.com/tippy.js@4/themes/light-border.css If you want to bundle all those files into a single dependency, I recommend Parcel, it's much simpler than webpack and you basically need no configuration for a basic compilation of JS/CSS dependencies into bundle files. I have just tried it out for a project I'm working on; this NPM script is all the config I needed: parcel build js/main.js --target browser --out-dir public/site/js --out-file bundle This will parse all code/imports in the main.js file and bundle them into a bundle.js file. It will also create a bundle.css file if you import any css.
  27. 6 points
    Here's a way to find all self-referencing page fields. Open your MySQL interface (MySQL Workbench, phpMyAdmin, adminer, whatever...) and execute the following query: SET @oldgcmaxlen = @@group_concat_max_len; SET SESSION group_concat_max_len = 32768; SELECT GROUP_CONCAT(querystring SEPARATOR 'UNION\n') as sqlstring FROM ( SELECT 1 as something, CONCAT( 'SELECT x.pages_id as id, y.name, z.data as title, \'', a.name, '\' as fieldname\n', 'FROM field_', a.name, ' x\n', 'JOIN pages y ON y.id = x.pages_id JOIN field_title z ON z.pages_id = x.pages_id WHERE x.pages_id = x.data\n' ) as querystring FROM fields a WHERE a.type = 'FieldtypePage' ) as inmemtbl GROUP BY something ; SET SESSION group_concat_max_len = @oldgcmaxlen; The result will be a UNION query that checks all your page fields for direct recursions. Here's an example: SELECT x.pages_id as id, y.name, z.data as title, 'permissions' as fieldname FROM field_permissions x JOIN pages y ON y.id = x.pages_id JOIN field_title z ON z.pages_id = x.pages_id WHERE x.pages_id = x.data UNION SELECT x.pages_id as id, y.name, z.data as title, 'roles' as fieldname FROM field_roles x JOIN pages y ON y.id = x.pages_id JOIN field_title z ON z.pages_id = x.pages_id WHERE x.pages_id = x.data UNION SELECT x.pages_id as id, y.name, z.data as title, 'language' as fieldname FROM field_language x JOIN pages y ON y.id = x.pages_id JOIN field_title z ON z.pages_id = x.pages_id WHERE x.pages_id = x.data UNION SELECT x.pages_id as id, y.name, z.data as title, 'pagesel' as fieldname FROM field_pagesel x JOIN pages y ON y.id = x.pages_id JOIN field_title z ON z.pages_id = x.pages_id WHERE x.pages_id = x.data Copy that query into the SQL editor and execute it. If there are any recursions, you will see them listed with the page id, page name, page title and field name.
  28. 6 points
    Holiday bookings - here's a video (no sound, so might have to guess what I was doing in places!) showing backend management of calendars (so in this example two holiday cottages/apartments) and different fee structures per cottage/apartment throughout the year for different seasons (though I'd probably approach that differently now). For the backend I made it possible to click and drag so you can select an odd number of days for a booking as a member of a sales team if you're taking a booking over the phone. On the frontend calendar (not in this video) the customer can only pick from pre-defined dates that are availble. You'll see some dates has bookings (Burlingham - my surname) and clicking on those takes you to the booking details - obviously customers viewing the frontend wouldn't see the other booking details It doesn't show the whole parment process but I think that was because it wasn't working with the Reno admin theme at the time I last looked at this code in 2016. I think to be honest I'd forgotten how interesting some of the things were that I'd done on here that the event calendar is probably the one to do first, followed by this accomodation booking one.
  29. 6 points
    First part... A quick test (ProcessWire 3.0.123 and FI 1.0.0) where I exactly did what you described and... it worked as expected. Added FI language pack to default Logout / Login Admin in finnisch Deleted all language files in default Logout / Login Admin in english again There were no mixed translations in the backend at all. Please try to log out and log in again. That sometimes helps with language hiccups. Or even clear browser cache including cookies / try another browser. Second part... Have had the same feelings about language handling at the beginning. But after ~20 multi-lang installations and lots of hours playing around with it my feelings changed. Works ~95% of the time I need it. Never had any real issues with it. WordPress: total fail Drupal: maybe it changed but a few years back it was quite painful Typo3: never seen a multilanguage setup that worked well Textpattern: mh... nope Silverstripe: can't really remember if it worked that well To be honest... I'm super biased in terms of ProcessWire as it gave me so much options and kind of freedom in the past to get almost everything done right from the start. But nonetheless I can't remember any real issues with multi-language setups, neither in front-end, nor in the backend.
  30. 6 points
    Most of my clients already have some sort of webhosting and only in very few cases it needs an update in terms of more features like SSL and similar things. If they don't have webhosting I recommend a middle-sized shared hosting from trusted providers. An all-in-one package works in almost every situation. Domain + Hosting + E-Mail management = ~15 EUR/month that's it and all they need. In the past I have had root servers and VPS to host client projects. It was a nice option, additional money, and a good way to keep clients close. But as regulations and laws changed over the past years I decided to stop offering hosting services. Hosting isn't that expensive anymore and you find really good options out there. Hosting providers are there for a reason. They take the hassle away from me. If your client already has a website, take a look at their web analytics to see how much traffic there is. You can then decide which way to go and what package might be a good deal if there are performance issues. As far as I can say... a good ProcessWire site doesn't need that much of a high performance hosting. Unless you can't use ProCache even a super cheap $3 shared hosting might work well enough. ProcessWire sites with ProCache, almost no real-time-database interactions, and only a few forms have a nice small footprint.
  31. 6 points
    You don't need to migrate to a new hosting server just because the domain name for a site changes. Point the domain to your host and update $config->httpHosts in /site/config.php. Depending on the type of hosting you might need to adjust a setting there too, e.g. update the primary domain if it's a cPanel host.
  32. 6 points
    If you don't create any variations on the front-end using size, width, etc. calls, ProcessWire won't create anything except for the variations created by default for admin (preview) purposes. Third party modules may still create their own variations, but if you're strictly against that behaviour, you can always avoid using any modules that do this What you're probably missing here is the amount of data: sure, browsers can handle resizing images, but if you're considering load times and amount of data users have to download to use your site, you absolutely want to resize images before they hit the visitors' browsers. When you're asking if this behaviour should be disabled to "reduce additional http requests (if the user resizes viewport)", it kind of sounds like you've implemented srcset on your site – otherwise there shouldn't be a additional requests when the viewport is resized due to images. Even then if you start with a larger viewport and then resize it to smaller size, browser shouldn't load the smaller sizes. Only case generating additional requests is when you go the other way, from small to large – otherwise tiny images would likely look pretty awful scaled to a larger size. Short answer is: no, it shouldn't be disabled. That being said, you don't have to create any additional variations if you don't want to – but be considerate of the user and don't make them download more data than they actually need
  33. 6 points
    Although I don't know what your reasons for using var_dump(), I really recommend that you use the module TracyDebugger instead. It will give you better and cleaner information regarding any ProcessWire objects and their properties.
  34. 5 points
    Hi Charles, I've enjoyed reading the PW Review website over the last couple of days. The interview with Ryan is illuminating, and the technical information and videos are thorough and clear. It's obvious that you've put a lot of time and effort into the site and it will be especially helpful to new PW users. Thanks! I have a bit of feedback about the appearance of the site. Please take or leave it as you see fit - nothing that follows had any significant impact on the readability of the site. 1. It would be nice to make the header a bit more visual - maybe use the PWR logo in the header to give the site some clearer branding? 2. A favicon would be a nice touch. 3. There seems to be a styling glitch that is pulling the main content to the left on some pages: I'm not sure what's causing it because I'm not very familiar with Uikit but maybe someone here who is a regular Uikit user will have some advice. 4. Some of the headings are not immediately recognisable as headings. I think this is because the lower-level headings like h5 and h6 are as small or smaller than the body text and use the same weight as the body text. My suggestion would be to use a bold weight for the smaller headings so they are more recognisable as such. One of your tutorials explains how you modified the Uikit CSS so some headings have different colours: IMHO this is not such a good idea because it makes it a harder for the reader to know what is a link/clickable and what is a heading because there isn't a consistent colour to identify headings. True story: the Page Clone article was one of the first pages I read on the site and I clicked the "Related Source Documentation" text because I thought it was a link. This is all minor stuff. I'm looking forward to reading more as you add new content to the site!
  35. 5 points
    Works like a charm! Thank you for this! And also, I want to thank every one for motivating me to write hooks and seeing how practical and easy they're to make!
  36. 5 points
    $wire->addHookAfter('ProcessPageEdit::buildForm', function($event) { $page = $event->object->getPage(); if($page->template != 'home') return; // example if($page->isUnpublished()) return; $form = $event->arguments(0); $field = $form->getChildByName('title'); // example $field->collapsed = Inputfield::collapsedNoLocked; });
  37. 5 points
    PageHitCounter Version 1.2.4 Thanks to @wbmnfktr for reporting the issues. And thanks to @Sergio for the corrections. Both issues have been fixed in version 1.2.4 and the corrections have been applied. Changelog as always updated in the first post. Explanations of the bugs below. The functionality has always been and is correct. The module sends the data to a fictitious endpoint of the current page. Then the module hooked in before a 404 is triggered and writes the data. The problem here was that the module "Jumplinks" had a lower priority than PageHitCounter. Therefore the request was logged as 404, because jumplinks were executed earlier. Now fixed, PageHits are not logged as 404, regular 404s will be. Here was the problem that system templates or pages are excluded in the normal search, without the selector "include=all". This is now included by default. Oh, my gosh, there were a lot of typos in there. So if you have a lot on your mind what you're going to code next, you don't look at the comments. Anyway, many thanks for the corrections! And by the way, I'd love to. Take the code and build something new out of it!
  38. 5 points
  39. 5 points
    What could the controller look like then?
  40. 5 points
    This profile can be used as a simple business card or it can be used as a starting profile. Live Example Can download from this link: https://github.com/rafaoski/site-minimal Basic Info Most of the profile settings and translates are in the _init.php file. Functions can be found in the _func.php file. The entire view is rendered in the _main.php file that uses markup regions. You can easily add hooks using the ready.php file. Options page added with the new “Unique” status, which you can use in this simple way like: pages('options')->site_name pages->get('options')->site_name f you want to use Laravel Mix you must first ensure that Node.js and NPM are installed on your machine. Basic example to Debian and Ubuntu based Linux distributions: Node.js curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - sudo apt-get install -y nodejs See more installation options LINK npm is installed with Node.js just check in linux terminal like below: node -v npm -v Set BrowserSync inside folder /templates/webpack.mix.js and change your dev url proxy: 'http://minimal.test', to your installation processwire folder like: proxy: 'http://localhost/your-processwire-installation-folder/', Next install npm packages in your templates folder with command npm install Now, boot up the dev server npm run watch, and you're all set go! On completion, use the command npm run production to build styles and scripts in the dist folder Simple Usage ( Basic Command ) Run npm install Watch npm run watch Build npm run production All files to Webpack build steps is inside file ( webpack.mix.js ) Folder With all SCSS files is inside templates/asets/src/scss All build styles and scripts is inside the templates/assets -- /css/mix.css -- /js/app.js
  41. 5 points
    In recent posts, Kongondo has mentioned quite a bit about his use of Linux. I am certain there are other users of Linux here in the community forums of ProcessWire I have been a loyal user of FOSS and GNU Linux for as long as I can remember. Every single Android device I have owned has been rooted. My Linksys router runs DD-WRT. Every computer I have had has had some distribution of Linux at one time or another. Back in the late 90's my ex-girlfriend gave me a big box set of Suse and another of RedHat. I have since then distro-hopped from those to Arch, Mandrake, Suse, everything *buntu and I settled on Crunchbang++ for a few years. I have yet to play with CentOS or Linux From Scratch (LFS) but that is on the horizon I have always preferred Debian and everything in its family tree, including Sparky. I just don't like XFCE nor LXDE. Openbox has always appealed to me, as well as i3wm. I finally got around, by special request by Kongondo, to share my LAMP set up. It's a file I have modded over the years but it remains pretty simple. I formatted it to MarkDown and threw it up on github for your viewing. I hope to help our growing community in something I kinda sorta know a bit about https://github.com/OrganizedFellow/LAMP
  42. 5 points
    Have you tried this: https://processwire.com/talk/topic/45-url-schema/?do=findComment&comment=150 "ProcessWire will support .html extensions. You just have to make them your page names, i.e. "about.html" rather than "about", or look for them in urlSegments. I've actually done this before, though for specific pages (like /sitemap.xml), not on a site-wide basis. But I don't see any problem with it conceptually."
  43. 5 points
    Flags are only for internal use. You most likely cannot use them in selectors. Also you don't need to try to be efficient when selecting templates, as all templates are loaded as part of the processwire bootstrapping process, so you can simply iterate $templates and select only non system templates without using a selector. Everything's in memory anyways.
  44. 5 points
    Agreed. I think that perhaps the best solution is for you to maintain the module, integrating anything applicable from my version. I’d be happy to help with this process.
  45. 5 points
    Could that "Forums" text in breadcrumb be a link to forum frontpage?
  46. 5 points
    You can install the predefined page-publish system permission: https://processwire.com/docs/user-access/permissions/#page-publish Then do not give the role that permission for the template of the page in question.
  47. 5 points
    A sad day for the internet, the EU, the democracy, and so much more. I don't know anything about any #article13 discussions, protests or media coverage in Spain or anywhere else but at least here in Germany - especially in the last weeks and days - the way of communication from politicians towards protestors, their statements against protests, and media coverage that supports that copyright directive were kind of shocking. They said some really weird things like... Online-protesters were bots. Mailings were from Google (as most of those mails came from gmail.com addresses). Those on the streets were paid [from big US companies]. ... and so on Yet another bad aftertaste especially for Germany and our politicians: https://edition.faz.net/faz-edition/wirtschaft/2019-03-26/f30a5870c08cc1e1b4524c1be19d1faf/?GEPC=s3 Maybe I never fully realized that degree of misleasing information from politicians and media but now I'm not only upset but actually really p*ssed. There seems to be a last option left but I really don't know if this will ever happen but... maybe. Back to your topic: those already big platforms will do fine with that. YouTube already has its Content ID system in place and therefore can offer APIs to those who will need it in the future. At least for video material. But the main issue I have with this copyright directive is this argument "Copyright-holders and creators should earn money with their work!" which is totally fine by all means. But that directive will not help any content creator on any plattform. How could it? Independent writers, musicians, DJs, fotographers, even programmers will still have the problem to find all those pirated copies of their work. They won't earn more money. They still have to prove their copyright claims. But on the other hand publishers got some more power to bypass money from the real creators. And they got their link tax foundation they always asked for. But... there is a positive side-effect. I learned to look closer. I learned to trust less. I learned to think more than twice. I learned who might not be on my side. And I learned who to vote for the next election. Regarding Alex Jones and de-platforming: That was never a real topic here in Germany at all. At least I saw only very few articles or side-notes somewhere or at the bottom of a newsfeed. That's it. And if you find anything about it, they applaud about it because he is some kind of a bad person. This narrative or bias at Twitter, Facebook, YouTube, [name more here] and the banning of people from their platform wasn't invented by those platforms. They would be doing totally fine even with all of those now banned people. Maybe even better. It was cultivated over the last few years.
  48. 5 points
    ProcessWire InputfieldRepeaterMatrixDuplicate Thanks to the great ProModule "RepeaterMatrix" I have the possibility to create complex repeater items. With it I have created a quite powerful page builder. Many different content modules, with many more possible design options. The RepeaterMatrix module supports the cloning of items, but only within the same page. Now I often have the case that very design-intensive pages and items are created. If you want to use a content module on a different page (e.g. in the same design), you have to rebuild each item manually every time. This module extends the commercial ProModule "RepeaterMatrix" by the function to duplicate repeater items from one page to another page. The condition is that the target field is the same matrix field from which the item is duplicated. This module is currently understood as proof of concept. There are a few limitations that need to be considered. The intention of the module is that this functionality is integrated into the core of RepeaterMatrix and does not require an extra module. Check out the screencast What the module can do Duplicate a repeater item from one page to another No matter how complex the item is Full support for file and image fields Multilingual support Support of Min and Max settings Live synchronization of clipboard between multiple browser tabs. Copy an item and simply switch the browser tab to the target page and you will immediately see the past button Support of multiple RepeaterMatrix fields on one page Configurable which roles and fields are excluded Duplicated items are automatically pasted to the end of the target field and set to hidden status so that changes are not directly published Automatic clipboard update when other items are picked Automatically removes old clipboard data if it is not pasted within 6 hours Delete clipboard itself by clicking the selected item again Benefit: unbelievably fast workflow and content replication What the module can't do Before an item can be duplicated in its current version, the source page must be saved. This means that if you make changes to an item and copy this, the old saved state will be duplicated Dynamic loading is currently not possible. Means no AJAX. When pasting, the target page is saved completely No support for nested repeater items. Currently only first level items can be duplicated. Means a repeater field in a repeater field cannot be duplicated. Workaround: simply duplicate the parent item Dynamic reloading and adding of repeater items cannot be registered. Several interfaces and events from the core are missing. The initialization occurs only once after the page load event Changelog 1.0.4 Bug fix: Various bug fixes and improvements in live synchronization Bug fix: Items are no longer inserted when the normal save button is clicked. Only when the past button is explicitly clicked Feature: Support of multiple repeater fields in one page Feature: Support of repeater Min/Max settings Feature: Configurable roles and fields Enhancement: Improved clipboard management Enhancement: Documentation improvement Enhancement: Corrected few typos #1 1.0.3 Feature: Live synchronization Enhancement: Load the module only in the backend Enhancement: Documentation improvement 1.0.2 Bug fix: Various bug fixes and improvements in JS functions Enhancement: Documentation improvement Enhancement: Corrected few typos 1.0.1 Bug fix: Various bug fixes and improvements in the duplication process 1.0.0 Initial release Support this module If this module is useful for you, I am very thankful for your small donation: Donate 5,- Euro (via PayPal – or an amount of your choice. Thank you!) Download this module > Github: https://github.com/FlipZoomMedia/InputfieldRepeaterMatrixDuplicate > PW module directory: – soon –
  49. 5 points
    @happywire don't forget that a Page is not an array or similar, but a PHP object with protected and private fields. From the "top" (like print_r($page)) you may see some internal attributes (like the array of hooks), but you can not directly access those fields. To retrieve, for example, the table of hooks, you'll need to use an allowed method, like print_r($page->getHooks()). Same for any field placed on your template. Their content is not retrieved everytime you see a $page but only after an access. If you do something like $page->someField, then you do not access a member from that object, the Page object intercepts the access operator and retrieves 'someField' from the database, caches its content in the page object and performs any kind of output formatting specified for that particular field. So, to obtain a list of fields available on a particular page, you'll do a $page->getFields(), which you may use to enumerate all fields and dump their contents: foreach($page->getFields() as $fldName) { echo "{$fldName}: {$page->$fldName}<br/>"; echo '<pre>'; print_r($page->$fldName); echo '</pre>'; } Edit: if you print_r($page) before and after that loop you'll see the embedded ['data'] array populated. And similar will do for $image->getVariations();
  50. 5 points
    Hi @adrian, A lot of the code is much the same, but tidied up with the the coding style guide implemented, so I'm not surprised the diff doesn't reveal much! The readme is pretty thorough and covers a lot, but here's the gist: addData() - add X-Mailgun-Variables - https://documentation.mailgun.com/en/latest/user_manual.html#attaching-data-to-messages - to be honest don't know what use cases there are for it but it's in the API and was easy to implement addTags() - add multiple tags as an array getHttpCode() - to get the response code from either send() or validateEmail() * Most methods now chainable (see the Advanced Example in the readme) Tracking only used if bodyHTML() is set (As this only works in HTML email) cc() and bcc() only used when batchMode is off - this seems to me to be the correct implementation WireMail::htmlToText() used for generating the text version if only HTML passed (as in WireMail now) The ASCII conversion for tags now uses $this->sanitizer->nameFilter($tag, [" "], "", false, 128); WireMail::replyTo() implemented - doesn't seem to have been before removed addAttachment(), now uses WireMail::attachment() - which adds the ability to set the filename Unixtime is now passed to setDeliveryTime() A bunch of other small tweaks like using $sanitizer->email() in validateEmail() * I'd wanted to use WireHttp for the requests, but it doesn't allow custom cURL options. I have done a pull request for this, but I don't think I'll be changing the module's cURL request implementation now anyway. Cheers, Chris
×
×
  • Create New...