Jump to content

Jonathan Lahijani

Members
  • Posts

    740
  • Joined

  • Last visited

  • Days Won

    28

Everything posted by Jonathan Lahijani

  1. Just a heads up for anyone using DigitalOcean and sending out emails using SMTP with port 587, DigitalOcean just recently started blocking this port on "new" droplets. I put "new" in quotes because that's not true: I have a droplet from months ago, before their supposed announced change, and it still got blocked. I didn't realize this until one of my clients brought it up. Good job DO! /s I use WireMailSmtp and power it with Mailgun's SMTP credentials with port 587. I've been doing it this way for a long time, although using Mailgun's direct API approach (of which WireMailgun uses) is more preferred and would avoid this issue. I will start taking that approach soon with new and existing sites. Using SMTP is convenient however. Anyway, I'm not the only one that's complaining: https://www.digitalocean.com/community/questions/smtp-587-ports-is-closed An easy fix, for now at least, is to use port 2525 which is not blocked and which Mailgun also supports: https://www.mailgun.com/blog/email/which-smtp-port-understanding-ports-25-465-587/
  2. They are droplets. One droplet is Ubuntu 22.04 and the other is 24.04. I don't think the droplets themselves have the same hardware specs. There wasn't a similarity between the sites that would possibly explain it, at least not an obvious one.
  3. (I'm putting this in the Dev Talk forum since I don't think this is ProcessWire specific.) I have a ProcessWire site on a DigitalOcean server using Ubuntu 24.04 with MariaDB and PHP. This site doesn't receive much traffic. On 4/1/2025 MariaDB crashed. Here's what systemctl said: > systemctl status mariadb.service × mariadb.service - MariaDB 10.11.11 database server Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; preset: enabled) Active: failed (Result: exit-code) since Wed 2025-04-02 06:31:12 UTC; 9s ago Duration: 1month 5d 13h 27min 44.368s Docs: man:mariadbd(8) https://mariadb.com/kb/en/library/systemd/ Process: 752113 ExecStartPre=/usr/bin/install -m 755 -o mysql -g root -d /var/run/mysqld (code=exited, status=0/SUCCESS) Process: 752115 ExecStartPre=/bin/sh -c systemctl unset-environment _WSREP_START_POSITION (code=exited, status=0/SUCCESS) Process: 752118 ExecStartPre=/bin/sh -c [ ! -e /usr/bin/galera_recovery ] && VAR= || VAR=`/usr/bin/galera_recovery`; [ $? -eq 0 ] && systemctl set-> Process: 752178 ExecStart=/usr/sbin/mariadbd $MYSQLD_OPTS $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION (code=exited, status=1/FAILURE) Main PID: 752178 (code=exited, status=1/FAILURE) Status: "MariaDB server is down" CPU: 178ms Apr 02 06:31:12 myserver1 mariadbd[752178]: 2025-04-02 6:31:12 0 [ERROR] InnoDB: Failed to read log at 73992704: I/O error Apr 02 06:31:12 myserver1 mariadbd[752178]: 2025-04-02 6:31:12 0 [ERROR] InnoDB: Plugin initialization aborted with error Generic error Apr 02 06:31:12 myserver1 mariadbd[752178]: 2025-04-02 6:31:12 0 [Note] InnoDB: Starting shutdown... Apr 02 06:31:12 myserver1 mariadbd[752178]: 2025-04-02 6:31:12 0 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed. Apr 02 06:31:12 myserver1 mariadbd[752178]: 2025-04-02 6:31:12 0 [Note] Plugin 'FEEDBACK' is disabled. Apr 02 06:31:12 myserver1 mariadbd[752178]: 2025-04-02 6:31:12 0 [ERROR] Unknown/unsupported storage engine: InnoDB Apr 02 06:31:12 myserver1 mariadbd[752178]: 2025-04-02 6:31:12 0 [ERROR] Aborting Apr 02 06:31:12 myserver1 systemd[1]: mariadb.service: Main process exited, code=exited, status=1/FAILURE Apr 02 06:31:12 myserver1 systemd[1]: mariadb.service: Failed with result 'exit-code'. Apr 02 06:31:12 myserver1 systemd[1]: Failed to start mariadb.service - MariaDB 10.11.11 database server. Not sure why that happened and this is a recently built ProcessWire site (no legacy cruft). I thought simply restarting MariaDB would fix it but it didn't. Not even restarting the server fixed it. After Googling and ChatGPTing, this post (and ChatGPT) recommended removing /var/lib/mysql/ib_logfile0 (and iblogfile1), then restarting. The replies to that post suggest that while it works, it's dangerous for reasons related to potentially losing data. Given that this site is not mission critical, that wasn't a concern and the approach suggested worked. Ok. --- Now today, on a totally different site and server (still DigitalOcean) with the same Ubuntu version and LAMP stack, MariaDB crashed in the same way. I ran the same command "systemctl status mariadb.service" on that server and the output was basically identical. Restarting MariaDB worked in this case so it was much easier to fix. Again, this site doesn't receive much traffic. --- I'm wondering what's going on here? While these sites do get the typical hack-bots trying to exploit WordPress or insecure env files and things like that, I don't think that's the story here, even though they do tend to hammer the server. It has to be one of the following reasons logically speaking: a bug with MariaDB and/or Ubuntu? a bug with ProcessWire? an issue with DigitalOcean underlying hardware? Unlikely. overloading of server resources from hackbots or even AI crawlers? I looked at my logs and that didn't seem immediately plausible something code related on my end? Possible because they are both running my home-grown ecommerce module. Anyone else have issues with MySQL or MariaDB crashing for odd reasons?
  4. Good question. It has to do with an order and production management system I'm developing. Imagine you ordered a blanket with a personalized design, like a family photo of your choosing, and your order is for 3 of them. That's a print-on-demand product that has to be ultimately manufactured by a fulfiller. A person in the fulfiller manufacturing company will get this order and see it as 3 separate "production jobs" (not one production job with a quantity of 3 -- it's done this way because each manufactured product has to have specific status tracking and other data associated with it), but since it's the exact same product and design, the artwork that needs to be printed (a jpg or png) is actually the same across all 3, and they all point to the same file (won't get into the details of how it's all structured, it's very complex). However I also designed the system so that an employee can understand a production job just by looking at the filenames of the artwork files they downloaded from the manufacturing system, which is required because after they download that file, it has to go through special ripping and printing software. The filename format would be like this: [manufacturer-location]___[provider]___[ship-by-date]___[product]___[production-job-id-x].png That "x" at the end is represents the number based on the quantity of that exact personalized product. A realistic example would be like this based on the quantity of 3 blankets that were originally ordered: losangeles___somebigecommercesite___2025-03-28___blanket-60x80___123456-1.png losangeles___somebigecommercesite___2025-03-28___blanket-60x80___123456-2.png losangeles___somebigecommercesite___2025-03-28___blanket-60x80___123456-3.png So going back to the download attribute and custom filenames, that original file may have been originally called 123.png (where '123' is the id of repeater the artwork file belongs to since that repeater has a single-file field), but when it is downloaded through the interface by a person in the manufacturing facility, it will download as losangeles___somebigecommercesite___2025-03-28___blanket-60x80___123456-1.png, -2, thanks to the download attribute. Those downloaded files can then easily be loaded into a ripping software and the worker won't need to "think" about which ones had multiple quantities since that is fully expressed as individual files.
  5. Some time ago, I learned you can add the "download" attribute to a link to force a browser to download the file when its clicked, like this: <a download href="my-awesome-file.jpg">Download</a> What I didn't realize until today is that you can actually specify a filename as a value for the download attribute like this which will automatically use that filename instead!: <a download="my___awesome___file.jpg" href="my-awesome-file.jpg">Download</a> This is incredibly convenient because it means if I want a user to download the same exact file 3 times but with specific filenames for each, I can just do this: <a download="my___awesome___file-1.jpg" href="my-awesome-file.jpg">Download 1</a> <a download="my___awesome___file-2.jpg" href="my-awesome-file.jpg">Download 2</a> <a download="my___awesome___file-3.jpg" href="my-awesome-file.jpg">Download 3</a> Furthermore, as you can see, I am using a triple underscore which ProcessWire cleans up and changes to a single underscore, as well as other changes (such as lowercasing everything) when uploading to a pagefile field. I want my filenames to be exactly as I upload and I know there's ways to prevent ProcessWire from doing that, but using the download attribute in the way I described works perfectly for my use case.
  6. I resonate very deeply with this, especially in the last 2 years where I'm using ProcessWire as a web application framework. Maybe it's my impatience of having to write migration files or the fact that I'm usually a team of one, but modeling an app in this way and getting an admin interface "for free" with everything interconnected is peak productivity. I look at ProcessWire very differently as of 2 years ago. In 2006/7, not long after I decided to get into website development, I gravitated towards Ruby On Rails (which has a special place in my heart even though I haven't used it in over a decade). However given my lack of experience with programming in general at that time (I was more of a "hacker") and the fact that a web application framework lends itself to complex applications, OOP, software engineering, etc., it was too early for me to pursue that line of work, so I went down the CMS path and eventually found PW in ~2012 after searching for an alternative for WordPress for a few years. Two years ago, I had the opportunity to re-write an internal order and production system (a true web application... no frontend, purely admin) and I had to make a decision... should I write this in a web application framework like Rails/Laravel or can I actually do this in ProcessWire in the "ProcessWire Way"? This forced me to look at ProcessWire in completely differently and to make a long story short, I've proven it to myself, on a deep level, that ProcessWire is a very capable web application framework as well. Realizing and proving this to myself with this system I've developed is liberating because for me, I can use one system to do two very different types of projects.
  7. Nice. Just wanted to mention Cerberus as an alternative to MJML if you want to use email-friendly HTML templates directly.
  8. Very cool. You got the "PATH" stack going there too (ProcessWire, Alpine, Tailwind, HTMX). Nice. Funny enough, I happened to watch this video on YouTube about the history of Palm Springs architecture.
  9. @bernhard How do RM's config migrations work when it comes to creating pages, since it doesn't support page creation? So let's say I wanted to create /colors/ with child pages red, green and blue. I would have: /site/RockMigrations/templates/colors.php /site/RockMigrations/templates/color.php /site/RockMigrations/fields/color.php To make the 'color' single-select page field use /colors/ as a parent page and 'color' as a template, the /colors/ page needs to be created using the 'colors' template and red/green/blue need to be created with the 'color' template. Where would the code go for creating those pages if now the code for fields and templates are done in the new "config migrations" way?
  10. @FireWire Have you used managed databases with Vultr? I see that they don't have MariaDB, but I suppose MySQL should be fine.
  11. @markus_blue_tomato Is there a reason you didn't use Session Handler Database? https://processwire.com/docs/security/sessions/
  12. I was thinking about this as well recently. Here's what I came up with: function convertRepeaterPageToPage($repeaterPage, $newParent, $newTemplate, $newStatus) { // store for cleanup $forPage = $repeaterPage->getForPage(); $forField = $repeaterPage->getForField(); // convert $repeaterPage->set('parent_id', $newParent->id); $repeaterPage->set('templates_id', $newTemplate->id); $repeaterPage->set('status', $newStatus); $repeaterPage->set('published', time()); // make this adjustable as well? $repeaterPage->save(['noHooks'=>true]); // cleanup $forPage->save($forField, ['noHooks'=>true]); return $repeaterPage; } Note: It should be improved to make sure what's provided in the arguments is valid. Also maybe have the ability to set the 'name' field of the page as well instead of preserving the auto-generated one that a repeater item gets assigned. Also maybe use types for the arguments. --- Example: Let's say you have a repeater field called 'books'. Then you decide one day that it would be better that they existed as regular pages instead of repeater pages. Therefore, you would create a new template called 'book' making sure it has the same fields as the repeater fields, then do this: foreach($pages->get('/path/to/page/')->books as $book) { convertRepeaterPageToPage($book, wire('pages')->get('/foo/'), 'book', 1); }
  13. I've literally thinking about that these past few weeks. What a timely post!
  14. @Jan Romero Thanks for your research. Your approach worked but yea it's not efficient as you say. I created a feature request: https://github.com/processwire/processwire-requests/issues/550
  15. @Jan Romero Thanks for making me aware of that method. I tried it and used the full path, but it didn't seem to work. I tried it in /site/init.php and /site/ready.php and other status files, but no luck. I traced the code to see where it executes, and from what I can tell, it seems that path will not get added in time, which is a little surprising. But maybe I haven't totally thought it through? Since this is kind of a rare thing I'm trying to do, I wonder if it's technically supported.
  16. ProcessWire's default folder for site modules is /site/modules/. I want to have a separate folder called /site/modules-2/ where additional modules are available. I believe this is technically supported however I haven't seen any discussion on it. I tried doing this in /site/init.php: // init.php wire('modules')->loader->loadPath(__DIR__ . '/modules-2/'); That finds the additional modules when I refresh the admin modules page and allows me to install a module in that folder. However after installing it, it technically becomes immediately uninstalled. I can't uninstall the module at that point, but if I try to reinstall it, I get an integrity constraint violation. So I have to remove the bit of code above. Then if I refresh admin modules again, it becomes missing (correctly) where I can then remove it. Doing it over again leads to the same result. I feel like while having multiple module holder folders is possible, it's either buggy in ProcessWire, or my approach is incorrect. Any suggestions?
  17. I have a page that has a two repeater fields. Those two repeater fields have nested repeaters, etc. I want to run a hook after the page has been saved, BUT only after all the repeaters and nested repeaters have been saved as well. If I use addHookAfter on Pages::saved(template=mytemplate), the hook fires after the page is saved, but before all the repeaters and nester repeaters are saved. What's the correct way to do this?
  18. It was a pleasure speak with you today @bernhard. For the others wondering, we mainly talked about "rabbit hole" you can go down with ecommerce and how there has to be a line drawn between what one gets with a fresh installation vs. what one must build on their own. Basically, how turn-key the solution is and how that relates to the target audience the system would be for.
  19. I've integrated Stripe Payment Elements with my system which we can discuss @bernhard. Stripe is hugely popular in the US and it's probably the easiest to work with.
  20. @bernhard Would love to chat about RockCommerce. I have my own internal ecommerce system that I've built with PW so I've walked this path as well and can offer some insights.
  21. This thread is #1 on HN at the moment: https://news.ycombinator.com/item?id=41805391 Do a search for processwire on the page. Looks like an old forum member.
  22. @bernhard RockMigrations and ProcessDbMigrate take fundamentally different approaches. RM takes the traditional web application framework approach while ProcessDbMigrate is more of a change recorder, similar to Craft CMS Project Config. There's trade-offs to each approach, but I will say it's nice to have changes to be recorded automatically, even if it's not a 100% full-proof approach (although I'm looking into that). It's basically automating what I typically do when I need to migrate a changes "by hand" on the sites I work on, which is an approach I like. I'm experimenting with the change recorder approach in a module of my own for now, but development of it is on and off for the moment. Understanding ProcessDbMigrate helped with understanding the approach, and the recording part of it is straight-forward. The "playing" of the recording gets tricky for all the reasons we all know about.
  23. This idea is so under rated. Forums have declined in popularity as the primary communication method for software projects and general communities over the years in place of social networks and chat apps (Reddit, Discord, Twitter, Facebook). This makes me very sad because I find forums to be the optimal way to communicate while maintaining true control of the community. Discussions on Discord/Slack can't be discovered by a search engine. Twitter and similar services aren't ideal for long discussions. Reddit seems childish and their UI update is terrible. Facebook is closed and has bad discoverability. If ProcessWire didn't have this forum, it wouldn't be nearly the same. If a large software project similar to ProcessWire doesn't have a community powered by a forum like this, it's a big missing feature in my book. When I did a small Craft CMS project a few years ago, there was no equivalent to this forum, only Slack, although it did have a lot of people in it. Then if I asked a question that was answered in the past many times over, I would probably feel like an idiot.
  24. MariaDB won't be an issue. I'm running ProcessWire on it with quite a few sites, from simple to complex, without any issues. (fun fact, Craft CMS requires MySQL or PostgreSQL; MariaDB won't work) I don't have direct experience with setting up Litespeed but that shouldn't be an issue either. I think Geffen Playhouse (a site I developed) is on Litespeed. The hosting company has abstracted that away and Litespeed is built as a drop-in replacement (?) for Apache so I wouldn't worry about that either. As @da² mentioned, if you use Windows, WSL is an excellent and seamless choice to spin up a VM to test, or DigitalOcean or Hetzner if you don't want to install a VM hypervisor on your system. Either way, you'll have to set up the server software and configure it yourself. I recommend Ubuntu 24.04 and installing everything with apt. If using VS Code, you can connect to the server and modify files as if it were a local VM site using VS Code Remote SSH.
  25. I recently discovered Pinkary.com which I would describe as a Twitter clone, built by one of the Laravel team members with all the latest and greatest of Laravel and its ecosystem (the project is open-source). Right now it's got about 1000 members after being launched earlier this year and it's almost all web developers, which reminds me of the early Twitter days. I don't get excited about social media or microblogging much, but having a concentrated community of like-minded folks is intriguing and a place to find interesting things going on and nuggets of information, without all the noise, bots and other nonsense you'd see on Twitter/X. I think it's worth a join.
×
×
  • Create New...