Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 12/05/2018 in all areas

  1. The admin search is JqueryUI Autocomplete. http://api.jqueryui.com/autocomplete/ there are some Extension Points such as _renderMenu and _renderItem that are using some custom logic to return the required markup. (look at the AdminThemeUikit/scripts/main.js, as well as the _search-form.php. It does work well and looks nice, but can achieve the same basic look and functionality for a front end site with possibly less work using typeahead.js and with the Bloodhound using local storage, it could mean for faster lookups.
    3 points
  2. You should not overwrite this file. Instead, edit the config in site/config.php.
    2 points
  3. Just for the curious, your garbled text error was caused by using the wrong operator. A single pipe character (|) is the bitwise OR-operator in PHP. Bitwise operators perform comparisons on the bits of integer values. They aren't really useful for strings, as the results are pretty much random. From the PHP manual: What you were looking for is probably the logical OR operator (||). However, your original $key1 assignment still wouldn't work because of operator precedence in PHP: $key1 = $vars['key1'] || "Default1"; // executed as $key1 = ($vars['key'] || "Default1"); In this case the OR operation will be executed first, and the expression will always evaluate to true because non-empty strings are true-ish. Then the result of the expression is assigned to $key1. A cleaner way that works and will never throw errors: $var1 = !empty($vars['key']) ? $vars['key'] : 'Default1'; In PHP 7 you can use null coalescing: $var1 = $vars['key'] ?? 'Default1'; Keep in mind that this will only assign the default value if $vars['key'] is NULL, but not if it is (int) 0 or an empty string!
    2 points
  4. it depends! // ADD PAGE // adding a page via API can be triggered by the guest user even if he has not the permission to add children under a specific parent (12464) if ($user->isGuest()) $pages->add('contribution', 12464); // works // VIEW PAGE or FIELD VALUE // if guest user has not the view permission it depends on outputformatting if ($user->isGuest()) var_dump($pages->get(12985)->title); // "I am the Page Title" if ($user->isGuest()) var_dump($pages->get(12985)->of(true)->title); // NULL // MODULES // Call of a Module via API. User has not the permission to use the module if ($user->isGuest()) $modules->get('MyModule')->execute(); // Fatal error: Exception: You do not have permission to execute this module (if debug mode is on/ 500 otherwise) if ($user->isGuest()) $modules->getModule('MyModule', array('noPermissionCheck' => true))->execute(); // works!
    2 points
  5. After building the ProcessMentions module and another autocomplete module for images, I found that I am going to need even more of these, but things were going to get repetitive. So I refactored the whole thing into a basic autocompletion module and individual "actions". The result is Autocomplete for CKEditor (GitHub). To try out, Install the module and actions Enable actions in the settings of any CKEditor field Edit a page with this field, type "@" and some characters for the and enjoy There are still a few things I need to implement. ATM, it only supports single characters as triggers for the autocomplete. I'd like to change that to combinations so I don't run out of special characters at some point. I also have to add a few more configuration options (like search only at the beginning or also in the middle of the searched string). The documentation for custom styling also needs some work. I have tried to keep things generic. Implementing your own actions should be quite straight forward. The README at GitHub illustrates the main steps and the supplied action classes have inline documentation. I would love to get some feedback or even see some third party InlineCompleteAction implementations.
    1 point
  6. Hello everyone, I always wanted to try out an ajax autocomplete search function, but never knew where to start. Of course there is the Ajax Page Search module by soma, but it seems that it was build around the basic site profile. In my case I wanted something more custom and I discovered in this thread the jQuery Plugin Typeahead by RunningCoder, which seemed to be nice. After many hours figuring out, how to combine this Plugin with ProcessWire, I finally got it implemented and want to share my solution with anyone, who also struggles with this topic. 1. Set-Up Typeahead Download the Typeahead-Plugin from the website (I prefer via Bower) and include the following scripts and stylesheets in your templates: <html> <head> ... <!-- Optional CSS --> <link rel="stylesheet" href="/vendor/jquery-typeahead/dist/jquery.typeahead.min.css"> <!-- Required JavaScript --> <script src="https://code.jquery.com/jquery-2.1.3.min.js"></script> <script src="/vendor/jquery-typeahead/dist/jquery.typeahead.min.js"></script> ... </head> As next step we need the JSON data. 2. Install Pages to JSON To get the necessary data of all pages as JSON, I use the module Pages to JSON, which provides an easy way to output pages as JSON objects. Of course you can achieve this without this module, but I am not very experienced with JSON, so this module was really helpful. After you downloaded and installed the module, you can configure in the module settings page, which fields you want to output. You can select between own and system fields. For my purpose I selected only title and url to be outputted. 3. Output JSON Now, that we have the module configured, we have to output our search suggestions as JSON. I did it in my template file search.php like this: <?php namespace ProcessWire; // Check if ajax request if($config->ajax) { $results = $pages->find("has_parent!=2"); // Find all published pages and save as $results header("Content-type: application/json"); // Set header to JSON echo $results->toJSON(); // Output the results as JSON via the toJSON function } else { // Your own front-end template } To sum up, we search the pages we want as search suggestions and save them in a variable. Then we output them with the toJSON-Function by the Pages to JSON-Module. All of this happens in a Ajax-Request, that is the reason why we check first, if the page is called via an Ajax request. 4. Insert Form We can now embed the HTML form anywhere you want. Either in an header-include or a specific template. Also you can use your own classes, for this example I used the Typeahead-demo-mark-up and extended it a little. <form id="searchform" method="get" action="<?= $pages->get("template=search")->url ?>"> <div class="typeahead__container"> <div class="typeahead__field"> <span class="typeahead__query"> <input id="q" name="q" type="search" placeholder="Search" autocomplete="off"> </span> <span class="typeahead__button"> <button type="submit"> <span class="typeahead__search-icon"></span> </button> </span> </div> </div> </form> The action-attribute in the form-tag is the url of your search-site. This attribute is of course necessary to know where the form redirects you and where the JSON data is located. 5. Initialize Typeahead As last step we have to initialize the Typeahead-plugin jQuery like this: $(document).ready(function() { var actionURL = $('#searchform').attr('action'); // Save form action url in variable $.typeahead({ input: '#q', hint: true, display: ["title"], // Search objects by the title-key source: { url: actionURL // Ajax request to get JSON from the action url }, callback: { // Redirect to url after clicking or pressing enter onClickAfter: function (node, a, item, event) { window.location.href = item.url; // Set window location to site url } } }); }); We save the action url of the form in a variable, then we initialize Typeahead by selecting the input-field inside the form. As the source we can pass the action url and I included the callback, to link the search results with the site urls. Now you should have a nice ajax autocomplete search form, which of course you can further style and configure. I hope I didn't forget anything, but if so, please let me know. Regards, Andreas
    1 point
  7. Modules > Core > ProcessProfile
    1 point
  8. Probably obvious, but remember it is only enabled for superusers. Scratch that ? What exactly isn't working? Are you not getting detailed errors on the frontend, or does the backend not report debug mode on?
    1 point
  9. @horst This works perfectly in alle pages. many, many thx
    1 point
  10. I ran into this issue too. I edited the Mollie module to fit my own needs, a bit too many changes to create a merge request, but it deals with this issue. <?php namespace ProcessWire; // Here you can find more information about the Mollie php api https://github.com/mollie/mollie-api-php require_once __DIR__ . "/vendor/autoload.php"; class PaymentMollie extends PaymentModule { public static function getModuleInfo() { return [ 'title' => 'PaymentMollie', 'version' => '0.0.2', 'summary' => 'Mollie Payment method', 'singular' => false, 'autoload' => false, 'requires' => 'ProcessWire>=3.0.98, PaymentModule', ]; } public function init() { ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL); } public function getTitle() { return $this->_("Mollie: iDeal, Bancontact"); } public function getFailureReason() { return "Error"; } public function processPayment() { $payment_id = wire()->input->post->id; $order_id = wire()->input->urlSegment2; $mollie = new \Mollie\Api\MollieApiClient(); $mollie->setApiKey($this->test_api_key); if ($this->live_check == "1") { $mollie->setApiKey($this->api_key); } $payment = $mollie->payments->get($payment_id); $order_id = $payment->metadata->order_id; wire()->log->save("mollie", "Processing payment for... $order_id"); if ($payment->isPaid() == true) { wire()->log->save("mollie", "Order $order_id was paid using mollie!"); $order = wire()->pages->get($order_id); $order->of(false); $order->pad_paid = time(); $order->addNote($this->_("Order paid using Mollie") . ": " . $payment->id); $order->removeStatus(Page::statusUnpublished); $order->save(); return true; } elseif ($payment->isOpen() == FALSE) { return false; } return false; } public function getMollieMethods() { $mollie = new \Mollie\Api\MollieApiClient(); $mollie->setApiKey($this->test_api_key); if ($this->live_check == "1") { $mollie->setApiKey($this->api_key); } $methods = $mollie->methods->all(); $return = [ ]; foreach ($methods as $method) { $return[] = [ "title" => htmlspecialchars($method->description), "icon" => htmlspecialchars($method->image->size1x), "icon2x" => htmlspecialchars($method->image->size2x), ]; } return $return; } public function render() { $output = ""; $mollie = new \Mollie\Api\MollieApiClient(); $mollie->setApiKey($this->test_api_key); if ($this->live_check == "1") { $mollie->setApiKey($this->api_key); } $paymentInfo = [ "amount" => [ "value" => number_format(($this->getTotalAmount() /100), 2, '.', ''), "currency" => 'EUR', ], "description" => "Bestelling van: " . $this->customer->givenName . " " . $this->customer->familyName, "redirectUrl" => $this->httphost . "checkout/?id=" . $this->id, "webhookUrl" => $this->httphost. "checkout/processmollie/" . $this->id . "/", // Specify here wat you want "metadata" => [ "order_id" => $this->id, /* "customer_name" => $this->customer->givenName, "customer_familyName" => $this->customer->familyName, "customer_address" => $this->customer->streetAddress, "customer_locality" => $this->customer->locality, "customer_postalCode" => $this->customer->postalCode, "customer_country" => $this->customer->country, "customer_email" => $this->customer->email */ ], ]; // $output .= "<pre>" . print_r($paymentInfo, true) . "</pre>"; $payment = $mollie->payments->create($paymentInfo); wire()->log->save("mollie", "Creating the payment... $order_id"); // Type here your custom HTML // use $payment->getPaymentUrl() as url for your payment link foreach ($methods as $method) { $output .= '<div style="line-height:40px; vertical-align:top">'; $output .= '<img src="' . htmlspecialchars($method->image->size1x) . '" srcset="' . htmlspecialchars($method->image->size2x) . ' 2x"> '; $output .= htmlspecialchars($method->description) . ' (' . htmlspecialchars($method->id) . ')'; $output .= '</div>'; } $output .= "</div>"; $output .= "<div><form action='{$payment->getCheckoutUrl()}'> <button type='submit'>". __('Pay') ."</button></form></div>"; return $output; } public static function getModuleConfigInputfields(array $data) { $inputfields = new InputfieldWrapper(); // Test API $live_api_field = wire('modules')->get('InputfieldText'); $live_api_field->name = 'test_api_key'; $live_api_field->label = __("Test API Key"); $live_api_field->notes = __(""); if (isset($data['test_api_key'])) { $live_api_field->value = $data['test_api_key']; } $inputfields->add($live_api_field); // Live API $test_api_field = wire('modules')->get('InputfieldText'); $test_api_field->name = 'api_key'; $test_api_field->label = __("Live API Key"); $test_api_field->notes = __(""); if (isset($data['api_key'])) { $test_api_field->value = $data['api_key']; } $inputfields->add($test_api_field); // Select live or test API $check_api_field = wire('modules')->get('InputfieldCheckbox'); $check_api_field->name = 'live_check'; $check_api_field->checked = $data['live_check']; $check_api_field->label = __("Use Live API Key"); $check_api_field->notes = __("If not selected, the test-api will be used. Keep in mind that you also have to activate the Live api on your Mollie dashboard"); if (isset($data['live_check'])) { $check_api_field->value = $data['live_check']; } $inputfields->add($check_api_field); // HTTP Host url $httphost_field = wire('modules')->get('InputfieldURL'); $httphost_field->name = 'httphost'; $httphost_field->label = __("HTTP Host"); $httphost_field->notes = __(""); if (isset($data['httphost'])) { $httphost_field->value = $data['httphost']; } $inputfields->add($httphost_field); return $inputfields; } }
    1 point
  11. You overide each pagereload the complete session vars. I think that the $gebruiker is not created and available on every page load, but only on a special template. You may use a conditional that secures you that a (new) gebruiker is sent and need to be transfered into the session: $gebruikerarray = json_decode($gebruiker); if(!empty($gebruikerarray->naam)) { // add new data to sessions vars ... } OR you look if $gebruiker is available or not, or if a post submitt was sent, or ...
    1 point
  12. As of (12.2018) we have this: https://processwire.com/api/ref/field/get-label/g/
    1 point
  13. You have several options in the backend: 1.) Page based under Page > Settings Enable or disable every non default language. Trying to access an inactive page will result in an 404 2.) Template based under Template > Advanced (bottom) 3.) Field based under Edit Field > Details
    1 point
  14. From what I understand, you could create/publish pages regardless of roles/permissions. However, if you were to wrap the page creation in an if statement like : if($user->hasPermission('permission-name', $page)) { // user has this permission, for this $page } then that person with the permission could perform whatever action you created.
    1 point
  15. Not exactly a changelog, but I have been thinking about adding a "What's New" section at the top of the API Explorer panel in Tracy. It would simply list any new methods or properties in the current version compared to the old version. Firstly, would you guys find this useful? Secondly, the catch with implementation is that Ryan doesn't seem to be using @since tags anymore - not sure if this is a recent oversight, or an intentional omission (https://github.com/processwire/processwire-issues/issues/759). If he gets back to me and starts implementing them again, I think that would be the simplest approach. Otherwise I'll need to cache the API explorer results and compare the current to the cached version (on PW upgrades). This isn't a big deal and I guess has the added advantage of showing all changes since your last upgrade (not the last actual version) so if you skip over a few versions, this will be more complete. So what do you think - would you guys make use of this? Can you see viewing the API Explorer panel after each upgrade to see what's new?
    1 point
  16. The Katharinenhöhe is a rehabilitation clinic in the Black Forest (Germany) for teenagers, young adults and families with children who suffer from cancer. Our agency designconcepts was lucky to relaunch their website. Our goal was to unify the previous separated areas (families and teenagers/young adults) and provide a clear structure for potential patients. Also we wanted to show that the clinic is a nice place to live, despite the circumstances. We rebuild the website from scratch with the framework UIkit and used large images as well as videos. www.katharinenhoehe.de Features: Repeater Matrix Tour Contrast Theme Glossary Autocomplete Search Facebook Repeater Matrix Most of the pages use a basic page template which have one Repeater Matrix field. This field has around 15 different content elements, so it is easy to build a page with different elements in various amounts. Tour On the site tour we build a image map with markers showing interesting places of the clinic. For this task the nice module Image Marker and the Marker component of UIkit came in handy. The tour is available on every page containing a marker. Contrast Theme For a better reading experience you can switch to a more contrasting theme of the website by clicking the theme switcher (on the top right). This is a separate stylesheet with darker color variables. The choice will be saved in a session variable and stays as long as the browser is opened. Glossary To explain complicated medical terms better, we highlight a set of terms in every textarea they occur and explain them with a tooltip. For this task we wrote a simple Textformatter module which looks for the terms in a page and replaces the terms with the tooltip. This tutorial by @benbyf helped me. Thank you! ? Modules used: Color Email Obfuscation (EMO) Front-End Page Editor Functional Fields Image Marker Markup Sitemap XML Phone ProCache Repeater Matrix Tracy Debugger Upgrades Regards, Andreas
    1 point
  17. Recently Bitrix (a popular commercial CMS here in Russia, known worldwide for its Bitrix24 CRM/PM/... solution) introduced similar functionality they called Site Constructor. This thing allows to build pages or parts of the pages from pre-defined blocks which can be static or dynamic. Site developer can style, modify or add their own blocks. They recommend this for landing pages for now, but are aiming to move all content management to those blocks. So there is some trend. I actually do use (almost) the same approach in PW. Most of my pages have content-page template with content_blocks Repeater Matrix field holding most of the content in repeater items. What is missing in my solution is: the easy ability to restrict the order, allowed types of those items (though possible with this module); the ability to easily move/duplicate content blocks from project to project (still think Repeater Matrix should be PageTable Matrix); the ability to easily preview the page built (like with this solution) in admin / edit it inline on the frontend. I see this way of building content very flexible, but still somehow unfinished. We have all the parts in PW to build a full-blown page bulder that will not allow too much for ones that do not need it, but will make it easy to build something really complex and interesting without programming. But those parts are not yet combined in a polished solution. I would certainly like to have it in PW (as a PageTable-like PageBuilder FieldType/Inputfield combo, probably).
    1 point
×
×
  • Create New...