Leaderboard
Popular Content
Showing content with the highest reputation on 03/13/2020 in all areas
-
I hope you are having a good week and staying healthy with all that’s going on with this Coronavirus pandemic. Here in Atlanta, they have closed the schools indefinitely, so I’ve got my kids with me during the work days for awhile, which started this week. That might slow me down with work and development here, but hopefully not too much. It might also take me a little longer than usual to respond to messages temporarily, as I get used to the new schedule. It’s a nice change of pace to have the kids home during the day, even if it slows work a bit. Thankfully everyone here is healthy and we don’t yet know of anyone being sick. But then again, nobody is apparently able to get tested for it, so who knows. It sounds like the whole world is dealing with this, I hope you and your families stay healthy and safe. I’m still working on the same client project I’ve been working on here for months, and of course doing it all in ProcessWire. This week the client project needed to do a lot with user-submitted comments, and I had to make a lot of major upgrades to ProcessWire’s comments system in order to accommodate them. Most of these upgrades are related to API improvements and making the comments field able to better handle completely custom markup for both comments and the forms to submit them. (Commit details). A couple new classes were added, and existing classes went through major refactoring. While there have been some nice API additions as well, there aren’t any breaking changes to the existing API, so it should all keep working as it always has. I’m not going to bump the core version this week because, as major as the additions were, I don’t think they will matter much to most existing installations, so there's little reason to upgrade for most. So I’ll continue plugging away here and save the version update for when there are some more things to share as well, hopefully next week. Thanks for reading and have a great weekend.10 points
-
Just wanted to put it on everyone's radar that VueMastery is having a free weekend starting today at (12 ET). All videos in every course are free to watch until Sunday at midnight. Cheers!5 points
-
You don't even need to adjust your template, as long as the rows have one common parent you can use the CSS nth-selector: .row { display: flex; flex-flow: row nowrap; justify-content: space-between; align-items: center; } .row:nth-child(2n) { flex-direction: row-reverse; }4 points
-
3 points
-
Right, this should be fixed now finally. For those that are interested, there was an issue with the forum session wiping out the ProcessWire session by the end of the script - a little puzzling because right up to the end of the script everything seems fine but when you redirect the session information is lost. To overcome that there's some background CURL stuff going on now so the two systems are separated completely during the login process. Please feel free to post/update your profiles again and sorry it took so long.3 points
-
Hi @Ben Sayers, are you sure that you need to use the migration module for that onetime migration? For me it looks like you simply can run this example script once (with your fieldnames) and then you are ready. To do this, you can create a php file with a name you like, in your root directory, besides the index.php. Calling this script will bootstrap PW and do all your desired work. Here an example. NOTE: Not tested, written in the browser! Before running this, do a BACKUP-COPY of your database, so have option to roll back, when something went wrong. <?php namespace ProcessWire; // prepare server for continuous output if(function_exists('apache_setenv')) @apache_setenv('no-gzip', '1'); @ini_set('zlib.output_compression', 'Off'); @ini_set('output_buffering ', '0'); @ini_set('implicit_flush', '1'); @ob_implicit_flush(true); @ob_end_flush(); //if(isset($_SERVER['HTTP_HOST'])) header('Content-Type: text/plain'); // bootstrap PW require_once('./index.php'); // here you bootstrap PW, after that line you will have available the most PW variables and functions. if(!$user->isSuperuser()) { // when using those scripts online, I do secure them with forcing a login in the admin as Superuser, ... echo "ACCESS DENIED! ($user->name)"; exit(1); } elseif($user->isSuperuser() && 'horst' == $user->name) { // and where are multiple superusers registered, additionally limited to my username echo '<pre>'.$_SERVER['HTTP_HOST'].' :: '.basename(__FILE__)."\n"; $selector = " DEFINE YOUR SELECTOR HERE TO GET A PAGE ARRAY WITH YOUR PAGES "; $pa = $pages->find($selector); // or: $pa = $pages->findMany($selector); $max = count($pa); $cur = 0; foreach($pa as $p) { // loop over all collected pages set_time_limit(30); // renew the time limit for each loop, so that you may run this script long times, but lets it time out on failures in a reasonable short timeframe $cur++; // following do your work if(!$p->hasField('seo')) { continue; } echo " - [$cur / $max] {$p->title}\n"; $p->of(false); foreach (wire('languages') as $lang) { wire('user')->language = $lang; $title = $p->seo_title->getLanguageValue($lang); $desc = $p->seo_description->getLanguageValue($lang); $p->seo->meta->title = $title ?: 'inherit'; $p->seo->meta->description = $desc ?: 'inherit'; } $p->save(); $pages->uncacheAll($p); // after saving, uncahe the current page //die('BREAK!!'); // just when first test the script before processing all items } die('<p>READY!</p>'); } die('RIP');2 points
-
@dotnetic sorry that was my mistake - made an error when I changed something last night and it didn't show the error to me as a superuser, only to other users (my logic was back to front). So you should now get redirected properly and you can change your forum name back again if you like (it's only used for login - the directory links your profile via the user ID).2 points
-
If using flexbox you could use the order property to change the order of the columns, I normally add a class to a parent div that wraps both columns. foreach($page->repeater as $i => $item){ //Going to offset the count starting from 1 instead of 0 so I can use modulo operator $i = $i + 1; $class = ""; // If the count is even, such as 2,4,6, etc. if($i%2 == 0){ $class = "invert-order"; } echo "<div class='row {$class}'>"; //output the columns here echo "..."; echo "</div>"; } You should end up with something like this: https://codepen.io/elabx/pen/RwPMaym2 points
-
@adrian, thanks, I've got it sorted. It was a typo in a field name on my part. I didn't realise it would drop the whole filename pattern rather than just the incorrect part, but once I corrected that, it's all good.1 point
-
there is a thirdparty module available, that let you define different crops with absolute width x height sizes. It is called CroppableImage3.1 point
-
1 point
-
1 point
-
Hello, elabx I tried your code and it works perfect. I was looking for this so long. You are the best ? Thank you very much R1 point
-
I'm pretty sure I've also fixed this issue in the 2.0 branch, so updating from there should've fixed this as well ?1 point
-
VC 2 is deprecated, you should use the dev branch instead: https://github.com/teppokoivula/VersionControl/tree/dev1 point
-
This seems to do the job: $wire->addHookAfter('ProcessPageEdit::buildFormContent', function(HookEvent $event) { /* @var InputfieldWrapper $wrapper */ $wrapper = $event->return; // Do some check on user role if($event->wire('user')->isSuperuser()) { $inputfields = $wrapper->getAll(); foreach($inputfields as $inputfield) { $inputfield->required = 0; } } });1 point
-
Well, I just found processInputErrorAction() in ProcessPageEdit.module, but that is a non-hookable method. A related function seems to be * // Disable change tracking * $page->setTrackChanges(false); which is in wire/core/Wire.php I would maybe try to work with "Required only if custom PHP returns true" and add some logic like "required only if data is edited in the frontend", but I'm not even sure that's possible. A quick test with $isAdmin = $this->page->rootParent->id == 2; return !$isAdmin; seems to work... (thanks to @LostKobrakai's post here)1 point
-
In the past I've worked with a few translation platforms (Launchpad, Twitter translation center, translate.wordpress.org, etc. — there are plenty of good examples) and one of the projects on my "things I want to do as soon as I find the time" list is a similar platform for ProcessWire. The way I envision this working would be a shared service (website, essentially) where translators can register and do pretty much the same thing they would do in the translations screen in Admin, and then share those projects with others who can both use them and contribute (obviously after an approval process). This would likely be split into "projects" (core, individual core or third party modules, site profiles, etc.) For the site you'd still need a module to install these translations, but the main concept here is a common library of translation files that would do most of the heavy lifting and provide an API for the module. I've been struggling a lot trying to keep up with who manages which translation for what language and where and how (and which version is the recommended, when there are many competing translations), and that's really the biggest thing I'd like to solve with this. In a multi-language environment I feel that this is almost a must-have feature in the long term... and, should it gain some momentum, I could really see that being a valuable addition to our "official site bundle" (translate.processwire.com or something along those lines), though obviously that part depends on how Ryan sees this ? Anyway, just wanted to let you know that you're not along with this need. The problem for me is that I've got a pretty good idea of what I need to do, but I still need the time to do that. I hope to find just that (unless someone nails something similar down first, that is) in a few months, but that's not a certainty yet ?1 point
-
Thanks Craig - that's because I was a muppet and used $sanitizer->pageName instead of just $sanitizer->text on a value that's being checked against a non-PW system. By this point it's habit ? Fixed now though for anyone with a space in their forum login name.1 point
-
Fortunately it was more complicated than just me being silly so I can stop kicking myself now ?1 point
-
Updated version here - works with more field types - just make sure you have at least 3.0.148 if you want to use it with autocomplete /* Script to refresh a form content when an element gets changed To work across all admin pages, this script needs to be loaded in admin.php – add the line $config->scripts->add($config->urls->templates . "scripts/form-update.js"); before the final require in templates/admin.php. Typical use is to modify other elements based on a select drop-down change The trigger element can have the following data attributes assigned to it (typically set these with $myInputfield->attr() in a module or hook): * data-action="form-update" : Required to run the script. * data-update-target="#myid1" : Required - the element to change. Note that this should not be the whole form, otherwise .find(target) will not find it. * data-confirm="Some confirmation text": Optional - if you want to show a confirmation before the update, this holds the text to display. If absent, there will be no confirmation dialogue. If the user chooses ‘cancel’, the script will revert the change and terminate. * data-alert="Some alert text": Optional – if you want to warn the user that the update cannot happen for some reason (the script will then revert the change and terminate). * data-cache="#myid2" : Optional - if you want to cache the (changed) value, this element stores it. * data-cache-prefix="Some prefix string" : Optional (requires data-cache) - a prefix to prepend the value stored in the cache This currently works with the following trigger elements: * select options * select page (single and multiple) * page list select (single and multiple) * asm select * page autocomplete (but note that data attributes must be set in the wrapper element - e.g. $myInputfield->wrapAttr() ) Note also that autocomplete only works fully with the latest master 3.0.148 * checkboxes (set attributes in wrapper as above) * checkbox (set attributes in wrapper as above; also, if you need to set or get the value (0 or 1) you may need to use getParent() ) * toggle (but only with 0,1 formatting and 'select' input type; plus see the comments for checkbox above) but not with: * toggle other than as described above * radio buttons NOTE: If you are using this with other js scripts (e.g. in a module) that listen for events in the target, you must use event delegation (e.g. $(document).on("change","#myid", function(){}); NOT $("#myid").onchange(function(){}); ) because #myid is dynamic if it is inside the target) */ $(document).on('change focusin', '[data-action="form-update"]', formUpdate); // need 'change' to catch normal select fields and 'mouseenter' for others function formUpdate(event) { console.log("event type = " + event.type); value = inputVal(this); if (event.type != 'change') { // if the input has not changed, just get the value now so that we can revert if necessary when it is changed console.log("Saving prev value " + value); $(this).data('prevVal', value); return; } console.log("Saving current value " + value); $(this).data('currVal', value); var prev = $(this).data('prevVal'); var current = $(this).data('currVal'); console.log("Prev value " + prev); console.log("New value " + current); // if trigger element has data-confirm attribute, confirm or revert and exit var confirmText = $(this).data('confirm'); if (confirmText) { if (!confirm(confirmText)) { $(this).val(inputVal(this, prev)); return; } } // if trigger element has data-alert attribute, show alert and exit var alertText = $(this).data('alert'); if (alertText) { alert(alertText); $(this).val(inputVal(this, prev)); return; } // cache the value before proceeding (if data-cache set) var cache = $(this).data('cache'); var cachePrefix = ($(this).data('cache-prefix')) ? $(this).data('cache-prefix') : ''; $(cache).val(cachePrefix + current); var $form = $(this).closest('form'); var target = $(this).data('update-target'); console.log("Target is " + target); var method = $form.attr('method'); var action = $form.attr('action'); var data = $form.serialize(); var encodedName; // .serialize() will omit select elements that do not have a 'null' option (e.g. asm select, page list select) // or checkboxes with nothing selected // so find them and add empty parameters to the data string, otherwise the page field will not be updated $($form.find('select, input').each(function(index){ console.log('Select element no. ' + index + ' with name ' + $(this).attr("name") + ' has serialize = ' + $(this).serialize()); encodedName = encodeURI($(this).attr("name")); if (data.search(encodedName) === -1) { data += ('&' + encodeURI($(this).attr("name")) + '='); } })); console.log("Submitted data: " + data); if (!method) method = 'get'; if (!action) action = window.location.href; // If you want to fade the affected inputfields then assign the loading class to their wrappers with method wrapClass(loading) $(target).find('.loading').css({ display: 'block', opacity: 0.2 }).animate({ opacity: 1 }, 5000); // then send your request $.ajax(action, { type: method, // type used, not method, for older versions of jquery data: data, // you can also add an error handler here if required, in case the server returns an error on the request success: function (data) { // Initial ajax just returns an array with message. Need to GET the form data. $.ajax(window.location.href, { type: 'GET', cache: false, success: function (data) { // then just take the target, and replace it with the target div from the returned data $(target).html($(data).find(target).html()); console.log("Returned data: " + data); console.log("Updating html with: " + $(data).find(target).html()); } }); } }); } function inputVal(el, val=null) { var value = $(el).val(); var inputfield = $(el); if ($(el).hasClass('InputfieldCheckbox')) { console.log("checkbox"); inputfield = $(el).find("input[type='checkbox'], input[type='radio']").first(); if (val === 1) { $(inputfield).attr('checked', 'checked'); } else if (val === 0) { $(inputfield).removeAttr('checked'); } value = ($(inputfield).attr('checked') === 'checked') ? 1 : 0; } else if ($(el).hasClass('InputfieldToggle')) { console.log("toggle"); inputfield = $(el).find("option[selected='selected']").first(); if (val === '1') { $(inputfield).attr('selected', 'selected'); } else if (val === '0') { $(inputfield).removeAttr('selected'); } value = ($(inputfield).attr('selected') === 'selected') ? '1' : '0'; } else if ($(el).hasClass('InputfieldPage') && $(el).find(".InputfieldPageAutocompleteData")) { console.log("page autocomplete"); inputfield = $(el).find(".InputfieldPageAutocompleteData").first(); value = $(inputfield).val(); } else { console.log("other selector type"); if (val) { $(el).val(val); } value = $(el).val(); } console.log("returning value = " + value); return value; }1 point
-
Hmm... I think there is still an issue with sessions actually - if you get your password wrong first time you have to close the browser and re-open, either that or it's due to too many login attempts stacking up - but either way without the helpful message popping up like it used to it's impossible to tell. I'll work on this some more now, but if you open a fresh browser window and get your forum username and password correct first time it should let you login to edit your profile in the meantime.1 point
-
Swopping out... $page->children for $page->pagetable throws up errors Error: Exception: Method Page::pagetable does not exist or is not callable in this context I can't find reference for "$page->pagetable" anywhere in the docs/forums? **UPDATE** I got this working by using the name of the pagetable field not 'pagetable' doh!1 point
-
$page->pagetable //Get the pages as sorted in the pagetable $page->children //Get the pages as sorted in the tree1 point
-
Well, I live in Italy, Turin, inside a building 50mt far from an hospital and 20mt of a 24h supermarket. The hospital had 1 decease today and Covid19 is the one to blame for it. The supermarket is overcrowded outside even at 23 a.m. I'm working from home and I cannot go outside without a 'right purpose' and a self-certificate of why I am there. My wife cannot stays home for work and her company produces various cleaning products which are a top-sellers this days... My 4yo son stays with his grandparent all day long, without having the opportunity to play with other kids. My mother is 72 and had, 2 years ago, some lunges problems and now, even though she is fine by now, she is really scared.0 points