Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 05/18/2017 in all areas

  1. New tutorial up on Tuts+ of little tit bits to help processwire devs. https://webdesign.tutsplus.com/tutorials/processwire-tricks-and-tips--cms-28613
    14 points
  2. I've been using PW for quite a while, now, so I would like to give back to the community that helped me so many times. I had this customer that wanted to use the Google Translate API to automatically translate the site, so I built this function that takes advantage of it without the need to use the API on every page cycle. I put it on a file that gets called on the _init.php, so that I can use it on every template. Here it is: <?php function googleAutoTranslate($page, $field) { // Turn off outputFormatting $page->of(false); // Get current language and field content for this language $current_language = wire('user')->language->name; $field_content = $page->getLanguageValue($current_language, $field); // Is there any content for this language? if($field_content != '') { // Do nothing! } else { // No content, lets translate... // Get default language text $text = $page->getLanguageValue('default', $field); // Translate only if there's content in the default language if($text != '') { // Translate it $apiKey = 'YOUR API KEY HERE'; $default_language = 'pt'; // Your default language here! $url = 'https://www.googleapis.com/language/translate/v2?key=' . $apiKey .'&q=' . rawurlencode($text) . '&source=' . $default_language . '&target=' . $current_language; $json = json_decode(file_get_contents($url)); $field_content = $json->data->translations[0]->translatedText; // Save translated text $page->$field->setLanguageValue($current_language, $field_content); $page->save(); } } // Turn on outputFormatting $page->of(true); // Return result return $field_content; } ?> Whenever you use a field on a template that should be auto translated, just call the function with a page object and the field name, like so: echo googleAutoTranslate($page, 'body'); Features: Translation occurs only once per field, so you don't need to keep paying translations (it stores the translation into the field language); You can correct the translation in the admin area and it won't be overwritten; If you need the translation to be made again, just delete the field content in the needed language. For the translation to occur, content must exist in the default language. I had to fight a little to get this working, so I hope this helps anyone, who comes across this particular need. Nice Things To Have If someone wants to give it a shot to make this into a module, please do. It would be nice to have a checkbox "Enable Google auto translate for this field", when you edit a field input features. Don't Spend Too Much Mind you that the Google translate is a payed service! and needs a Credit Card to get it going (even with $300 free credit); With a relatively small site (and the tests made to get this to work) I already spent about 80.000 translated characters = $3, Hope this helps someone!
    6 points
  3. $pf = $pages->getPageFinder(); $selector = new Selectors($selector); $query = $pf->find($selector, ['returnVerbose' => true, 'returnQuery' => true]); # Show sql $query->getQuery(); # Modify query $query->where($sql); # Run query $query->execute();
    6 points
  4. Having such information presented publicly is a great idea to help promote ProcessWire. Thanks to @benbyf for taking the initiative. The newspaper writing style certainly helps with content such as this. My only concern with this article is the wording. This is meant only as constructive criticism. #1 The way it is written, it implies that for some unknown reason ProcessWire (not the user) had created an arbitrary number of images within a page, and now you may want to remove them. To a new user, or prospective user, it implies they will have maintenance issues when working with ProcessWire. We know this is not the case. This tip's opening sentence might be more accurately written like so, 1. Bulk Delete Images in Admin As you create your site content, you may have added any number of images to a particular page that are no longer wanted. Should you want to get rid of them... #2 This one really sticks out. The means by which a user gets 'locked out' is due to either pilot error, or an interruption in a critical process, and rarely due to some internal malfunction. It might be better to have written it like so, 2. Regain Entry to Backend For those times where you may have forgotten your administrative password, or if a poor network connection caused a critical process (like a site migration) to fail, you can reset the administrative password using this simple trick... #3 Specifying a heading "Upgrade ProcessWire" and immediately opening with "Upgrading is a chore..." doesn't give a good first impression. While that statement is technically accurate, it might be better to lead with how simple the ProcessWire upgrade procedure is in relation to the complexity found with other platforms (without naming names). /$0.02 Like I said, these are simply my comments meant as constructive criticism for future articles. Giving a good first impression is critical to our growth. I know there is no style guide associated with ProcessWire-related articles, so it might be a good idea for anyone wanting to write such articles in the future to ask a staff member to proof read it before publication for things like grammar, inflection, conveyance, etc. And again, thanks to benbyf for making this contribution!
    5 points
  5. @Arcturus, isLoggedIn() only works for the current user. There is a related thread here which suggests adapting some code from the SessionHandlerDB module to get active users from the database. I updated/modified it a bit below: // Find IDs of users that have been active in the last $mins number of minutes function onlineUserIDs($mins, $limit = 500) { $table = SessionHandlerDB::dbTableName; $seconds = $mins * 60; $sql = "SELECT user_id " . "FROM `$table` " . "WHERE ts > DATE_SUB(NOW(), INTERVAL $seconds SECOND) " . "AND user_id!=40 " . // exclude guest "ORDER BY ts DESC LIMIT $limit"; $query = wire('database')->prepare($sql); $query->execute(); $results = $query->fetchAll(\PDO::FETCH_COLUMN); return $results; } $online_user_ids = onlineUserIDs(60); // User IDs active in the last hour // Online users $online_users = $pages->find([ 'id' => $online_user_ids ]); // Offline users $offline_users = $pages->find([ 'id!=' => $online_user_ids, 'template' => 'user', 'roles!=' => 'guest' ]);
    5 points
  6. There's always a solution First thing to understand is that the access control that is built into the PW core is based around templates, not around pages. So if you have given a role permission to add children for a template then a user with that role can add children to any page with that template. Or if you have allowed permissions to be inherited then a role might inherit the add children permission from the template of a parent page you have granted it on. Same goes for any other access permission. But that is only the PW core - you can modify the way permissions work with your own hooks or by using existing modules. A couple of modules that might suit your needs: AdminRestrictBranch: If your users only have permission to work with a particular page and children of that page then this module might be ideal because it can hide everything outside of that branch. UserGroups: Another module that implements page-based permissions. I haven't used this module but apparently it is pretty stable despite the "alpha" label in the support thread. You might need to tweak a couple of things to get it working smoothly in PW3 - see this and this. And a third option... You don't make this clear in your original post but I take it you have installed the PageEditPerUser module. This module allows you to define individual pages that a user may edit but it doesn't get involved with the permission to add children. However you could edit the module to include a hook to Page::addable public function init() { $this->addHookAfter('Page::editable', $this, 'hookPageEditable'); $this->addHookAfter('Page::viewable', $this, 'hookPageViewable'); // fixing a long-standing typo in the module $this->addHookAfter('Page::addable', $this, 'hookPageAddable'); // the new addable hook } // ... public function hookPageAddable($event) { if($event->return) return; $event->return = $this->onMyBranch($event->object); } Now child pages may only be added to pages that the user has been given edit access for in their user profile.
    3 points
  7. Yep, if I'd learned PW from the start I'd probably be better off, but I'm used to the WP + ACF way of doing things, so they creep into this PW project as well. As for the setup, for example, I have a group of tabs on the homepage, and each tab has sections with an image, icon and text. I figured the best way to do this would be to have a repeater for the tabs themselves and a nested repeater for each tab's sections. I have a pretty short deadline, so I had to just jump in head-first and get the homepage done to show the client. I'll definitely need some time to learn the ropes properly, and then I'll be able to better think every field and template out from the start and make things simpler. Thanks a lot, once again, to all of you who took the time to help a newbie out, I hope to return the favor sometimes.
    2 points
  8. Hey @joer80, I've been dealing with finals/graduation/masters applications lately and cannot spend as much time coding as I would like. Because of this I haven't been active in the forum for the last two weeks as well. However, hopefully tomorrow, after submitting a project which filled my last three weeks, I'll be finished with school (for now) and be able to go back on coding. Once I get a usable beta going, I'll open a topic for the updates and feedback. Thanks a lot for your interest. Abdus.
    2 points
  9. At our site we use both email and phone authorizations at frontend. To make life easier, I've developed HelperPhone pack that handles phone numbers. This pack includes following modules for ProcessWire CMS/CMF: FieldtypePhoneNumber: module that stores phone numbers InputfieldPhoneNumber: module that renders inputfield for phone numbers HelperPhone: module that loads PhoneNumber and PhoneNumberConst classes, and 'libphonenumber' namespace All these modules require included PW WireData-derived class PhoneNumber and PhoneNumberConst. PhoneNumber class is a thin wrapper over giggsey/libphonenumber-for-php, itself is port of Google's libphonenumber. PhoneNumberConst class stores constants, used by PhoneNumber class Usage: PhoneNumber class $phone = '8 (916) 318-07-29 ext 1234'; // input string could be in any phone-recognizable format $phoneNumber = new PhoneNumber($phone, 'RU'); // or wire('modules')->get('HelperPhone')->makePhoneNumber($phone, 'RU'); echo ($phoneNumber->isValidNumber() ? 'Yes':'No'); // Yes echo ($phoneNumber->isValidNumberForRegion($regionCode) ? 'Yes':'No'); // Yes echo $phoneNumber->getNumberTypeTitle(); // Mobile echo $phoneNumber->getCountryCode(); // 7 echo $phoneNumber->getRegionCode(); // RU echo $phoneNumber->getNationalNumber(); // 9163180729 echo $phoneNumber->getExtension(); // 1234 echo $phoneNumber->formatForCallingFrom('US') // 011 7 916 318-07-28 echo $phoneNumber->formatForCallingFrom('GE') // 00 7 916 318-07-28 For more methods and properties please refer to PhoneNumber and PhoneNumberConst source files. Need more? Check giggsey/libphonenumber-for-php and use it by accessing $phoneNumber->phoneNumber property - it is instance of \libphonenumber\PhoneNumber or null (if empty). Usage: field Note: on field creation, make sure that you've configured field settings Default region: assumed region if input phone number string is not in international format (starts with '+', etc) Enabled/disabled phone extentions: if disabled, phone extension will be removed on field save. Phone field settings in example below: default region code 'RU', phone extensions are enabled echo $page->phone; // +79163180729 // Note1: $page->phone stores instance of PhoneNumber and renders to string in E164 format. // Note2: E164 format does not include extension. echo $page->getFormatted('phone'); // +7 916 318-07-29 ext. 1234 echo $page->getUnformatted('phone'); // +79163180729 echo $page->phone->format(PhoneNumberConst::RFC3966); // tel:+7-916-318-07-29;ext=1234 echo $page->phone->getNationalNumber(); // 9163180729 Usage: PW selectors FieldtypePhoneNumber is instance of FieldtypeText. It stores phone numbers and extensions as string in E164 format with #extention (if provided by user and enabled in settings) E.g. in db it looks like this: '+79163180729#1234'. This makes it easy to query fields as any text field. echo $pages->find([ 'template' => 'my_temlate', 'phone^=' => '+79163180729', ]); // will echo page ids where phone starts with '+79163180729' Finally I've decided to put it here first and later to Modules directory (based on your feedbacks). GitHub: https://github.com/valieand/HelperPhone Enjoy
    2 points
  10. never mind, the simplicity of processwire was a big hurdle for many of us in the beginning ...and i'm still curious what setup would need lots of repeaters for structuring everything. usually you can keep everything very clean just by using different templates, different parents in the tree and doing the relations via pagefields. don't get me wrong. it's just my experience that whenever something felt complex/complicated it was most of the times a problem of my (or other forum users) setup i wish you lots of happy aha-moments
    2 points
  11. @adrian I am working on a multisite project using single database. I forked multisite.module by Antti and another fork by Soma and started to adapt it for my needs. Luckily I found your module. I tried it out and it fits 90% to my needs and already saved a lot of work. Thanks for this great module. To get it working properly I need to make some changes. I think these changes could also be an enhancement of your module and you maybe want to take it. First of all I need an option to set branchRootParentId via hook which is currently not possible since the related function isn't hookable and private too. It would be nice if you could change the visibility of the function getBranchRootParentId() to protected and make it hookable. As far I can see there is no reason (security) to refrain from this. Furthermore there are 2 unexpected behaviours or potential issues: In Processwire the breadcrumb 'Pages' is prepended to breadcrumbs in the PageEdit area of the root page only. @see ProcessPageEdit::setupBreadcrumbs() This behaviour is different in your module. The breadcrumb is prepended in any Editor not only for the branchRootParent since $this->wire('breadcrumbs')->count() returns always 0. Is this wanted like that? I would prefer the default behavior here. I found a working solution. If you like I could post an issue on github. The BranchRootParent is not prepended to the Pagetree under PagesTab. ProcessPageList::executeNavJSON() doesn't prepend branchRootParent here. This couldn't be solved inside your module. I can see a PW issue here. ProcessPageList::executeNavJSON() should use $config->rootPageID instead of hardcoded 1 Possible Solution // in ProcessPageList::executeNavJSON // Line 489 from if(!$parentID) $parentID = 1; // to if(!$parentID) $parentID = $config->rootPageID; // Line 494 from if($parentID === 1 && $parentViewable) $items->prepend($parent); // to if($parentID === $config->rootPageID && $parentViewable) $items->prepend($parent); // Line 523 from $numChildren = $id > 1 ? $page->numChildren : 0; // to $numChildren = $id != $config->rootPageID ? $page->numChildren : 0; // Line 551 from if($page->id > 1 && $page->numChildren) { // to if($page->id != $config->rootPageID && $page->numChildren) { //in your module public function ready() { $this->wire('config')->rootPageID = $this->branchRootParentId; // ... }
    2 points
  12. Currently working on a premium module and I would love to be able to sell it through the PW store (currently not possible) and maybe have the store handle code creation.
    1 point
  13. I did another quick module, which plugs something I always kinda missed in ProcessWire. It's just a raw overview over the access management from the templates. Nothing fancy, but useful. The visible roles and the visibility of system templats can be setup in the modules settings. I'll add this to the modules directory later. But for now it would be great to hear if anyone is missing anything or if someone does have a better idea how to name the module. 12.03.15: Renamed the module and fixed wrong information for superusers and inherited rights from the required guest role. GitHub: https://github.com/LostKobrakai/ProcessAccessOverview
    1 point
  14. It helps the community if people share the solutions to their problems Could you please post back with what you found? Thanks.
    1 point
  15. 1 point
  16. Thanks, please re-download (only .module file was changed).
    1 point
  17. Yes, i try to support all filterboxes. Sadly right now I am busy with some projects. Hope I find the time to finish this soon.
    1 point
  18. It could be possibly tricky to have the reset admin password on the admin template, since you cannot predict who will access that... The tip is useful though, and would be probably too complicated for the scope of that article to explain about putting it into some more obscure template (like a console or tools/api); $users->get('admin'); maybe needs to be $users->get('name-of-superuser'); // change this to the actual 'name' of the user
    1 point
  19. $events = $pages->find('template=calendar-post, limit=8, Start_date>=today, sort=Start_date'); if (count($events)) { echo "There are events, yes!"; } else { echo "Out of luck"; } Small clue
    1 point
  20. yes, that was the reason for my question i already have a query and it works well. it creates a db-view of all my data and then i can run an efficient query on this view easily without joining everything again manually. i think your pagefinder example code will save me some time next time together with tracy console panel
    1 point
  21. There probably isn't. The pagefinder and Pages::getById and Pages::getFieldValue are the places where processwire does query the db for page data, with the first probably being the most elaborate piece. Converting your foreach into a single query is probably a bit difficult (selection and retrieval), but maybe 2 is enough for you. Use $pages->findIDs() and then your custom query with "WHERE id in (1000, 1001, …)"
    1 point
  22. Oh!!! Thanks a lot for the heads up @szabesz !!
    1 point
  23. Feedback always welcome, so thanks. First comment i believe that was me proofing reading badly and your right should have been more obviously on the user not PW. second. I believe you are indeed correct but I do find myself using this tip alot so there most be a reason... :/ I think the wording here is fine but you're right, could be misleading, if you stopped reading.
    1 point
  24. Maybe this is an option as well: https://processwireshop.pw
    1 point
  25. 1 point
  26. Also: Dynamic Roles Module might me of interest here. I have not used it, to tell the truth, but Ryan has updated it recently so that it is installable on PW3, that is why I guess it works too, see: https://github.com/ryancramerdesign/DynamicRoles more:
    1 point
  27. I'm not sure, I haven't used in in a while. But I haven't added the 3.0 flag for a purpose, because the module was build before the ability to assign additional permissions on a per template level was added. I'm not sure if the module does take those into account properly.
    1 point
  28. @elabx Hi, FYI, Adrian is still away for more than a month, see:
    1 point
  29. 1 point
  30. @elabx Thanks for interest. Have a look here: https://processwire.com/talk/topic/1025-multisite/?do=findComment&comment=144509 https://github.com/kixe/Multisite/tree/kixe Need some thumbs up here https://github.com/processwire/processwire-requests/issues/94
    1 point
  31. Yes it works. Thank you very much!
    1 point
  32. @Slav, you might find this module useful for understanding user permissions across your templates: https://modules.processwire.com/modules/process-access-overview/
    1 point
  33. This finds all 'articleFeatured' articles, but you only need one. So better to do this: $latestArticle = $pages->findOne("template=article, articleFeatured=1, sort=-created"); I wrote that imagickal() function and it doesn't recreate the image on every page load if the processed image already exists. But it was really intended for applying ImageMagick effects - you don't need it for simple image resizing. Rather than add padding in the resized image you should use CSS to keep the image within its container while maintaining aspect ratio. A couple of ways you can do this below - CSS is inline in the examples but you would move it to an external stylesheet. If you don't mind using background images the technique is dead simple. Just adjust the padding-top for the desired aspect ratio (in the example I used your 730:350 ratio). <div style="padding-top:47.945%; background:#000 url('my-image.jpg') no-repeat center center / contain;"></div> If you want to use an <img> tag there's a bit more to it: <div style="padding-top:47.945%; position:relative;"> <div style="position:absolute; width:100%; height:100%; top:0; left:0; font-size:0; line-height:0; text-align:center; background-color:#000"> <img src="my-image.jpg" style="max-width:100%; max-height:100%;"> </div> </div> If you are using a CSS pre-processor you can use a helper mixin, e.g. https://css-tricks.com/snippets/sass/maintain-aspect-ratio-mixin/ But none of this should make that much of a difference when you are using ProCache - your server load should be very low when ProCache is used considering you have no front-end users logging in. You could check to make sure you are not clearing the entire cache unnecessarily - for best performance you shouldn't use the "Reset cache for entire site" option for when a page is saved but instead use the settings on the "Cache" tab of Edit Template to only clear the cache of related pages. But the other thing to consider is if the problem might be due to the host. You could copy the files and DB to a different host and trial that for a bit to see if the problem resolves. A hassle for sure but if you are getting desperate...
    1 point
  34. Here are the updates. You can use absolute (fully qualified) or relative paths (relative to site root). aos-assetpaths.zip
    1 point
  35. Since a few days I'm completely addicted to listening to this while working https://www.youtube.com/channel/UC5FUNVH36ebM6ffQd3rvz8g
    1 point
  36. afaik it works with template id too, "template!=1200"
    1 point
  37. You could either remove the page-add permission from the role completely or remove the "add children" permission in the page's template for the exponent role.
    1 point
  38. Hi! Will "Show this field only if" condition work for you? You could specify an id of a page on which you would like your field to be present. I am attaching a screenshot to illustrate my point.
    1 point
  39. Check your credentials, make sure the domain of the database is correct, usually it's "localhost", but it depends. It could also be the ip address of the machine where the database exist.
    1 point
  40. Hi @franciccio-ITALIANO, If your database was deleted for some reason, then ProcessWire will have no internal data (created during install) in which to reference. That means your admin login does not exist, nor the admin url, nor any other information. I'm afraid that you will need to re-install ProcessWire to use the new database. Since the previous database was deleted, so was the previous content, and any fields/templates/pages that existed before. The only information not specifically related to the previous database are the files in the /site/templates/ folders. You should copy those to a safe location before you re-install. I hope you are in contact with @3fingers on skype. He can help you, as he speaks Italian. I would talk with him first before you proceed with the new installation in case I have missed anything.
    1 point
  41. Suppressing errors is a bad idea. Having "Integrity constraint violation" means something is trying to insert data with a key, which is already present in the database. Worst case scenario: You loose data because of it not being in a saveable state. This should be fixed and not be put aside (even it it's really a core issue and not one with your code).
    1 point
  42. @Zeka's suggestion is the right direction, but a couple of extra things are needed: $your_pages = $pages->find("template=some_template"); foreach($your_pages as $p) { // Output formatting must be off before manipulating and saving the page $p->of(false); // You need to get the formatted value of the markdown field // i.e. with the textformatter applied $p->ckeditor_field = $p->getFormatted('markdown_field'); $p->save(); } Or a shorter way that takes care of the output formatting using setAndSave(): $your_pages = $pages->find("template=some_template"); foreach($your_pages as $p) { // Normally you wouldn't want to save a formatted value with setAndSave() // but in this case we do $p->setAndSave('ckeditor_field', $p->markdown_field); }
    1 point
  43. @Marc I think you can do the same with hosts.
    1 point
  44. Forked this module a few days ago and ended up in a complete rewrite. Still under development and testing but working properly here. What is different? Do not worry about page naming. The root page is defined via ID. Full multilanguage support * take in account $template->slashUrl settings take in account LanguageSupportPagenames::useHomeSegment settings Fallback to default 404 page if custom 404 is not set Throws exception in case of misconfiguration Access of pages residing in a MultisitePageTree for other domains other than the corresponding root page is disallowed except for superuser Pages inside a MultisitePageTree accessible only via the modified url if called from the corresponding domain (throws 404 instead of unexpected redirects) Page paths are set via hook in Page::path() instead of modifying the return of Page::render() Crosslink support via the RTE (CK Editor) Link plugin Page view links in admin with correctly modified urls * under conditions: see next post! Feedback welcome. Have a try: https://github.com/kixe/Multisite/tree/kixe
    1 point
  45. I know this is a pretty old thread, but every time it comes to creating a Repeater through the API, I get LOST. @thetuningspoon's function illuminates a LOT of what happens behind the scenes when a new Repeater is made through the GUI - but I just keep wishing it was as simple as: $f = new FieldtypeRepeater(); $f->set('name', 'repeaterTest'); $f->add($repeaterField1); $f->add($repeaterField2); $f->save(); Because that isn't technically possible without setting the Fieldgroup or Template that will be used by the Repeater first, right? At the end of the day, I think we should improve the docs for Repeaters (https://processwire.com/api/fieldtypes/repeaters/) to include a section on creating a Repeater from scratch through the API so that this process is more easily understood. I am always referencing several Forum posts and parts of the docs in order to get through the spaghetti - having everything in one place would be great. Otherwise it would be awesome to have some functions as a part of the FieldtypeRepeater Class that cut down on the amount of API calls one needs to make in order to create one of these. Just my 2 cents.
    1 point
  46. This was bothering me when I was working on this question about PageTables. It appears that Tracy isn't included when page is called via a modal. Check this out // /site/modules/TracyDebugger/TracyDebugger.module public function init() { // ... // EARLY EXITS // modals if(in_array('regularModal', $this->data['hideDebugBarModals']) && $this->wire('input')->get->modal == '1') return; if(in_array('inlineModal', $this->data['hideDebugBarModals']) && $this->wire('input')->get->modal == 'inline') return; // ... } We need you @adrian, come back!
    1 point
  47. I used a much simpler and faster method utilizing the pagefile class. My link looks like this: // Sorry for smarty language. but thats what I used {if $page->files|@count > 0} {foreach $page->files as $file} <p> {if $file->description} {$file->description} {else} {$file->name} {/if} <br> <a href="download/{$file->name}" class="link-icon">Download</a> | {$file->filesizeStr} </p> {*{/if}*} {/foreach} {/if} and then in my _init.php I used the following code if ($input->urlSegment1 == 'download') { $download_options = array( // boolean: halt program execution after file send 'exit' => true, // boolean|null: whether file should force download (null=let content-type header decide) 'forceDownload' => true, // string: filename you want the download to show on the user's computer, or blank to use existing. 'downloadFilename' => '', ); session_write_close(); if ($input->urlSegment2) { $pagefile = $page->files[$input->urlSegment2]; if($pagefile){ wireSendFile($pagefile->filename, $download_options); } } } EDIT: The downside when implementing this in the _init.php is, that you can´t send a Wire404Exception, because this file gets included (prepended) and PHP doesn´t like exeptions in included files. If you paste this code into one of your templates you could add trowing a Wire404Exception.
    1 point
×
×
  • Create New...