
abdus
Members-
Posts
743 -
Joined
-
Last visited
-
Days Won
42
Everything posted by abdus
-
What does your session log show? (Setup > Logs > session) Also, I'm having a similar issue. Session cookie is set to expire with session, so it asks for password at least once an hour.
-
[WIP] ProcessMailer - A module for managing and sending newsletters
abdus replied to abdus's topic in Modules/Plugins
Thanks @tpr , it looks quite useful, I'll be sure to check it out. -
A client of mine was asking for a solution to send newsletter mails to a list of subscribers. I looked around for a module, but couldn't find any. Then I saw a screenshot on this blog post about UIKit update, and decided to recreate it. Huge thanks to @ryan for the inspiration. The module uses regular pages for building HTML content. These pages can be used to create a fallback link in emails (i.e. "Use this link if you can't view email properly"). During render it injects $page->mailerMode, which can be used to change page output between text and HTML, or to show a simplified, email only HTML output. Screenshots: Main screen is just a list of items. Create page: Module configuration page: During installation, module creates a page under admin for storing items similar to FieldtypeRepeater. It also creates some fields for storing mail info Todo: More testing Sending in batches (with a script that runs in background and real-time progress log) Plans: Integration with Mailchimp (for subscriber lists) Automation (as a separate module for creating email content pages) I'm hoping to complete and release the module in the following days. I think these features should be enough for the beginning, but I'm open to suggestions.
-
While I agree on having more detailed documentation on module development, you can still add inputfield selector to FieldtypeText by hooking FieldtypeText::getConfigInputfields Again, not tested: wire()->addHookAfter('FieldtypeText::getConfigInputfields', function (HookEvent $e) { $wrapper = $e->return; require_once($e->config->paths->FieldtypeTextarea . 'FieldtypeTextareaHelper.php'); $helper = new FieldtypeTextareaHelper(); $inputfields = $helper->getConfigInputfields($e->arguments(0), $wrapper); });
-
I think a module is modifying your field editor, I don't have an "After Save" fieldset on my setup. Also, change the field type to textarea, or change inputfield class to extend InputfieldText class instead
-
Thanks @benbyf, I really appreciate it. I'm working on a v2, and hopefully I'll release it in a few weeks. You dont have to create a new Fieldtype, using a Textarea field (to store Dropbox folder path or JSON) with a custom Inputfield (for picking Dropbox folders) should suffice. I'll try to flesh out how you would go about creating what I meant in the previous post: Note: I haven't tested the code below. Regard it as pseudo-code if you will. Create an Inputfield class InputfieldDropboxFolderPicker extends InputfieldTextarea { public function ___renderReady() { $this->modules->JqueryUI->use('modal'); $this->config->scripts->add(__DIR__ . '/dropboxfolderpicker.js'); } public function ___render() { $attrs = $this->getAttributes(); unset($attrs['value'], $attrs['size'], $attrs['type']); $attrs = $this->getAttributesString($attrs); return " <div class='InputfieldDropboxFolderPicker'> <textarea $attrs class='hidden'></textarea> <a class='pw-modal' href='/url/to/my/process/module/?modal=1'>Pick Dropbox Folder</a> </div> "; } } Continue by creating a ProcessField that uses DropboxAPI and shows a list of folders. Use ProcessPageEditLink.module and ProcessPageEditSelectImage.module modules as your guide. class ProcessDropboxFolderPicker extends Process { public static function getModuleInfo() { ... } public function execute() { /** @var $form InputfieldForm */ $form = $this->modules->InputfieldForm; $form->action = './'; $form->method = 'GET'; $folders = $dropboxApi->getFolders(); $form->add([ [ 'type' => 'radios', 'id' => 'pickedFolder', 'label' => 'Your folders', 'optionColumns' => 2, 'options' => $folders ] ]); return $form->render(); } function install() { /** @var $p Page */ $p = $this->installPage('dropbox-picker', null, 'Dropbox Folder Picker', 'admin'); $p->addStatus(Page::statusHidden); } function uninstall() { $this->uninstallPage(); } } Finally a JS file to bring it all together. (\wire\modules\Inputfield\InputfieldCKEditor\plugins\pwlink\plugin.js) // dropboxfolderpicker.js let $textarea = $('.InputfieldDropboxFolderPicker textarea'); let modalSettings = { title: "<i class='fa fa-link'></i> Pick Dropbox Folder", open: function() { // }, buttons: [{ 'class': "", 'html': "<i class='fa fa-link'></i> Submit", 'click': clickInsert }] }; // create modal window let $iframe = pwModalWindow(modalUrl, modalSettings, 'medium'); // modal window load event $iframe.load(function() { let $i = $iframe.contents(); $i.find("#ProcessPageEditLinkForm").data('iframe', $iframe); // capture enter key in main URL text input jQuery("#link_page_url", $i).keydown(function(event) { let $this = jQuery(this); let val = jQuery.trim($this.val()); if (event.keyCode === 13) { event.preventDefault(); if(val.length > 0) clickInsert(); return false; } }); }); // load function clickInsert() { let $i = $iframe.contents(); let pickedFolder = jQuery("#pickedFolder", $i).val(); let data = { 'picked': pickedFolder }; $textarea.val(JSON.stringify(data)); $iframe.dialog("close"); } Feel free to ask questions and good luck
-
Hook before/after Password::setPass() method instead? Keep in mind that this hook is called before page publish (while setting value for a password field) /** * Set the 'pass' to the given value * * @param string $value * @throws WireException if given invalid $value * */ protected function ___setPass($value) { // if nothing supplied, then don't continue if(!strlen($value)) return; if(!is_string($value)) throw new WireException("Password must be a string"); // first check to see if it actually changed if($this->data['salt'] && $this->data['hash']) { $hash = $this->hash($value); if($this->isBlowfish($hash)) $hash = substr($hash, 29); // if no change then return now if($hash === $this->data['hash']) return; } // password has changed $this->trackChange('pass'); // force reset by clearing out the salt, hash() will gen a new salt $this->data['salt'] = ''; // generate the new hash $hash = $this->hash($value); // if it's a blowfish hash, separate the salt from the hash if($this->isBlowfish($hash)) { $this->data['salt'] = substr($hash, 0, 29); // previously 28 $this->data['hash'] = substr($hash, 29); } else { $this->data['hash'] = $hash; } }
-
@LostKobrakai, a bit tangential, but can I allow editors (non-superuser) to modify settings for only a set of modules (TextformatterAutolinks for instance)?
- 14 replies
-
- admin
- permissions
-
(and 2 more)
Tagged with:
-
I just noticed that I forgot to populate $fieldValues array, which effectively removes unique value check. You need to add $fieldValues[] = $record->textField at the end of foreach loop
-
+1 I really like whoops's color scheme and layout but I guess Tracy is packed with more indispensable features.
-
Just append the script to $value? You don't need to hook page render at that point
-
Here's a micromodule for you: Save this in site/modules/TextformatterCurrentYear/TextformatterCurrentYear.module. Then refresh modules and install it. Once it's installed, add it to your field's textformatter list. It will replace all instances of `curryear` with the current year (4 digits `2017` for example). You can set it once and forget it <?php namespace ProcessWire; class TextformatterCurrentYear extends Textformatter { public static function getModuleInfo() { return [ 'title' => 'Current Year Replacer', 'version' => '1.0.0', 'summary' => 'Replaces `curryear` with current year', ]; } public function format(&$str) { $str = str_replace('curryear', date('Y'), $str); } }
-
Nice one @Robin S, I've never seen that one used anywhere before. It seems to fetch all fields before handing you an ArrayObject. public function getIterator() { $a = $this->settings; if($this->template && $this->template->fieldgroup) { foreach($this->template->fieldgroup as $field) { $a[$field->name] = $this->get($field->name); } } return new \ArrayObject($a); } One thing that I'd like to have with explode() method is to get deeper fields with dot notation, such as $thumbData = $page->explode(['url', 'title', 'images.first.url', 'tags.count']); like underscore.php (or understore.js) does. I guess I should start building a module.
-
Simply put: a field is an interface to DB, an inputfield is an interface to user. One does not necessitate the other, but for some complex data types, you may need to build a custom inputfield (like MapMarker). If you're going to store information about multiple books on a single page, then you need to extend FieldtypeMulti class (FieldtypeEvents, FieldtypeNotifications, FieldtypeComments for example), to store information about a single book per page, you need to extend regular Fieldtype class (FieldtypeText, FieldtypeDatetime etc). If you want to allow more than 1 property to be used in selectors, then you need to use multiple table column in DB. This means you need to override getDatabaseSchema() method and specify a more complex table structure. Edit: Based on your description, you expose only one input to the user for ISBN/title, filling the rest is up to you (by fetching from a web service). You have two options: either fetch the data using fieldtype or using inputfield. Using inputfield to do fetch the rest of the data sounds more appropriate, because the purpose of the fieldtype is validation, formatting, sanitization querying and saving data from/to database, i.e. it only deals with the given data. An inputfield, however, collects and prepares all data that needs to be written to the database and presents it to a fieldtype.
-
There's a function in the core for this: function wireRelativeTimeStr($ts, $abbreviate = false, $useTense = true) {...)
-
Thanks for sharing it with us. I've been planning to do something like this but on the frontend. I have but one request. Can you add a randomization logic? [dc:3-6p] -> mt_rand(3, 6) // paragraphs [dc:4-15w] -> mt_rand(4, 15) // words
-
Unable to select the template I created for a specific page
abdus replied to mhamurray's topic in General Support
Ok, I've checked out the source. It could also be a permission issue. Check if you changed access settings for a role. // ProcessPageAdd.module /** * Returns an array of templates that are allowed to be used here * */ protected function ___getAllowedTemplates($parent = null) { // ... $templates = []; // ... foreach ($allTemplates as $t) { if ($t->noParents == -1) { // only 1 of this type allowed if ($t->getNumPages() > 0) continue; } elseif ($t->noParents) { continue; } if ($t->useRoles && !$user->hasPermission('page-create', $t)) continue; if (!$t->useRoles && !$parentEditable) continue; if (!$t->useRoles && !$user->hasPermission('page-create', $parent)) continue; if (count($allParents) == 1) { if (count($parent->template->childTemplates)) { // check that this template is allowed by the defined parent if (!in_array($t->id, $parent->template->childTemplates)) continue; } } if (count($t->parentTemplates)) { // this template is only allowed for certain parents // ... } // ... $templates[$t->id] = $t; } // ... $this->allowedTemplates = $templates; return $templates; } -
Yup. That's a really nice feature of hooks. You can use it anywhere after the point you set it. https://processwire.com/api/hooks/#where_define
-
Unable to select the template I created for a specific page
abdus replied to mhamurray's topic in General Support
Go to to a Setup > Templates. Pick a template, open Family tab, you'll see the list of allowed templates there -
No but you can use a hook like this: wire()->addHookMethod('Page::explode', function (HookEvent $e) { $arr = new WireArray(); $arr->add($e->object); $e->return = $arr->explode($e->arguments(0))[0]; // ONE LINER // $e->return = (new WireArray)->add($e->object)->explode($e->arguments(0))[0]; });
-
This means you've set up the file field to give you an array of files (Pagefiles), you need to get the file using annual_report->first->url. Using annual_report->url gives you the directory. You can limit field to 1 file and return you a Pagefile object instead of an array (Pagefiles) too
-
Yes, it's for getting only the desired fields. Normally PW fetches them lazily (to save memory) with multiple queries but with this method everything can be done in a single query. A lazy method can still be in there somewhere
-
@ryan is usually pretty adamant about extending the core for a feature that very few people will use. So I doubt he'll agree on that. Because it would mean rewriting a good chunk of the core and breaking many 3rd party modules, or having to maintain a separate set of underutilized classes. Feel free to open up an issue, though. If you study PagesLoader class you can figure out how PW fetches fields from their respective tables and maybe develop a module that works aside the current implementation. I, for one, wouldn't mind using something along the lines of: $list = $db->pages->posts->where('title.length>5')->fetch(['title', 'name', 'body']);
-
Yeah I agree. It's too verbose for starters. But you're free to use any PDO / ORM library over ProcessWire's. You can get database credentials with $config->db<key>, and use it anyway you'd like. But unless you're using custom tables, you'll have to join multiple tables to get a meaningful output from pages/templates/fields, all of which PW provides out of the box for you.