Leaderboard
Popular Content
Showing content with the highest reputation on 06/05/2016 in all areas
-
Hola amigos I wrote a little DOMDocument magic (long time ago) which would automatically link images add classes for Magnific Popup set alt tag wrap the whole thing in a figure insert figcaption if image description available and wrap multiple figures in a container think that's it.. So for our articles we only needed to open pwimage popup in cke, choose desired image, set the size and alignment To caption images we use description input from image field It was a nice starting point, and at some point I changed DOMDocument to SmartDOMDocument wrapped the code into TextformatterBlogImages.module.. But I had ideas to simplify the whole process..and due to a problem with the old implementation which broke design (just realised it a week ago, or that it's linked to my Textformatter) I finally took the time and rewrote the whole thing. Problem was that figure is not a valid child of <p> so at least in chrome I ended up with orphaned text and an empty paragraph so the text style differed from the rest.. I'm posting this as a boilerplate/resource/idea, it's really basic..everything is hardcoded and it's not flexible right now.. So there is the Textformatter module and a hook which is placed in my /site/ready.php right now but might be moved somewhere else.. Maybe it can become a proper module..Maybe I find time to do so..but if someone is interested everyone is welcome to grab the code and extend/modify for their own needs Here's a little animated gif screencast (it's shrinked so the quality is not very beautiful..) So what it does right now: TextformatterBlogImages.module: first it replaces double line breaks like <br><br> or <br /><br /> or any other combination with </p><p> (I had such occurences) parses the article for <p> tags using simple_html_dom finds all containing images it extracts the image name stripping image variations gets the corresponding pageimage from images field the image itself will be replaced by markup used with LazySizes JS plugin (https://github.com/aFarkas/lazysizes) Example: <img src="fullImageUrl" srcset="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-srcset="smallUrl smallWidth, medium mediumWidth, full fullWidth" data-sizes="auto" width="fullImageWidth"> data-sizes="auto" works for now but I might replace it by normal sizes markup, manually deciding how images should be chosen width="fullWidth" I read that images with width attribute render faster but I'm not sure if this is true even if the image is downsized by css? then the new image will be linked to full size image link with markup for js modal (wrote my own, but not ready yet) if image class contains "align_left" or "align_right" it will wrap it in span moving classes from img to span if pageimage got a description it'll insert the descr below the img within span in another span the old image will just be replaced by the new span image so it will be in the same place it image is not aligned (or align_center) it wraps the image in figure moving img classes to figure and description will be wrapped in figcaption and the figure will be stuffed in an own container before the paragraph (original image within p will be removed) The figure gets a class landscape or portrait according to the aspect ratio Uh, I added another hook property called Pageimage::cdn so the images will be served directly from assets subdomain (using domain sharding option from AIOM but saving the extra redirect) Then there is another "round" reparsing the article for newly created figure containers adding additional class containing the number of children and another class indicating how many of the images are landscape/portrait for later styling like 2lx1p for 2 landscape and 1 portrait We add rows of 1 to 4 images, not more so my stylesheet contains rules for all possible cases like 1 landscape 2 portraits, 3 landscapes 1 portrait and so on to resize the images so alls images in a row will have the same height and the row will be always as wide as the main container as seen in the gif above Because the textformatter is doing everything for us I added a little clickable area to each image in the image field and a little javascript which inserts an image into body cke field on click at caret position Only thing to do is manually break the line after 4 images (or less) (NOTE: This javascript code inserting the clickable area requires at least PW 3.0.17 with new image field, as mentioned by Robin S below) For inline images I have to modify, I guess, the javascript a little, or maybe I can add another script which adds 3 links to inserted images, which add alignment classes to the image Here you'll find the files (and code snippes) https://gist.github.com/CanRau/662a559a07d6d7c492159d1cd497944f Any questions, ideas, improvements, concerns and other comments are highly appreciated PS: I'm not using it in production yet, just finished the version, I think I need to review all articles first to ensure proper migration, and maybe I add the inline handling to the javascript as mentioned before PPS: If you're interested in using this you should at least cache the textformatter output using WireCache, or TemplateCache or you can of course use ProCache, but I wouldn't recommend using it without any caching mechanism as it would re-do all the work every time someone requests the page.. Un Saludo Can4 points
-
Fixed (at least half of the "problem") the inline image issue by extending CKEditor's contextmenu. So I added 3 menu items "alignLeft", "alignRight", "removeAlignment" First step, and it's working good. As a second step I wanted to add some preset sizes to the contextmenu like "small", "medium", "large" which would set the img size attribute But it's not yet working, no errors but no changes.. var editor = CKEDITOR.instances.Inputfield_body; editor.on( 'instanceReady', function(e) { if ( editor.contextMenu ) { editor.addCommand('alignLeft', { exec: function (editor) { var element = editor.getSelection().getStartElement(); element.removeClass('align_right'); element.addClass('align_left'); } }); editor.addCommand('alignRight', { exec: function (editor) { var element = editor.getSelection().getStartElement(); element.removeClass('align_left'); element.addClass('align_right'); } }); editor.addCommand('removeAlignment', { exec: function (editor) { var element = editor.getSelection().getStartElement(); element.removeClass('align_left'); element.removeClass('align_right'); } }); editor.addCommand('small', { exec: function (editor) { var element = editor.getSelection().getStartElement().$; console.log(element); element.attributes.width = 100; } }); editor.addMenuGroup( 'HappyImages' ); editor.addMenuItems({ alignLeft : { label : 'Rechts umfließen', command : 'alignLeft', group : 'HappyImages', order : 1 }, alignRight : { label : 'Links umfließen', command : 'alignRight', group : 'HappyImages', order : 2 }, removeAlignment : { label : 'Nicht umfließen', command : 'removeAlignment', group : 'HappyImages', order : 3 }, small : { label : 'klein', command : 'small', group : 'HappyImages', order : 4 } }); } editor.contextMenu.addListener( function( element ) { if ( element.getAscendant( 'img', true ) ) { return { alignLeft: CKEDITOR.TRISTATE_OFF, alignRight: CKEDITOR.TRISTATE_OFF, removeAlignment: CKEDITOR.TRISTATE_OFF, small: CKEDITOR.TRISTATE_OFF }; } }); }); Maybe someone knows why the small command is not working? Other ideas, improvements and any feedback is always welcome2 points
-
This module extends WireMail base class, integrating the PHPMailer mailing library into ProcessWire. Module Directory - Githup repo1 point
-
Working through GitHub issue reports was the focus of this week, and it looks like we've got one more week to go in working through the current queue. There have not been any major bugs in 3.x, so things are looking more and more stable. Most updates in this weeks version (3.0.20) are about fixing minor bugs and various cosmetic things. There's nothing particularly exciting to report in this version other than that. But working towards a fully stable 3.x master version is itself an exciting thing. So rather than focus on the small tweaks and fixes from this week, lets backtrack and review all that's new in 3.x relative to the current 2.7 master version… https://processwire.com/blog/posts/review-of-processwire-3.x-so-far/1 point
-
actually this is in the core, all you need to do is add these to your toolbar (you don't need to add any plugins): so where your first line would look like this out of the box: Format, Bold, Italic, -, RemoveFormat you can change it to be like this: Format, Bold, Italic, Underline, -, RemoveFormat, -, TextColor, BGColor1 point
-
Here is a little trick how a user the user template to manage things like a /profile/ page to frontend edit a users profile and this could be easy used for a own register logic and let the new user fill in all needed fields....the logic could be implemented via URL segments: //load module $fh = $modules->get('FormHelper'); // Template based form, skip fields 'title' and other adminfields, unstyled $form = $fh->create($templates->get('user'), array( 'notifications', 'admin_theme', 'language', 'roles', 'user_email', //this is where we fill a created token/hash to register the user and verifie via emaillink... 'confirm' //confirm link for an admin to set user created stuff puplic )); and in your template you could use URL segements for very simple or complex logic on registration - in my case i need to register a user but hide his content until an admin activated the user...email from the user itself should have to be validated, too so i've to build my own code here...since i wanna stick to just email + password and let the username created automatical in the background...this is just the basic for such a template nothing fancy here - maybe i wrote a little topic if it is running stable. Pseudocode for a template file register.php and URL's like: http://mysite.com/app/regsiter/URLsegment1/UserID/Hash http://mysite.com/app/register/activate/1235/fb5a44cfc2ecd8b5667a667319b66688 http://mysite.com/app/register/confirm/1235/d41d8cd98f00b204e9800998ecf8427e // we are using 3 URL segment, so send a 404 if there's more than 1 if($input->urlSegment4) throw new Wire404Exception(); switch ($input->urlSegment1){ case '': // segment 1 is empty so display normal content/register form // users could submit the register form and a new user is created two tokens are generated // email to the user and to admin // user is logged in and can add content - but the content will only published if // his two tokens are created on the first step to validate his email and confirm by an admin break; case 'activate': if ($input->urlSegment2){ // check for the user id if ($input->urlSegment3 == user_email) // check for the email token // user has get an email on submit the register form with a token link // and he hit this link so publish/activate the user and show him a message // delete user_email token break; case 'confirm': if ($input->urlSegment2){ // check for the user id if ($input->urlSegment2 == confirm){ // the user is confirmed by an admin and his content is published, delete confirm token break; default: // Anything else? Throw a 404 throw new Wire404Exception(); } This is just a example to how to rebuild the functions of the EmailValidation module in a flexible way with URL segments and some additional fields on the user template....AND the awesome form module from pwFoo... URL segments could setup with an regex in the template settings like this: regex:^[0-9]*$ //regex for user id regex:^[a-f0-9]{32}$ //reges for a hash/token If my project is finished i will provide more and detailed examples with templates and FormHelper! Best regards mr-fan1 point
-
Yep, same error. I managed to do what I wanted by adding after line 266 in "FrontendUser.module" the following code: $value = $field->value; $sanitizedValue = wire('sanitizer')->pageName($value); if ($value != $sanitizedValue) { $field->error('Your username cannot contain uppercase letters, spaces, accents or special characters.'); } But of course hacking the module is not the recommended way to proceed.1 point
-
1 point
-
With a normal file or image field it will not let you save an empty "Valid File Extensions". It would seem to be a great idea, however I believe it would open many ProcessWire websites up to being hacked due to the actions of unsavory actors if it is enabled from the start. It's a vulnerability that would be easily exploited if the developer has not taken prudent actions to sanitize the input (files/images). The majority of knowledgeable developers would be aware of the danger, but that's not always the case. Making it a configurable option that you would have to explicitly enable would be a way to make it possibly work.1 point
-
That's not an option; in this case the field becomes unusable. In my opinion this is correct behaviour: not having anything defined here sounds more like a half-configured field or a mistake than something the developer did intentionally and knowingly.1 point
-
A while back while importing some 10k pages from another system I wrote an import script that would sniff the extension of the file, and if it wasn't yet allowed, it would first add it to allowed extensions and only then add the file. In this particular case I knew that all files were "safe", but there were dozens of different extensions to account for. To me this idea seems to make sense: as a developer I should have the option of saying that it's safe to insert "anything" in this specific field. A warning would still make sense, considering that not everyone who has access to these options will understand the risks involved. On a related note, I'm wondering if supporting regex would make sense here? Seems to me like one way to support just about every imaginable requirement in a future-proof way. It might confuse some vs. the old * trick, but then again, simple regex is not that much more difficult; just prefix the star with a dot1 point
-
For something like this you can use normal fields (i.e. page/options select and text fields), and set the widths of the inputfields so they appear in row groups. If you want a single heading across both inputfields something I have done in the past is: create a fieldset, place the grouped fields inside the fieldset, use AdminCustomFiles to hide the labels of fields inside the fieldset.1 point
-
I guess that should be doable with inputfield dependencies: https://processwire.com/api/selectors/inputfield-dependencies/1 point
-
I had this problem, and I believe it's caused by deleting the default lister (aka "Find"), which is something that becomes possible when Lister Pro is installed. If you have done this the solution is to create a new lister called "Lister". Because the default lister is used by the core it would be better if Lister Pro did not allow you to delete it, but instead made it simple to disable it for non-superuser roles. If you have other Lister Pro instances and you don't want certain roles to see the default lister you have to set up a special permission for the default lister and then not apply it to a role. There's definitely scope to make this process a bit clearer and easier for Lister Pro users.1 point
-
Here you go: new InstagramFeed version 1.0.0 add required scope public_content to retrieve tagged media with getRecentMediaByTag('tag') (thanks @gebeer) add ProcessWire 3.x compatibility add endpoint to get a list of recent comments on a media object: getRecentComments($media) Example: <?php $feed = $modules->get('InstagramFeed')->getRecentMedia(); ?> <div class="instagram> <?php foreach ($feed as $media): ?> <?php if ($media['type'] === 'image'): ?> <a href="<?=$media['link']; ?>" class="instagram-item"> <img src="<?=$media['images']['thumbnail']['url']; ?>" alt=""> </a> // display comments <?php $comments = $modules->get('InstagramFeed')->getRecentComments($media); ?> <?php if ($comments): ?> <ul> <?php foreach ($comments as $comment): ?> <li><?=$comment['text']?></li> <?php endforeach; ?> </ul> <?php endif; ?> <?php endif; ?> <?php endforeach; ?> </div> A comment ($comment in the example above) contains the following data: "created_time": "1280780324", "text": "Really amazing photo!", "from": { "username": "snoopdogg", "profile_picture": "http://images.instagram.com/profiles/profile_16_75sq_1305612434.jpg", "id": "1574083", "full_name": "Snoop Dogg" }, "id": "420"1 point
-
The suggestion by gebeer can achieve that markup - you just need to modify the PHP used in the Hanna code. If you consider it's not user friendly to type the Hanna code then you can make use of the Hanna Code Helper module. If you wanted to support multiple galleries per page and don't want to worry about the 'show' limit in gebeer's code it occurs to me that you could create a repeater field, the template for which contains only an images field. Then your Hanna code could get then nth repeater item (as specified by the user in the Hanna tag) and output its images. Shouldn't be too difficult to code. Downside is the user would need to be instructed not to reorder gallery repeaters after they are in use. ...the template for which contains a title field and images field, and the the Hanna code finds the gallery by title. That said, to do this type of layout (and an infinite number of others) properly I recommend the Repeater Matrix - it's a pro module but well worth the cost.1 point
-
I have both actually. Though Paytrail is implemented with their merchant channels (myyntikanavamalli), so that one would require minor adjustments to work for simple solo seller. Not yet published, but code is available if you need.1 point
-
There's also this one https://github.com/ryancramerdesign/ProcessWire/pull/11801 point
-
We can propose that on Github. Done. ... and thanks for noting where the module is (and what its correct name). I know that we have this, but everytime I need it, forget how it is named and where to find it.1 point
-
BEAUTIFUL!!!! Thanks guys! Each time I have a question I end up liking ProcessWire more and more! Everything can be reached just around the corner. I think that "ã = a" should be default. It's strange everything working BUT that one. By the way, it's: Admin > Modules > Core > InputfieldPageName Thanks again for the quick response.1 point
-
Have you tried adding this character to the Page Name module's settings? (under admin-modules-core I guess)1 point
-
Module in development and this solved the current issue https://github.com/adrianbj/ProcessMigrator/issues/41 point
-
This might be useful to anyone trying to convert a (single) existing file field to a secure one, while maintaining integrity of other file fields on the same pages. Put a file with this content in pw's root directory and run it from the terminal: <?php include "index.php"; // allow for: $ php filename.php fieldName $fieldName = !empty($argv[1]) ? $argv[1] : 'file'; $field = $fields->get($fieldName); $usedInTemplates = $field->getTemplates(); $fp = fopen('files.txt', 'w'); // the use() statement allows for both pre and post pw 3.0 usage without change/compiler $eachPageUncache = function($selector, callable $callback) use ($pages) { $num = 0; $id = 0; while (true) { $p = $pages->get("{$selector}, id>$id"); $id = $p->id; if(!$id) break; $callback($p); $pages->uncacheAll($p); $num++; } return $num; }; try { // Alternatively use findMany and a foreach on PW 3.0.19+ $eachPageUncache("template=$usedInTemplates, include=all, check_access=0", function($page) use($fp, $fieldName, $config) { $files = $page->getUnformatted($fieldName); foreach ($files as $file) { $path = str_replace($config->paths->files, '', $file->pathname); fwrite($fp, $path . PHP_EOL); } }); } finally { // PHP 5.5+ fclose($fp); } Then you can use the created files.txt to copy files to their new location (add --remove-source-files to also remove the source files). rsync -v \ --files-from=PW_ROOT_PATH/files.txt \ PW_ROOT_PATH/site/assets/files NEW_LOCATION_PATH Switch the file field to be a secure file field and all files should still work.1 point
-
I have a setup where users can enter some Hanna Code in the editor which will be replaced by a gallery that contains all images on that page or a chosen number of images. This is my Hannacode PHP <?php $images = $page->images; // name of your images field if ($images->count) { $config->scripts->add($config->urls->templates . "bower_components/fancybox/source/jquery.fancybox.pack.js"); $config->styles->add($config->urls->templates . "bower_components/fancybox/source/jquery.fancybox.css"); $showcount = ($show == "all") ? false : $show; $gallery = "<article class='gallery row'>"; if($showcount) $images = $images->find("limit={$showcount}"); foreach ($images as $i) { $thumb = $i->size(300, 300); $desc = ($i->description) ? $i->description : $page->title; $gallery .= "<div class='col-md-4'> <div class='thumbnail'> <a class='fancybox' rel='group' href='{$i->url}'> <img src='{$thumb->url}' alt='{$desc}'> </a> <p class='caption'>{$desc}</p> </div> </div>"; } } $gallery .= "</article>"; echo $gallery; Hanna Code to insert into the editor: [[gallery]] // shows all images [[gallery show=6]] // shows first 6 images Settings in Hanna Code module With this solution users cannot choose the images for the gallery from within CKEditor but it takes images from the images field of that page. This should get you started. Obviously you'd need to adjust script paths and markup (I'm using Bootstrap 3 here)1 point
-
sorte all.by price ? text=a|b, sort=price sorte.by text thens by price ? text=a|b, sort=text, sort=price1 point
-
1 point
-
Just had to do a quick head scratch to get the colour picker to work inside PW 3.12 Repeater and Repeater Matrix. If anyone is looking for a very quick and dirty hack, that seems to work. Not sure if it would cause any other issues. This is InputfieldFontIconPicker.js function SetUpCPicker(){ $('div[id^=ColorPicker_]').each(function(){ var $colorpicker = $(this); $colorpicker.ColorPicker({ color: $(this).data('color').toString(), onShow: function (colpkr) { $(colpkr).fadeIn(500); return false; }, onHide: function (colpkr) { $(colpkr).fadeOut(500); return false; }, onChange: function (hsb, hex, rgb) { $colorpicker.css('backgroundColor', '#' + hex); $colorpicker.css('background-image', 'none'); $colorpicker.next('input').val(hex).trigger('change'); } }); }); $('a.ColorPickerReset').on('click',function(e){ e.preventDefault(); var color = $(this).data('default') && $(this).data('default') != 'transp' ? '#' + $(this).data('default').toString() : 'transparent'; $(this).parent().find('input').val($(this).data('default')).trigger('change'); $(this).parent().find('div[id^=ColorPicker_]').ColorPickerSetColor($(this).data('default').toString()); $(this).parent().find('div[id^=ColorPicker_]') .css('backgroundColor', color) .css('background-image', 'none') .attr('data-color', $(this).data('default').toString()); if(color == 'transparent') { var modurl = $(this).data('modurl'); $(this).parent().find('div[id^=ColorPicker_]') .css('background-image', 'url(' + modurl + 'transparent.gif)'); } }); /* additions (swatches) by @Rayden */ $('div.ColorPickerSwatch').on('click',function(e){ e.preventDefault(); var color = $(this).data('color') && $(this).data('color') != 'transp' ? '#' + $(this).data('color').toString() : 'transparent'; $(this).closest('.ui-widget-content, .InputfieldContent').find('input').val($(this).data('color')).trigger('change'); $(this).closest('.ui-widget-content, .InputfieldContent').find('div[id^=ColorPicker_]').ColorPickerSetColor($(this).data('color').toString()); $(this).closest('.ui-widget-content, .InputfieldContent').find('div[id^=ColorPicker_]') .css('backgroundColor', color) .css('background-image', 'none') .attr('data-color', $(this).data('color').toString()); if(color == 'transparent') { var modurl = $(this).closest('.ui-widget-content, .InputfieldContent').find('.ColorPickerReset').data('modurl'); $(this).closest('.ui-widget-content, .InputfieldContent').find('div[id^=ColorPicker_]') .css('background-image', 'url(' + modurl + 'transparent.gif)'); } }); }; $(document).ready(function() { SetUpCPicker(); $(document).on('repeateradd', '.InputfieldRepeaterMatrix .InputfieldRepeaterMatrixAddLink', SetUpCPicker); $(document).on('opened', '.InputfieldRepeaterItem', SetUpCPicker); }); I posted this to github as well...1 point
-
Nice idea, I was also thinking about some time ago. One way is to not extend the InputfieldTextarea, and make a new Inputfield type, but Hook into the necessary methods to extend the config and rendering. Since this made me wonder how it would go, I gave it a try. It's a nice example showing how to archive it using hooks only. It will give you a extra Input setting "Max length" in the field setup. And a counter for all InputfieldTextarea (not tinymce fields) and add a attribute "data-maxlength" to the one that have a max length value. I had to use "maxchars" as the setting field name as there's already this attribute, but not used in the context of page edit. The script js is also added via a hook, and is a basic example of the script that counts backward while typing. Since I was already that far it was easy to add, but you might want to modify it and add features if you like. This took me roughly 30min, and little more to add the js. I think a year ago I wouldn't knew how and would have taken ages to figure out. But it grows on you after so many modules and insight. This module shows you some good practices and maybe helps understanding modules. If you have questions please bring them in. Module code: https://gist.github.com/4252958 JScript code: https://gist.github.com/4252962 Put them in a folder /site/modules/TextAreaCounter/.. Install, enjoy. Edit: just found an issue... will take a look again1 point
-
I think I understand. I should say though that PW's fields and inputs are designed for administrative use rather than front end use. If I'm building something for the front end, I might still use PW pages to store the data, but I'm handling the input on my own and populating fields into page objects. That's what I recommend because you'll be able to do whatever you want without limitation and use PW's API in the manner it was built for. But if the Inputfields are suiting your need, then here's what you'd do to extend all of them. In the example, we add a hook to the field rendering (to add a select box with each one) and another hook to the input processing. This example module should be pasted into a file called /site/modules/InputfieldHookTest.module <?php class InputfieldHookTest extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Inputfield Hook Test', 'version' => 100, 'summary' => 'Just a test.', 'singular' => true, 'autoload' => true, ); } public function init() { $this->addHookAfter('Inputfield::render', $this, 'render'); $this->addHookAfter('Inputfield::processInput', $this, 'processInput'); } public function render(HookEvent $event) { $inputfield = $event->object; // optional, but better to limit to those you want if(!$inputfield instanceof InputfieldText && !$inputfield instanceof InputfieldTextarea) return; $name = $inputfield->name; $event->return .= "<p><select name='test_$name'><option></option><option>test</option><option>test2</option></select></p>"; } public function processInput(HookEvent $event) { $inputfield = $event->object; $name = $inputfield->name; $post = $event->arguments[0]; $value = $post["test_$name"]; if($value) $this->message("You selected '$value' for '$name'"); } }1 point