Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 09/29/2016 in all areas

  1. Hello all, Just wanted you all to know that I found an excellent webhosting company for Benelux (where I live) and Europe. They are advertising Processwire on their frontpage, which is cool, is it not? What can Processwire want more than free publicity on hosting companies websites ;-) The link is: https://www.hosted-power.com/en/processwire Greetings, Karl.
    7 points
  2. Something like this ?: $id = $page->id; $pid = $page->parent->id; $locationData = $page->get("LocationData"); $relatedPages = $pages->find("parent=$pid, id!=$id, LocationData=$locationData");
    5 points
  3. LazyCron is a core module, a compatible version should be in the wire/modules folder.
    3 points
  4. Thanks @netcarver. Wow, this forum looks like is going to be a keeper. People say good things to random strangers. Am I on the internet? For a preview of the Work-in-progress landing page: http://codekitt.webflow.io I would love to know if the idea is communicated ok. This Mario idea may fail to get the point across. Ignore alignment, designy things... this is a live mockup.
    3 points
  5. Just for the record: I just had the problem that pages with a certain template did not save content any more. There was the green notification "Saved" but the changed fields have forgotten any changes made. The reason was that I had a fieldset in the template in the wrong order: The fieldset_END part was before the opening fieldset part. Maybe there was some inadvertent dragging of the wrong field. (tested with ProcessWire 3.34) Maybe this is useful to know for someone having the same mystery issue. Edit: This issue was solved in PW 3.35
    3 points
  6. Just a quick status update: I've started implementing different field types (text, integer, float, date, date+time) with native inputfields. Types can be switched back and forth, and I'll make it hookable so custom inputfields can be added as well. Will be a while though, since it looks like I'll be busy with a lot of other stuff until the end of next week. Here's a teaser though...
    3 points
  7. Hi There are about 10 projects I know that use Padloper (although license sales are 100+). I haven't asked promises to showcase those, but I will soon focus on that (asking showcases and putting them up to padloper.pw).
    3 points
  8. Attention: please don't install this module at the time being! It is not compatible with current PW versions, and it will be some time until I can work in all the changes. Due to a discussion here in the forums, I was inspired to finally have a take on datetime fields and see if I couldn't get them to be searched a little more conveniently. Here's a small module - still in alpha state, but I'd be happy to get some feedback - that allows searching for individual components of a date like year, month, day, hour or even day_of_week or day_of_year, and also returning them. Github repo: DatetimeAdvanced Current version: 0.0.5 Tested in: ProcessWire 2.8 + 3.0 Possible subfields: day month year hour minute second day_of_week day_of_year week_of_year Examples: // Database search: $pagelist = $pages->find("mydatefield.year=2016"); // Filtering PageArray in memory: $maypages = $pagelist->filter("mydatefield.month=5"); // Back to our starting point: $start = date('z'); $end = $start + 7; $sevendays = $pages->find("mydatefield.day_of_year>=$start, mydatefield.day_of_year<$end"); // Nice side effect: subfields are now directly accessible $blogentry = $pages->get('blog-entry-1'); echo $blogentry->title . "(" . $blogentry->publishdate->year . ")"; // New in 0.0.4: shorthand methods echo $blogentry->publishdate->strftime("%Y-%m-%d %H:%M:%S") . PHP_EOL; echo $blogentry->publishdate->date("Y-m-d H:i:s") . PHP_EOL; ToDos for the future: See if there's a possibility to specify ranges more conveniently Check if this can perhaps wiggle its way into the PW core Changes: example for direct subfield access and shorthand methods to strftime() and date() added.
    2 points
  9. Another proof-of-concept module: JsonNativeField Leverages MySQL >= 5.7.8's native JSON column type for key-value storage. This gives us the opportunity to store arbitrary (textual) fields in the database and allows us to search for them with plain subfield selector syntax, including wildcard operators. Possible applications are storing submitted form data or adding user-defined properties to their profile. Currently, the module is still really, really alpha, but I wanted to get input early on. Let me know what you think. Download from GitHub. Here are a few screenshots for anybody interested but unable to try for themselves: 1. First page with json field and custom subfields: 2. Second page with json field and custom subfields: 3. Searching through all subfields in the json field: 4. Searching only in a specific subfield: The interface is really rather crude still. The "delete" buttons only work after saving (have to attach listeners to the newly created entries yet), and I've got to straighten out supported operators for Lister to pick up. I'll see if I find some time tomorrow to work on these issues and brush up the visual side a bit.
    2 points
  10. Hi guys, Just launched my latest project, The Tourists' Affairs: http://www.thetouristsaffairs.com/en/ This one was a pleasure to build. It's based on a tours catalogue, features a tour finder, and for the first time I based a gallery on Instagram embeds. You can see those working on each tour. I'm using my basic ingredient set here: Languages, AIOM+, MarkupSEO, and not much more. Not big or complicated, but neat.
    2 points
  11. Here's a nice article with some examples if you need to allow dates before 1900 http://www.x-note.co.uk/javascript-regex-validate-years-in-range/ Also don't forget about some of the great regex testing tools: https://leaverou.github.io/regexplained/ https://regex101.com/ http://www.phpliveregex.com/
    2 points
  12. Hi @cb2004 That's a fine start However, it will also match "-", "--", "---", "-2000", "-0", "-1000-1", "1---", "31415926" etc. If you are expecting a 4 digit start and end year separated with a single dash then you will need to use a more restrictive/specific regular expression. Assuming the start year is in the 1900 to 2099 range, and the end year in the 1900 to 2999 range, you'd need something more like this; Also, if you are going to be splitting this string up into the start and end year, you might want to use a urlSegment for the start and a separate one for the end year. If that is the case, you'd use ^(19|20)[0-9]{2}$ for the start urlSegment and ^(19|2[0-9])[0-9]{2}$ for the end urlSegment. Hope that helps!
    2 points
  13. The processwire admin is using jquery all over the place, so why not use it if it's already there.
    2 points
  14. You're loading the links dynamically, so your 'click' event won't be bound to them, and the click assumes the default behaviour (without JS). That's why the url changes, and you get a page refresh. Try this instead: $("#container1").on('click','.MarkupPagerNav a', function() { Like that. the event is delegated to "#container1" — that will never change — and the dynamic content is searched for from there down. Documented here: http://api.jquery.com/on/#direct-and-delegated-events Edit: FYI I have it working on the live website only by executing this block of code on the console: $("#container1").on('click','.MarkupPagerNav a', function() { $("#container1").load( $(this).attr("href") + " #content1" ); return false; }); The miracle of inspector tools
    2 points
  15. Could you try replacing addItem() and getItem() with the following... public function addItem($arrayData) { if(!$this->_addItem()) return false; if(2 != $this->getState()) return false; if(!$fp = @fopen($this->getFilename(), 'ab')) return false; if(flock($fp, LOCK_EX)) { $arrayData = serialize($arrayData); $data = str_replace("\r\n", '\r\n', $arrayData) . "\n"; $res = fwrite($fp, $data); fflush($fp); flock($fp, LOCK_UN); fclose($fp); return $res == strlen($data); } fclose($fp); return false; } public function getItem($worker = null) { if(!$this->_getItem()) return false; if(2 != $this->getState()) return false; if(!$fp = @fopen($this->getFilename(), 'rb+')) return false; if(flock($fp, LOCK_EX)) { $line = trim(fgets($fp)); if(!$line) { flock($fp, LOCK_UN); fclose($fp); if(0 == $this->itemCount()) return null; return false; } // we have the first entry, now write all following data into a buffer $fpTmp = @fopen('php://temp/maxmemory:' . intval(1024 * 1024 * 5), 'rb+'); while(!feof($fp)) fwrite($fpTmp, fread($fp, 4096)); fseek($fp, 0, SEEK_SET); ftruncate($fp, 0); fseek($fpTmp, 0, SEEK_SET); // write back buffer into file while(!feof($fpTmp)) fwrite($fp, fread($fpTmp, 4096)); fclose($fpTmp); fflush($fp); flock($fp, LOCK_UN); fclose($fp); } return unserialize(str_replace('\r\n', "\r\n", $line)); } Untested - YMMV!
    2 points
  16. v134 is up with a new "fields" feature: now you can specify individual fields (comma separated) to load in the lightbox instead of the full admin. Thanks for @matjazp for this request and for the help. He has also found a few bugs that were fixed. Example: load title and body fields only: echo $page->feel(array( "text" => "Edit title and body fields", "fields" => "title,body" ) );
    2 points
  17. There's the option to publish/unpublish pages with the Schedule Pages module if you want to completely avoid custom code, though deleting/trashing pages based on a field value is just a few lines with the Lazy Cron module.
    2 points
  18. You're able to send an email to any service you want to after successful subscription / unsubscription. Calling an api endpoint isn't implemented yet (there are too much different services). If you miss a hookable function just let me know, I'll go ahead and add it. If everything works out (if the customer agrees to use ProcessWire), perhaps I'll soon be given an opportunity to implement a connection to mailchimp by myself.
    2 points
  19. Module: http://modules.processwire.com/modules/ajax-intercooler-js/ Repo: https://bitbucket.org/pwFoo/ajaxintercoolerjs AjaxIntercoolerJS module features integrates IntercoolerJS async CCS ("loadCSS") and JavaScript load / update optional disable async css / js handling for blocks, sidebar, ... Intercooler X-IC response header support support / hook $session->redirect multiple X-IC-Trigger handling multiple X-IC-Script handling Usage Basics It's a autoload module, but you need to enable it inside of your templates, because scripts and dependencies ("JqueryCore") have to be loaded too. You can enable / load it global inside of the TemplateFileHelper controller "_layout.php" $ic->enable(); Some changes are needed to your main template "_layout.tpl". <!-- IntercoolerJS needs a target with ID "pageContent" for (async) page content --> <div id="pageContent"><?=$pageContent?></div> And your navigation links need some IntercoolerJS attributes like that. <a href="..." ic-get-from='/url-to-load' ic-target='#sidebar'>...</a> Your just use and hook MarkupSimpleNavigation. $nav = $modules->get('MarkupSimpleNavigation'); $opts = array( 'show_root' => true, 'item_tpl' => "<a href='{url}' ic-get-from='{url}' ic-target='#pageContent' ic-push-url=true>{title}</a>", 'item_current_tpl' => "<a href='{url}' ic-get-from='{url}' ic-target='#pageContent' ic-push-url=true>{title}</a>", ); // optional modify a specific link to use another target. For example "#sidebar" $nav->addHookAfter('getTagsString', null, function($event) { $link = $event->arguments[1]; if ($link->title == 'sidebar') { $event->return = "<a href='{$link->url}' ic-get-from='{$link->url}' ic-target='#sidebar'>{$link->title} (sidebar)</a>"; } }); // render and set as _layout.tpl template var $layout->set('navigation', $nav->render($opts)); Disable CSS refresh (remove "current" styles and load the new one) The current loaded page css shouldn't removed if the sidebar is updated. So it's possible to disable the asyncHandler inside of the "sidebar" template. $ic->asyncHandler(false); Quick and dirty FrontendUser integration You just need a PW template file like that. $fu = $modules->get('FrontendUser'); $fu->login(); $button = $fu->form->fhSubmitBtn; $button->attr('ic-post-to', $page->url); $button->attr('ic-target', '#pageContent'); if (!empty($_GET['logout'])) { $fu->logout($page->url); } // Workaround until IntercoolerJS 1.0.1 release if ($input->post['ic-trigger-name']) { $input->post[$fu->form->fhSubmitBtn->name] = $input->post['ic-trigger-name']; } $processed = $fu->process($page->url); if ($processed && !$user->isGuest()) { // $processed == false if login failed (not submitted / login successful == true) echo "Hello $user->name!"; echo "<a href='$page->url?logout=1'>Logout</a>"; } else { echo $fu->render(); } X-IC Response Headers /** * Set x-ic-trigger response header * @param array $array One or more events with related data arrays */ public function trigger($array) { $json = json_encode($array); header('x-ic-trigger: ' . $json); } /** * Set x-ic-script response header * @param string $js Valid javaScript code */ public function script($js) { header('X-IC-Script: ' . $js); } /** * Stop current / parent element Intercooler polling */ public function cancelPolling() { header ('x-ic-cancelPolling: true'); } /** * Resume current / parent element Intercooler polling */ public function resumePolling() { header ('x-ic-resumePolling: true'); } /** * Set current / parent element Intercooler polling interval * @param string $interval */ public function setPollInterval($interval) { header ('x-ic-setPollInterval: ' . $interval); } /** * Set x-ic-refresh response header * @param string $pathCsv Comma separated paths to refresh. */ public function refresh($pathCsv) { header('x-ic-refresh: ' . $pathCsv); } /** * Set x-ic-open response header * @param string $url New window / tab address */ public function open($url) { header('x-ic-open: ' . $url); } /** * Set x-ic-redirect response header * @param string $url Redirect destination address */ public function redirect($url) { header('x-ic-redirect: ' .$url); } Wrapper for X-IC-Trigger Add a event trigger with event name ($event) and parameters array ($array). "addTrigger()" method is a wrapper for usage with multiple event triggers. Native method for a single execution is method "trigger()" $ic->addTrigger($event, $array); Wrapper for X-IC-Script String of javascript code for client side execution. "addScript()" method is a wrapper for multiple usage of "script()" method. $ic->addScript($javascript); $session->redirect is hooked! The module hooks $session->redirect() method for ajax calls. It's needed to execute redirects by IntercoolerJS X-IC-Redirect for ajax calls. Used for the FrontendUser integration.
    1 point
  20. I rock at regex regex:^[0-9-]+$
    1 point
  21. For what it's worth, I'm running it with 2.8.x no problem. Aren't 3.0 and 2.8.x essentially the same apart from the namespaces stuff? Does namespaces affect the module?
    1 point
  22. System fields and templates cannot be deleted without first removing the 'system flag'. Example code: $t = $this->wire('templates')->get('your-template'); if ($t->id) { // two step process to delete system template if ($t->flags == 8) { $t->flags = Template::flagSystemOverride; $t->flags = 0; $this->wire('templates')->delete($t); // delete the associated fieldgroups $this->wire('fieldgroups')->delete($t->fieldgroup); } }
    1 point
  23. But if you are already familiar with the destination and know that it is compatible, then that is still the easiest way to copy a PW installation. Perhaps the tutorial could include a caveat suggesting a test install from scratch might be beneficial if you are unfamiliar with the hosting environment. @Joss ?
    1 point
  24. Thanks for your quick reply. Sorry I missed those parts in the documentation! That has solved the problems. This seems to be a really cool module, I'm glad I tried it. I have just one more question: is it possible to upload images to the Media Manager from within the CKEditor button?
    1 point
  25. Neat indeed... This isn't meant as a critique or anything, but I just noticed a possible bug: I was randomly selecting options in the tour-finder dropdowns. The results page URL looked like this: http://www.thetouristsaffairs.com/en/tours/find-your-tour/?where=1267&when=undefined&what=undefined (Chrome / Windows) It's weird because I was definitely checking "when" + "what"... (no JS errors in the console either). Tried different options and combinations - same result.
    1 point
  26. Thanks BitPoet, I forgot that it could be found in the core
    1 point
  27. @Nukro. I see. Then it is a ProcessWire issue. I have confirmed this with an image field separate from Media Manager.
    1 point
  28. DOMContentLoaded has alot of pitfalls, browser compatibility etc etc. Why not use jQuery ready or call the script manually after the id app is in the dom.
    1 point
  29. Ok i solved the video problem with setting the maximum allowed size of uploaded files. ; Maximum allowed size for uploaded files. upload_max_filesize = 100M ; Must be greater than or equal to upload_max_filesize post_max_size = 100M I had 10M before and was trying to upload a 40M video..
    1 point
  30. My bad the cropping functionality works... I didn't recognized (again..) the Apply button on the left corner xD.
    1 point
  31. wow just read this back, and its amazingly badly typed, sorry. Yes mailchimp, I'm looking into it so will post back my implementation when done.
    1 point
  32. Kongondo it's not seeming to fit my needs in this particular case. But it is pretty great, thanks.
    1 point
  33. Hi @Nukro, Thanks for the purchase. Apologies for the 'rough start' 1. Uploading Videos: Have you specified .mp4 as an allowed extension? If not, you need to do that under Upload, then Settings Tab, scroll down to Settings: Video > Valid video file extensions What error is returned in the console (in response to the ajax request)? It could be an allowed file size issue. The error returned by the server will shed light on this 2. Editing Tags: Did you enable tags for the 4 media templates? Please have a look at the install instructions here, thanks. I have tried and have so far been unable to programmatically enable tags on install 3. Variations Hmm, that's quite a number of issues. Cropping: are you using Save as Copy? Are you developing locally or could I get some temporary access to the site to have a look around? PW version? Currently we don't officially support version 3 until there is an official release (which is soon!) Edit: How are you uploading images/media? In your screenshot above I see you are directly editing an image...
    1 point
  34. Would anyone here be able and inspired to develop a ProcessWire equivalent to the WordPress plugin WP All Import Pro? or to help me do so? This is what I'm envisioning... Upon installation the module creates an admin page titled "Import & Update". On the module config page you can specify allowed templates to run this on, otherwise allowing any. Include the following PHP libraries: hQuery for web scraping, Csv for CSV handling, and Parser for XML. Create template "import-update". On the "Import & Update" page, a list of current import/updaters will be displayed (0 initially), each with corresponding links to "edit" or "run". When you "Add New", this be the "import-update" template (with all module-specific fields tagged "impupd"): title destination (req.): parent, template source (req.): type (web, csv, xml) location (url, file, text) if web: opt. index URL & link selector, + paginator selector if csv: opt. ignore 1st row if xml: req. individual item node xpath actions (check): import (if none matching UID) update (if matching UID & field values differ) save() [req. here in flow] map (repeater): input (select fields from specified template to affect) intake (corresponding DOM selectors / CSV col. letters/headers / xpath per field) (req.) UID (unique ID; field reference to compare against, from selected input fields) (req.) Lazy Cron interval Scripts can be run via the import-update template; keep logs; show preview (iframe/ajax) for manual runs. ...
    1 point
  35. Besides the hidden admin page approach, you could use a module config page to return the AJAX data. You would need to have an additional module because an inputfield module doesn't autoload. So your module folder consists of: TestAjax.module InputfieldTestAjax.module InputfieldTestAjax.js TestAjax.module <?php class TestAjax extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'TestAjax', 'version' => '1', 'summary' => 'Installs and is used by InputfieldTestAjax.', 'installs' => 'InputfieldTestAjax', 'autoload' => "template=admin", ); } public function init() { $this->config->js('admin_url', $this->config->urls->admin); $this->config->js('module_name', $this->className()); $this->addHookBefore('ProcessModule::executeEdit', $this, 'ajaxResponse'); } public function ajaxResponse($event) { if(!$this->config->ajax || $this->input->get->name !== $this->className()) return; $event->replace = true; $data = '{}'; if($this->input->post->test_ajax) { $test_ajax = $this->input->post->test_ajax; // populate $data } $event->return = $data; } } InputfieldTestAjax.js $(function() { var test_data = { test_ajax: 'my string' }; var url = config.admin_url + 'module/edit?name=' + config.module_name; $.ajax({ url: url, data: test_data, type: 'post', success: function(data) { alert(data); }, error: function(jqXHR, textStatus, errorThrown) { console.log(textStatus, errorThrown); } }); }); InputfieldTestAjax.module ...whatever you need for the inputfield.
    1 point
  36. Sounds great, unfortunately the MySQL requirements doesn't allow me to try. Any chance to add a screenshot to see something "tangible"?
    1 point
  37. Another way could be to just remove the lines from the mysql dump, where it populates the caches table. Let the creation of the table in the dump: DROP TABLE IF EXISTS `caches`; CREATE TABLE `caches` ( `name` varchar(128) NOT NULL, `data` mediumtext NOT NULL, `expires` datetime NOT NULL, PRIMARY KEY (`name`), KEY `expires` (`expires`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; But remove all following rows that insert data: INSERT INTO `caches` (`name`, `data`, `expires`) VALUES('Modules.info', ... , '2010-04-08 03:10:10'); INSERT INTO `caches` (`name`, `data`, `expires`) VALUES('Permissions.names', ... , '2010-04-08 03:10:10'); INSERT INTO `caches` (`name`, `data`, `expires`) VALUES('ModulesVerbose.info', ... , '2010-04-08 03:10:10'); INSERT INTO `caches` (`name`, `data`, `expires`) VALUES('Modules.site/modules/', ... , '2010-04-08 03:10:10'); INSERT INTO `caches` (`name`, `data`, `expires`) VALUES('ModulesUninstalled.info', ... , '2010-04-08 03:10:10');
    1 point
  38. I may be interested if I get into vue.js (not had time to look at it yet sadly).
    1 point
  39. Interesting to see someone else using PW + Vue.js. Building components in Vue and using things like webpack and hot reloading has been kind of eye opening for me. I've just finished a small website/shop that uses Vue to render some elements. Things like the cart made a lot of sense, calculating/updating prices as quantities are edited for example. The cart in this instance is essentially a popover and doesn't need to be rendered immediately or visible for SEO purposes, which was a primary concern with this site. Where Vue was used to render actual content, I ended up writing duplicate templates in both PHP and using Vue components (the latter overwrites the former) which is obviously not ideal. I'm looking to eventually transition to using Vue/Vuex/Vue Router, moving away from writing PHP based templates and just using PW to expose JSON data via some kind of custom API. But as I almost exclusively build websites and not apps, things like SEO have always been a bit of a concern. I need to read a lot more about how to handle server side rendering with Vue for example. I wonder if there are enough people here who would be interested in some kind of PW/Vue/Webpack project template for use with Vue CLI or similar?
    1 point
  40. You probably did not replace the whole wire folder, but only replace existing files, because JqueryFancybox is no longer part of ProcessWire.
    1 point
  41. If you're logged in you have no template cache, unless you enable it for logged in users. That's enough most of the times. There's also whitelist for POST and GET for template cache. So simply adding "nocache" to the GET field when enabling template cache would let you see non-cached version by simply adding /?nocache to a url. The only way to disable template cache via a config, the only way would be to make a hook before Page:render() and set the "allowCache" render option to false. Somewhere in an autoload module public function init() { $this->addHookBefore('Page::render', $this, 'hookRenderPage'); } Then the method to set the arguments for "allowCache" to false if config disableTemplateCache is true public function hookRenderPage($event){ if($this->config->disableTemplateCache){ $args = $event->arguments(1); $args['allowCache'] = false; $event->setArgument(1, $args); } } Now one can add to the config $config->disableTemplateCache = true;
    1 point
  42. v1.3.2 is uploaded with a tiny but useful addition: middle-click on the edit link opens the admin in a new window. This can be handy if you want to see the "big picture" or eg. when you have AdminOnSteroids' fixed CKE toolbar ON and the CKE field is too high. We have also made the initial steps towards an "Add new" button so it will appear in a future release.
    1 point
  43. Once again heads up, everyone, I just now updated the “stable” German language pack for 3.0.34, which – as usual by now – means a lot of work, mostly by Manfred, (translating all the things) followed by a little work by me (merging). As usual, thanks to all the contributors, especially Manfred for his tireless efforts and Robert, who took the time to iron out a looooooot of small mistakes. Everyone, enjoy and please report anything you may find wrong or worth improving, ideally in a pull request at https://github.com/yellowled/pw-lang-de, please.
    1 point
  44. OH, I thought you were talking about posts automatically being merged within a certain time period. This particular feature is just regular "flood control" to prevent member accounts being able to spam lots of posts all over the place before a staff member can intervene. I think we probably have enough staff now though that it can be lowered to 30 seconds from the current setting of 60 seconds - does that help?
    1 point
  45. To tell the truth, I've just copied it over from Ryan's blog post without thinking too much... Probably that is why the "Composer method" of installing is not yet "promoted". I'm not a Composer user, but it would be interesting to see what the recommended way of setting up a site and using Composer at the same time is. A tutorial for Composer newbies like me would be nice.
    1 point
  46. I converted another site from a foreign system into PW. The previous page wasn't responsive, so I converted / redesigned it using Bootstrap 3. http://die-leserei.de
    1 point
  47. I had to do some tinkering around with WebODF and Wodo.texteditor to see if this was a possible approach for modifying report templates in the backend. Turned out there were too many features missing, but I've nonetheless uploaded a very basic (and experimental) module to github that let's you edit ODT (Open Document Text, format used by OpenOffice and LibreOffice). I'll be brushing it up a bit when/if time allows. If anybody wants to take a look or steal/improve on the idea: FieldtypeOdfFile Have fun!
    1 point
  48. If you don't want the "optional" HTML tags removed there is a setting in ProCache to disable this behaviour.
    1 point
  49. Thanks soma for the info. I ran into some issues but realised the module installed itself. My new code: if ($modules->isInstalled("MarkupBox")) { echo $modules->get("MarkupBox")->render(); }
    1 point
×
×
  • Create New...