abdus

Members
  • Content count

    105
  • Joined

  • Last visited

  • Days Won

    3

abdus last won the day on April 18

abdus had the most liked content!

Community Reputation

111 Excellent

About abdus

Contact Methods

  • Website URL
    https://abdus.co/

Profile Information

  • Gender
    Male
  • Location
    Istanbul, Turkey

Recent Profile Visitors

765 profile views
  1. This topic has some useful links on building custom button/command
  2. Huh, turns out there's this method inside ProcessPageView class <?php // /wire/core/ProcessPageView.php /** * Hook called when the pageview failed to finish due to an exception. * * Sends a copy of the exception that occurred. * */ public function ___failed(\Exception $e) { $this->wire()->setStatus(ProcessWire::statusFailed); } which I should be able to hook and access the exception and message with <?php wire()->addHookBefore('ProcessPageView::failed', function(HookEvent $e) { $ex = $e->arguments(0); $message = $ex->getMessage(); }) But, it's not firing when hooked inside /site/ready.php. In fact it does not appear to be used anywhere inside the core at all.
  3. While coding some templates I need to throw some Wire404Exceptions, which, expectedly, sets correct headers and renders 404 page. Since all these exceptions are extending Exception class, I can call its constructor with a message like this <?php $demoName = sanitizer()->pageName(input()->urlSegment1); $demo = pages('template=demo, name=$sanitizedPagenameFrom'); if(!$demo->id) { throw new Wire404Exception("Demo named $demoName cannot be found, but check out its source page instead"); } // inside template 404.php // somehow get the error $message echo "<h1>Page does not exist</h1>" echo "<p>$message</p>" What I want to do is to somehow catch this exception, or get inside 404 template the message that I set earlier in some module or another function, so that I can notify the user with a better message than "Error 404: Page not found". There's some parts inside core that handles this sort of things but they're not utilized. <?php // inside /wire/core/ProcessPageView.php public function ___execute($internal = true) { // ... try { // try to render the page } catch(Wire404Exception $e) { return $this->pageNotFound($page, $this->requestURL, false, '404 thrown during render'); } // ... } protected function ___pageNotFound($page, $url, $triggerReady = false, $reason = '') { // reason is not used, or passed to 404 template } So, is there a way to manually catch the exception thrown? For instance, with Silex all exceptions can be intercepted using <?php $app = new Silex\Application(); $app->error(function (\Exception $e, $code) { exit('asd'); });
  4. Process modules (ones that extend Process class) can have execute[Action] methods that are called with their respective urlSegments. In case of your example, the method comments portrait the exact conditions where ___executeFields is executed with /fields urlSegment, for instance. The problem with this approach is that you cannot (or should not) use them on frontend, as Process modules are intended for backend use (unless I'm mistaken). However, calling the method depending on urlSegment is quite simple with the snippet I posted earlier. You can use something similar to following to call execute[Action] methods <?php public function ready() { // accept only single urlSegment if($this->input->urlSegment2) throw new Wire404Error(); // always sanitize user input $method = $this->sanitizer->alpha($this->input->urlSegment1); if(!$method) return; // or perform more sophisticated checks // respond to execute[Action] methods // such as executeList() with /list urlSegment // or executeFields() for /fields urlSegment // create camelCase method name // /json urlSegment will be intercepted by executeJson() function $method = "execute" . ucfirst($method); if (method_exists($this, $method)) { $this->{$method}($param1, $param2); } else { // method does not exist throw new Wire404Exception(); } } public function executeJson() { echo json_encode(['a' => 1, 'b' => 2]); } Put this inside your init() or ready() method in your module to relay the request to specific functions.
  5. How are you using it? Is it like this one? https://processwire.com/docs/tutorials/using-custom-page-types-in-processwire/
  6. You can use this hook to remove Settings tab from page edit pages <?php wire()->addHook('ProcessPageEdit::buildFormSettings', function (HookEvent $e) { // get the page currently being edited $page = $e->object->getPage(); // check its template if($page->template->name !== 'some-template') return; // remove settings tab $e->object->removeTab('ProcessPageEditSettings') })
  7. I am not sure you can access Process modules (pages with admin template) as a guest. If you need to know what page the request is sent to, and perform operations depending on the page, or need some functionality from other autoload modules, then you'd do your checks under ready() function. If you don't, then both init() and ready() is fine. To intercept the requests, you can create a new template called api in your install() function (and remove in uninstall() function), then set it to accept urlSegments (as many as you want), then create a page with that template under root page, then inside your module check if request is made to that page and to that specific urlSegment. Optionally return 404 for all other urlSegments you're not interested in like this <?php $method = $this->sanitizer->alpha($this->input->urlSegment1); if(!$method) return; if (method_exists($this, $method)) { $this->{$method}($param1, $param2); } else { // method does not exist throw new Wire404Exception(); } You can build such a module like this <form action="/api/sendmail"> ... </form> <?php namespace ProcessWire; class MyModule extends Wire implements Module { public static function getModuleInfo () { return [ // ... 'autoload' => true // ... ] } public function ready() { if ($this->wire()->input->requestMethod() === 'POST') { // perform other checks if($this->input->url !== '/api/sendmail') return; // this is the request we should be intercepting $data = $this->wire()->input->post; $name = $this->sanitizer->text($data->name); $email = $this->sanitizer->email($data->name); if($this->sendMail($name, $email)) { // email sent successfully } else { // email failed } } } public function sendMail($name, $email) { $mailer = $this->wire()->mail; // check if any mail is sent successfully return 0 < $mailer->send( 'test@example.com', // to address 'pw@myhost.com', // from address 'Test post, please ignore', // subject 'Hey there, this is a test mail' ); } }
  8. Check out the module's support page, it has a fairly detailed tutorial
  9. You won't be modifying core files. You'll be working on translation files. From the top dropdown menu, go to Setup > Languages > [en/de] > Core Translation Files > Find Files To Translate > (pick language support module) > Submit > replace the values
  10. In case someone else encounters this issue, here's how I solved it. You will need sudo access to the server. Go to https://curl.haxx.se/docs/caextract.html You'll see on the bottom a command to download the latest CA certificate bundle. curl --remote-name --time-cond cacert.pem https://curl.haxx.se/ca/cacert.pem Download the bundle to some directory and copy it to /etc/ssl/certs/cacert.pem with sudo cp cacert.pem /etc/ssl/certs/cacert.pem Find out where php.ini is stored using locate php.ini # check for ..../fpm/php.ini then open php.ini inside some editor sudo nano /etc/php/7.0/fpm/php.ini Find where CA certs are defined with CTRL + W (search) and type cafile and hit enter, cursor will jump to the correct line Uncomment the line (remove semicolon) and type /etc/ssl/certs/cacert.pem after = sign. Restart php service with sudo service php7.0-fpm restart Hopefully this will be enough to get rid of fsockopen(): SSL operation failed with code 1 error.
  11. You can use strpos() function <?php if (strpos($page->path, "/blog/posts/") === 0){ echo "..."; } ?>
  12. If you have SSH access to the server, run dpkg-reconfigure tzdata and pick the correct timezone (no root access is needed)
  13. mini.css at 7KB gzipped is not much different than Foundation framework at 12KB gzipped or Foundation at 19KB gzipped, both of which are a lot more feature packed. This one is much smaller at 2KB gzipped that you can just inject it into HTML and not worry about extra bloat. Great if you're building something small and dont want to override much. https://milligram.github.io/
  14. I am following a similar approach, but I don't reduce objects to simpler states, I just pass them along to partial templates and use PW specific properties. Your approach is more portable with better separation, but unless you're thinking of migrating your code/template to other systems, where you'll be passing around arrays with same set of same keys, it doesn't make much difference. And not mapping objects to arrays presumably reduces process time/RAM usage as well. I think of my partial templates as components. Although much of hard work is abstracted away from them inside actual template files, components have specific functions available to them. Here's my navigation # Navigation is defined in YAML Blog: href: /blog/ class: highlight Labs: href: /labs/ Works: href: /works/ GitHub: href: https://github.com/abdusco target: _blank and here's its partial <?php namespace Processwire; /* @var $links WireArray */ $linkList = []; if (!function_exists('renderLinks')) { function renderLinks($links, $linkClass) { $out = []; foreach ($links as $name => $attrs) { if(page()->path === $attrs['href']) continue; $anchor = ''; // generate attributes string $attrs = $links[$name]; $class = $attrs['class'] ?? ''; $attrs['class'] = $class . $linkClass; foreach ($attrs as $attr => $val) $anchor .= " $attr='$val'"; $anchor = "<a $anchor>$name</a>"; $out[] = $anchor; } return $out; } } ?> <nav class="pad t--bold"> <?php foreach (renderLinks($links, 'footer-nav__link pad inline-block link link--b-no') as $link) echo $link; ?> </nav> Since I'll be passing the same YAML array, and not use renderLinks anywhere else, I keep them inside my partial. If I need to use this navigation elsewhere, I'd probably abstract link class (footer-nav__link) as a parameter I pass inside wireRenderFile, or refactor that class into a more general one.