Leaderboard
Popular Content
Showing content with the highest reputation on 08/09/2024 in all areas
-
This week I've bumped the dev branch version to 3.0.241. Relative to the previous version, this one has 29 commits with a mixture of issue resolutions, new features and improvements, and other minor updates. A couple of PRs were also added today as well. This week I've also continued work on the FieldtypeCustom module that I mentioned last week. There were some questions about its storage model and whether you could query its properties from $pages->find() selectors (the answer is yes). Since the properties in a custom field are not fixed, and can change according to your own code and runtime logic, it doesn't map to a traditional DB table-and-column structure. That's not ideal when it comes to query-ability. But thankfully MySQL (5.7.8 and newer) supports a JSON column type and has the ability to match properties in JSON columns in a manner similar to how it can match them in traditional DB columns. Though the actual MySQL syntax to do it is a little cryptic, but thankfully we have ProcessWire selectors to make it simple. (It works the same as querying any other kind of field with subfields). MySQL can also support this with JSON encoded in a more traditional TEXT column with some reduced efficiency, though with the added benefit of supporting a FULLTEXT index. (Whereas the JSON column type does not support that type of index). For this reason, FieldtypeCustom supports both JSON and TEXT/MEDIUMTEXT/LONGTEXT column types. So you can choose whether you want to maximize the efficiency of column-level queries, or add the ability to perform text matching on all columns at once with a fulltext index. While I'm certain it's not as efficient as having separate columns in a table, I have been successfully using the same solution in the last few versions of FormBuilder (entries), and have found it works quite well. More soon. Thanks for reading and have a great weekend!5 points
-
Still interested. I agree the site doesn't do justice to the product. Wordpress is looking pretty good these days, and the only other alternative I've seen deserving of notice, CraftCMS, is also looking pretty good. I think our site is directed too much at the developer audience, and I often found myself having to convince my clients that this is a better option than Wordpress or whatever platform they have in mind. And the site doesn't help much at that. If you guys want to consider a redesign, I'll gladly join that effort.4 points
-
I don’t think that’s a bad thing per se, but I agree the big PHPStorm background could probably be replaced by just the slideshow of PW admin screenshots that currently plays awkwardly on top of it. Perhaps with one or two code screenshots intermixed. In general though, maybe I’m just old, but the site doesn’t look outdated to me at all? At least the frontpage looks as fresh as ever to me. Welcoming, professional, you name it. Certainly no worse than the examples mentioned? Wordpress has a trendy serif typeface which I get is part of their printing press shtick, but I honestly find kind of offputting for what it is (also the footer is grade A pure unadulturated organic cringe and all their images are blocked by Firefox’s default tracking protection). Structurally I think the ProcessWire site could use some improving, especially these “hub” pages like https://processwire.com/docs/, especially especially if they link to the next identical looking hub page (eg. https://processwire.com/docs/start/). Someone mentioned earlier that it’s a shame a lot of great nuggets and frankly vital info can practically only be found in blog posts. I know I’ve searched for specific blog entries I knew existed plenty of times, wondering how someone who hasn’t kept up with PW for over a decade would find out about stuff like custom user parents, for example. It would be great to have a more official tutorial section for these things which the blog posts would then link to. The current tutorial section only has 10 tuts, most of which, including the "More Tutorials" link, are secretly external.3 points
-
When dealing with checkbox or radiobox inputs, if the name of the individual checkbox/radio inputs remains the same, you can set the name to an array-style, such as: <?php foreach ($pages->get(1104)->children() as $category) : ?> <div class="flex items-center"> <input id="<?= $category->id; ?>" name="category[]" value="<?= $category->id; ?>" type="checkbox" class="text-gold-600 h-4 w-4 rounded border-brown-300 focus:ring-gold-500"/> <label for="<?= $category->id; ?>" class="ml-3 text-brown-800"><?= $category->title; ?></label> </div> <?php endforeach; ?> Note the name="category[]". This then assigns the returned value(s) of the form input into the $_GET['category'] variable as an array. The way it's written now, whatever is chosen last will overwrite what was set/chosen prior, which is why you're experiencing what you're experiencing. Unlike a (multi)select element that provides option values that are assigned to the select's name, the radio and checkbox items are individual inputs with an expected (by us) association.2 points
-
I am with you @EyeDentify when you praise PW's simplicity and easiness to start to get around. But PW is also great being a powerful framework. Ryan always managed to balance things perfectly. New cool things like custom page classes never disturbed ones that didn't need them. So I am sure we can easily move forward making PW more suitable for larger projects, multi dev on the same project, more best practice compliance without sacrificing simplicity for the newbies.2 points
-
This week I received some client specifications for project that indicated it was going to need a lot of fields, and fields within fields. There are a lot of tools for this kind of stuff in ProFields, but none that I thought would make this particular project "easy" per se. The closest fit was the Combo field, but with 40-50 or so subfields/columns within each of the "groups", it was still going to be kind of a pain to put together. Not to mention, just a lot of fields and subfields to manage. To add more challenge to it, there was another group of 30 or so fields that needed to be repeatable over any number of times (in a repeater field). I wasn't looking forward to building out all these fields. That scale of fields/subfields is at the point where I don't really want to build and manage it interactively. Instead, I want to just edit it in a code editor or IDE, if such a thing is possible. With any large set of fields, there's often a lot of redundant fields where maybe only the name changes, so I wanted to be able to just copy and paste my way through these dozens of fields. That would save me a lot of time, relative to creating and configuring them interactively in the admin. Rather than spending a bunch of time trying to answer the specifications with existing field types, I ended up building a new Fieldtype and Inputfield to handle the task. Right now it's called the "Custom" field (for lack of a better term). But the term kind of fits because it's a field that has no structure on its own and instead is defined completely by a custom JSON file that you place on your file system. (It will also accept a PHP file that returns a PHP array or InputfieldWrapper). Below is an example of defining a custom field named "contact" with JSON. The array keys are the field names. The "type" can be the name of any Inputfield module (minus the "Inputfield" prefix). And the rest of the properties are whatever settings are supported by the chosen Inputfield module, or Inputfield properties in general. /site/templates/custom-fields/contact.json { "first_name": { "type": "text", "label": "First name", "required": true, "columnWidth": 50 }, "last_name": { "type": "text", "label": "Last name", "required": true, "columnWidth": 50 }, "email": { "type": "email", "label": "Email", "placeholder": "person@company.com", "required": true }, "colors": { "type": "checkboxes", "label": "What are your favorite colors?", "options": { "r": "Red", "g": "Green", "b": "Blue" } }, "address": { "type": "fieldset", "label": "Address", "children": { "address_street": { "type": "text", "label": "Street" }, "address_city": { "type": "text", "label": "City", "columnWidth": 50 }, "address_state": { "type": "text", "label": "State/province", "columnWidth": 25 }, "address_zip": { "type": "text", "label": "Zip/post code", "columnWidth": 25 } } } } The result in the page editor looks like this: The actual value from the API is a WireData object populated with the names mentioned in the JSON definition above. If my Custom field is named "contact", I can output the email name like this: echo $page->contact->email; Or if I want to output everything in a loop: foreach($page->contact as $key => $value) { echo "<li>$key: $value</li>"; } After defining a couple large fields with JSON, I decided that using PHP would sometimes be preferable because I could inject some logic into it, such as loading a list of 200+ selectable countries from another file, or putting reusable groups of fieldsets in a variable to reduce duplication. The other benefits of a PHP array were that I could make the field labels __('translatable'); and PHP isn't quite as strict as JSON about extra commas. So the module will accept either JSON or PHP array. Here's the equivalent PHP to the above JSON: /site/templates/custom-fields/contact.php return [ 'first_name' => [ 'type' => 'text', 'label' => 'First name', 'required' => true, 'columnWidth' => 50 ], 'last_name' => [ 'type' => 'text', 'label' => 'Last name', 'required' => true, 'columnWidth' => 50 ], 'email' => [ 'type' => 'email', 'label' => 'Email address', 'placeholder' => 'person@company.com' ], 'colors' => [ 'type' => 'checkboxes', 'label' => 'Colors', 'description' => 'Select your favorite colors', 'options' => [ 'r' => 'Red', 'g' => 'Green', 'b' => 'Blue' ], ], 'address' => [ 'type' => 'fieldset', 'label' => 'Mailing address', 'children' => [ 'address_street' => [ 'type' => 'text', 'label' => 'Street' ], 'address_city' => [ 'type' => 'text', 'label' => 'City', 'columnWidth' => 50 ], 'address_state' => [ 'type' => 'text', 'label' => 'State/province', 'columnWidth' => 25 ], 'address_zip' => [ 'type' => 'text', 'label' => 'Zip/post code', 'columnWidth' => 25 ] ] ] ]; The downside of configuring fields this way is that you kind of have to know the names of each Inputfield's configuration properties to take full advantage of all its features. Interactively, they are all shown to you, which makes things easier, and we don't have that here. There is yet another alternative though. If you define the fields like you would in a module configuration, your IDE (like PhpStorm) will be able to provide type hinting specific to each Inputfield type. I think I still prefer to use JSON or a PHP array, and consult the docs on the settings; but just to demonstrate, you can also have your custom field file return a PHP InputfieldWrapper like this: $form = new InputfieldWrapper(); $f = $form->InputfieldText; $f->name = 'first_name'; $f->label = 'First name'; $f->required = true; $f->columnWidth = 50; $form->add($f); $f = $form->InputfieldText; $f->name = 'last_name'; $f->label = 'Last name'; $f->required = true; $f->columnWidth = 50; $form->add($f); $f = $form->InputfieldEmail; $f->name = 'email'; $f->label = 'Email address'; $f->required = true; $f->placeholder = 'person@company.com'; $form->add($f); // ... and so on Now that this new Fieldtype/Inputfield is developed, I was able to answer the clients specs for lots of fields in a manner of minutes. Here's just some of it (thumbnails): There's more I'd like to do with this Fieldtype/Inputfield combination before releasing it, but since I've found it quite handy (and actually fun) to build fields this way, I wanted to let you know I was working on it and hope to have it ready to share soon, hopefully this month. Thanks for reading and have a great weekend!1 point
-
I've been wanting to review the 5 pages of responses and summarize the findings, but what I will say before (if?) I get to that: There seems to be three primary audiences that PW is catering to, or that it can potentially cater to: Developers (ease of development, API, headless, documentation, module development/sales, etc) Clients (security, continuously developed, version stability, availability of developers) Consumers: A developer and client all in one (all the ways in which it competes, and how it's different) It may not be evidently clear what the project is primarily aimed at catering to, and perhaps that needs to be clarified, whether directly by Ryan in terms of what he is interested/able in supporting, or by the community's desire (as Ryan seems amicable to our opinions on steering it). That may also help guide any potential website redesigns. I think this is an important question to really consider and have answered. Although it can be done, it's really hard to properly target all three of the above, all at once.1 point
-
If I understand correctly that the clicked checkboxes are already marked as checked after submitting the form, you could solve it as follows: $selectedCategories = (isset($input->get->category)) ? $input->get->category : []; <?php foreach ($pages->get(1104)->children() as $category) : ?> <div class="flex items-center"> <input id="<?= $category->id; ?>" name="category[]" value="<?= $category->id; ?>" type="checkbox" class="text-gold-600 h-4 w-4 rounded border-brown-300 focus:ring-gold-500"<?php echo in_array($category->id, $selectedCategories) ? ' checked' : '' ?>/> <label for="<?= $category->id; ?>" class="ml-3 text-brown-800"><?= $category->title; ?></label> </div> <?php endforeach; ?> I hope this helps you!1 point
-
OK here I am answering my own question, courtesies to chatGTP… 'extraAllowedContent' => '*(*){*}', // Allow any element, with any attribute, and any inline style happy days! thoughts?1 point
-
Me too. You can solve this (from a technical point of view at least) by using language-alternate fields. Combine that with @bernhard's great suggestion to sync settings between your language fields and you should be all set. The only thing you're not getting from that is the cool tabs system LanguageTabs provides. I am always extensively tagging both templates and fields. With the tags, you can even have some of them be collapsed by default. This retains all the overview I need.1 point
-
These things are so easy to do with RockMigrations: <?php // site/migrate.php $defaults = [ 'type' => 'image', 'maxFiles' => 1, 'descriptionRows' => 1, 'extensions' => 'jpg jpeg gif png svg', 'maxSize' => 3, // max 3 megapixels 'icon' => 'picture-o', 'gridMode' => 'grid', // grid, left, list ]; $rm->createField('your_image_field1', $defaults); $rm->createField('your_image_field2', $defaults); $rm->createField('your_image_field3', $defaults); You can then set custom labels for your fields or you can even set custom properties either in migrate.php overriding the defaults or via GUI as template context override. PS: If the fields already exist you CAN use ->setFieldData() instead, but ->createField() will work as well. PPS: If you need to change a setting just change the setting in the defaults, save the file and refresh your web broser!1 point
-
Here are some additional feature ideas: - The feature to define the TinyMCE-configuration of all your TinyMCE fields in a "parent"-field is so great - how about if we could have that with more fieldtypes? In my sites, I have tons of fields, which change from time to time, and as one can't use fields more than once on a template, I have e.g. image_single_1, image_single_2, image_single_3. It would be great to change all those e.g. image fields at once, by just changing a "parent field". Please tell me, if I missed that feature, if it already exists ? - Nearly all my sites have to be MultiLanguage sites, and therefore, a multilanguage image field would be great. I know Language-alternate fields, but a "real" field would be really great. The most complex project, I am working on, has currently 10 languages. When creating and maintaining all the needed fields, this is a lot of work, which could be much easier with a multilanguage image field. - As I am still working with (nested) RepeaterMatrix and Repeater fields, keeping track of fields which are really used or not used is a complicated, as simple fields often are displayed as "in use" on some pages, while those pages are not "real" pages, but system pages of repeaters. I hope you know what I mean. The feature suggestion in this case is to extend the display of fields on the fields admin page so the relations between the fields are somehow more comprehensible. - Also, the fields list get's confusing, if you have some hundred fields – the UI could be refined somehow, to make the fields list easier to work with.* * I'll try to start a thread about naming fields, because I tend to change my naming scheme with every project, because I try to find the perfect one - which I did't find yet. Perhaps you are willing to share your naming schemes. I am sure someone already invented the perfect scheme ?1 point
-
Since it looks like there is a some crossover with Mystique, and it also looks like that module is active and supported, I'll release this module in ProFields instead. That way it's not competing with Mystique, which looks to already be a great module. I'll focus on making Custom fields have some features that maybe aren't available in Mystique, like ability to query from pages.find and perhaps supporting some more types, etc. Plus, the new module fits right in with the purpose of ProFields and a good alternative to Combo where each have a little bit different benefits to solve similar needs.1 point
-
@Jonathan Lahijani Sort of, but it's not just that. I'll go into the details once I've got the storage part fully built out. It supports any Inputfield type that can be used independently of a Fieldtype. Meaning, the same types that could be used in a module configuration or a FormBuilder form, etc. It can be used IN repeater fields (tested and working), and likely in file/image custom fields as well (though not yet tested). But you wouldn't be able to use repeaters or files/images as subfields within the custom field. Files/images will likely be possible in a later version though, as what's possible in Combo will also be possible here. Yes, if you use the .php definition option (rather than the JSON definition option) then there are $page and $field variables in scope to your .php definition file. @MrSnoozles Searching yes. Can be used in repeaters (yes), but can't have repeaters used as subfield/column types within it. @poljpocket Yes. While I've not fully developed the selectors part of it yet, the plan is that it will support selectors with subfields for searching from $pages->find(), etc. @wbmnfktr The API side of this should work like most other Fieldtypes with subfields, so I think it should be relatively simple for importing and may not need any special considerations there, but I've not tried using it with a module like ImportPagesCSV yet.1 point
-
Hello There @ryan just wanted to add my concerns here. I am not an "advanced" developer, i just develop sites or conduct experiments on my own personal website thats been running PW for a very long time now. That being said, i have read through this tread and i have become a little worried that PW would be going away from it´s root that made me many years ago fall in love with it. I am concerned that many of the more advanced users of the CMS want´s to take it to a more complicated place instead of keeping PW simple for us beginners to pick up and use wich is why i love it. As a laymans dev i can actually understand most of the API and what i can use it for. Ryan have made some posts in this tread that makes me feel calmer that the core simplicity is not going to go away. I also feel that many of the more advanced devs are missing the point of PW simplicty and why not everything should be in the core. There is modules for a reason,, want something special?, then create a module. Reasons PW appeal to me: 1. It´s API made sense from the start, logicaly and was adopted fast by my Authistic brain. 2. It´s does not interfere with how i want to render my website. 3. It´s has a great admin backend that should not confuse anyone. 4. PW is not WP. Thank you all.1 point
-
Another question: In Mystique, you are able to detect the page requesting the field, and as a result, modify the fields that actually get displayed. This is very useful because it allows you to have one Mystique field but have it "morph" depending on the context. On my sites, I typically only have 1 Mystique field called 'options'. I then assign that to various templates that need it (even specific matrix-types like for my page builder). Then when the field is loaded when editing a page or a matrix-type, I can "build" the field based on what template requested it because the $page variable is available. My 'gallery' matrix-type/page builder block will have fields that are gallery configuration related, my 'video' block will have video configuration fields, but they are all still technically the single Mystique 'options' field. @ryan So in your example of /site/templates/custom-fields/contact.php, is it able to determine what page requested it?1 point
-
As others have mentioned, this is quite similar to the Mystique field which I'm a fan of and has the feel of how custom fields work in WordPress (more "on the fly"). I use Mystique for my matrix-based page builder block options which is a great fit. Will consider switching to this since it will be first-party and more integrated. Does it store the saved input data in json as well? I'm guessing this doesn't work with repeaters or images, correct?1 point
-
@BrendonKoz Looks like Mystique defines fields (subfields?) in a very similar way, in that it is also using the Inputfields settings/API (as an array) to define them. Though looks like the use of the "type" property might be something different, since it is mapping to a constant in the module rather than the name of an Inputfield. Maybe those constants still map to Inputfield names. Mystique looks good, perhaps I could have just used Mystique to solve the client's request! Though admittedly I have a lot of fun building Fieldtypes and Inputfields, and I'm guessing there will be just as many differences as similarities, but glad to see there are more options. @Kiwi Chris The syntax I'm using is just the Inputfields API. Looks like the Mystique field above also uses the same API as well. Nice that there is some consistency between these different use cases. That's good to know. Though in this case it was also that I needed a hierarchy of fieldsets which Combo doesn't support. Plus wanted something a little more lightweight, because there were so many fields and the client just needs the ability to store them and not so much to query them. I don't know if Combo is compatible with the migrations module or not, but always good to know about the options. I usually do prefer to manage stuff in the admin, but this is a case where it just seemed like it was not going to be fun.1 point
-
Seemingly quite similar to @ukyo's solution via Mystique. I have a local SQLite database that is a mirror of an external vendor's data for our event calendar (I use an API to sync their external with our local so that I can more easily integrate items into our website rather than constantly referring to their API). By parsing available data in the SQLite database (and making it available via a local REST URL) to determine options in the field, I can then use the chosen values as a filter to then query/display matching records in the SQLite database. This particular field was explicitly allowed as a RepeaterMatrix Fieldtype, and then added, in my case. My Mystique template: /site/templates/configs/Mystique.calendar.php <?php namespace ProcessWire; /** * Resource: Dynamic Calendar settings field */ return function ($page = null, $field = null, $value = null) { // Get the data to feed possible selection values $audiences = json_decode(@file_get_contents(input()->httpHostUrl() . '/calendar/audiences.php?activeMerge=1'), true); $categories = json_decode(@file_get_contents(input()->httpHostUrl() . '/calendar/categories.php?activeMerge=1'), true); $fields = [ 'event_type' => [ 'label' => __('Event Type'), 'type' => 'InputfieldCheckboxes', 'options' => [ 'events' => 'Library Events', 'meetings' => 'Public Meetings' ], 'required' => true, 'columnWidth' => 33 ], 'limit_days' => [ 'label' => __('Upcoming Days to Check'), 'type' => Mystique::INTEGER, 'min' => 1, 'max' => 60, 'defaultValue' => 1, 'initValue' => 1, 'inputType' => 'number', 'required' => true, 'columnWidth' => 34 ], 'limit_events' => [ 'label' => __('Maximum Events to Display'), 'type' => Mystique::INTEGER, 'min' => 0, 'defaultValue' => 0, 'initValue' => 0, 'inputType' => 'number', 'required' => true, 'columnWidth' => 33, 'notes' => __('Per event type. Leave at 0 for no limit.') ], 'not_found_msg' => [ 'label' => __('Message if No Matches Found'), 'description' => __('This will be displayed if no events match the given criteria. Leave blank for no message.'), 'type' => Mystique::TEXT, 'columnWidth' => 100, 'notes' => __('HTML cannot be used here. Markdown is allowed.') ], 'private' => [ 'label' => __('Include Private (Calendar) Library Events'), 'type' => Mystique::CHECKBOX, 'value' => false, 'showIf' => [ 'event_type' => '=events' ], 'columnWidth' => 33, 'notes' => __('This is not recommended.') ], 'output_style' => [ 'label' => __('Output Styling'), 'description' => __('Choose the presentation style for any events that will be displayed.'), 'type' => 'InputfieldRadios', 'options' => [ 'list' => 'A Simple Bulleted List', 'grid' => 'A Grid-Like Display' ], 'showIf' => [ 'event_type' => '=events' ], 'columnWidth' => 33 ], 'show_images' => [ 'label' => __('Display associated event images?'), 'type' => Mystique::CHECKBOX, 'showIf' => [ 'output_style' => '=grid' ], 'columnWidth' => 34, 'notes' => __('Images are always taken directly from the calendar and cannot be properly optimized.') ], 'fieldset' => [ 'label' => __('Filters for Library Events'), 'type' => Mystique::FIELDSET, 'collapsed' => true, 'showIf' => [ 'event_type' => '=events' ], 'children' => [ 'audiences' => [ 'label' => __('Audiences'), 'description' => __('Only show:'), 'type' => 'InputfieldCheckboxes', 'options' => $audiences, 'defaultValue' => '', 'columnWidth' => 20, 'notes' => __('Leave blank to show all.') ], 'categories' => [ 'label' => __('Categories'), 'description' => __('Only show:'), 'type' => 'InputfieldCheckboxes', 'options' => $categories, 'defaultValue' => '', 'optionColumns' => 3, 'columnWidth' => 80, 'notes' => __('Leave blank to show all.') ] ] ] ]; return [ 'name' => 'calendar_events', 'title' => 'Calendar of Events', 'fields' => $fields ]; }; Which then renders: I could've looped the field generation instead of the values generation, similarly to what Ryan did above, but that wasn't my use case here. Regardless of solution, it's a very handy way to generate fields, options, and values.1 point
-
A module to work around a few shortcomings of Fieldset and FieldsetPage fields. Not submitted to the modules directory because I'm hopeful that most if not all of this will be handled in the core eventually. https://github.com/processwire/processwire-issues/issues/1953 https://github.com/processwire/processwire-requests/issues/533 https://github.com/processwire/processwire-requests/issues/534 Fieldset Helper Adds some visibility features to fields of type FieldtypeFieldsetOpen and FieldsetPage, and adds a helper method to get the child fields of a FieldtypeFieldsetOpen field. Visibility The module adds support for the following visibility settings to FieldtypeFieldsetOpen and FieldsetPage fields: Open when populated + Closed when blank Open when populated + Closed when blank + Load only when opened (AJAX) * Open when populated + Closed when blank + Locked (not editable) Open when blank + Closed when populated "Blank" in the context of a fieldset means that all the child fields within the fieldset are blank. * The AJAX part of this option doesn't currently work for FieldsetPage. Get the child fields of a fieldset If you've ever wanted to get the child fields that are within a fieldset you will have noticed that the ProcessWire API doesn't provide a direct way of doing this. Although they appear indented in Edit Template, the child fields are actually all on the same "level" as the other fields in the template. The module adds a FieldtypeFieldsetOpen::getFieldsetFields() method that you can use to get the child fields of a fieldset for a given page. Example: $field = $fields->get('my_fieldset'); $template = $templates->get('my_template'); $fieldset_fields = $field->type->getFieldsetFields($field, $template); First argument: the fieldset Field, i.e. a Field whose type is an instance of FieldtypeFieldsetOpen (this includes FieldtypeFieldsetTabOpen). Second argument: the Template that the fieldset field is part of. Return value: a FieldsArray of child fields. If there is a nested fieldset inside the fieldset then the child fields of the nested fieldset are not included in the return value, but of course you can use the method again to get the child fields of that fieldset. https://github.com/Toutouwai/FieldsetHelper1 point
-
I'll share my experience as full-time 100% happy Linux user since 2018. I used Ubuntu up until a few months ago when I got my new laptop (Framework, btw). I just switched to Manjaro and have had a flawless experience. The pain point in the beginning was the common losing Photoshop conundrum, but I've found better solutions for web design since then and only use Gimp when I need to clean up/crop/make web-ready bitmap images. Moving primarily to vector for UI makes bitmap design feel very un-web. For web and layout design I've switched over to using the FOSS Penpot web app. I've traditionally be hesitant to embrace a web platform, but really with today's state of web technology I feel at home with it now and don't miss a desktop app. I've also come to appreciate that a web platform allows developers to iterate, bugfix, and deploy new features much more quickly without having to wait for an entire full local app update. I get that this can be a pain point for those looking to make the switch. In my case my work is UI/UX based and don't consider myself, nor have the talent for, a graphic designer. I, like pretty much everyone here, absolutely have to have a dependable machine to do work. My ability to earn an income stops dead without a usable laptop and having a backup machine just isn't a viable option considering how much it would take to fall back on. I'll back-to-back my experiences. I'm not trying to sell anyone on these distros, but the experience has broadened some horizons. I didn't switch for 5 years. Do what you want, it's still *checks watch* a free country. Linux in general: Free and open source. I've become much more aware and appreciative of how great this is. I don't feel "screwed around with". The "innovations" coming out of Microsoft and MacOS updates tend to be disruptive and entirely subjective as far as their utility and value are concerned. There hasn't been one single feature that they've released that I feel like I'm missing out on, and in some cases already have. Plenty of stuff I'm grateful not to have or deal with. Apple has been long-term recognized for it's decline in the "pro" experience. I feel more at home on servers and have stronger skills on the command line. Even if the distros are different, you still get a shared directory and OS behavior between server and desktop. I always appreciated Mac for the *nix-like environment, but switching to Linux still felt a lot more awesome because at the end of the day I wasn't jumping between OS' that have true distinctions. Docker just runs better both in ease of installing/managing and in raw performance- which Mac really struggles with. The fact that Windows now at least has WSL is a nod to the needs of developers. Mac specifically has had known performance issues for years. For me, security and privacy is a big deal. Win is completely out of the question, and Apple's claims are becoming less trustworthy on this front. When I boot my computer and connect to the internet my network up/down activity is literally a flat line. Aside from having automatic update checking for the OS, it don't talk to nobody nowhere about nothin'. Not possible with Win/Mac and I am also not constantly accepting new terms of service and opting out of things left and right. I think Windows Recall and Apple Intelligence are really dumb and whatever promises are made today about "security and privacy" can be cancelled via new Terms and Conditions you're forced to agree to so you can continue using your computer after a decision made based on what side of the bed a CEO woke up on or earnings report demanding more profits be made or else the CEO will be fired and replaced with a new CEO who will force it upon everyone anyway. A run-on sentence for a run-on problem. NVIDIA support is spotty, and that's on NVIDIA (linus_middle_finger_nvidia.jpg). My previous machine did have an NVIDIA gpu but it was as old as the 2018 laptop and I never had real problems with it since it had long been stable. If you're someone who needs new NVIDIA, it'll come down to some research about your gpu and compatibility. Aside from the graphics app situation, I didn't feel like I lost anything. My code editor (Sublime Text, I'm switching to Neovim) is available and there's a lot of availability great alternatives without compromise. If you like games, Steam's compatibility layer and continually widening native game selection has been a massive improvement. I'm an extremely casual game player though and others would have a better opinion on more serious gaming. Linux is a beacon of hope when faced with the depressing and accelerating trend known as "the ens**ttification of everything" Obvs, full customization, many desktop environment/window tiling options, it's like exploring the limitless frontier of space. You can do anything you want, including getting sucked into a black hole of customizing your machine and realizing at some point you just have to stop or you'll never stop. Never been there, no idea what that's like, totally hypothetical on my part, really, I would never do that, I see that none of you believe me. Ubuntu positives: Debian based means wide availability in software and a ton of support. Easy to find help online when needed. Everything can pretty much be relied upon to be ready out of the box Stable. Very. This is why I used it for so long, for reasons mentioned above Well tested before releases so you know upgrades are far less likely to break something save for the most deeply customized and tweaked systems Ready to go out of the box and does well maintaining availability for things like NVIDIA drivers where stable. It's why my NVIDIA gpu never had issues which was highly appreciated. The softest landing for someone making the jump from Win/Apple I never borked my machine to a point where it needed serious effort to get working again. This does not include typing "sudo rm -rf --force" into a terminal within a VM to see what would actually happen only to realize the VM wasn't in focus and it was actually a real terminal and find out it does exactly what you think it would do Ubuntu not-so-positives: I'll address the elephant in the room: Snaps. I've never liked them, but having had the choice of how I installed/managed my apps made it less of an issue. My tolerance ran dry once they started replacing system apps with Snaps at a direct cost of integrations due to sandboxing. Most simple example would be the calculator- they Snap'd it and you couldn't quickly type math into the Gnome search input, that's a micro-example but there are others that were problematic. Choosing to replace apps by default while removing features is just not great, especially when Snap hadn't been widely well received. Fresh installs meant a lot of work uninstalling and replacing- to a point where I kept a "checklist" so I didn't have to look them up. Snaps part II: The latest version of Ubuntu has now forced Snaps and added a lot of difficulty even forcing it to not install them by default. When I type "sudo apt install firefox", I expect a deb. What I didn't type was "snap install firefox", and Ubuntu choosing to ignore and deceptively replace what you asked for is unacceptable. I didn't know this happened until a) Firefox took longer to open, and b) I went to "About Firefox" to check. Not not not cool and it made me lose trust in Canonical. It involves extra steps that never existed before Feels bloated, I got a performance boost on the same machine switching to another distro. This means different things to different people though. Bi-annual stable release means that it's generally behind versions in things like Gnome and the kernel. This isn't 100% bad because that's a tradeoff made for peace-of-mind stability. I'm not sure if this is widespread, but out of the box APT fails because it hangs using ipv6 and doesn't fall back to ipv4. No idea why but I have to fix this on every install. Again, like the Snap calculator example, this is not a huge issue but things add up. Manjaro positives: Arch based without Arch stability anxiety. I am completely capable of managing an Arch distro but I just don't have the time to do it. As much as I want to use Arch, btw. I need to sit down at my computer and work without some concern that I might have to take a detour to manage the OS because it could cause me trouble with deadlines and confidently delivering for clients. Arch updates are tested and have a healthy delay between bleeding edge release and Manjaro updates. Personally, I wait an extra week- unless it's a notable security update, and just check in on the message boards to see if there are any known issues, then update myself. The maintainers are responsive and communicative. Absolutely faster and leaner than Ubuntu. Some of this comes from having more recent updates sooner. Gnome was a big difference because Ubuntu doesn't update as often and known performance issues take a lot longer to make it into the OS by comparison Truly clean install. Example- the dock on the left side of the screen was mentioned- not a problem on vanilla Gnome that hasn't been modified by Canonical Still has a wide selection of software. I lost nothing when switching. AUR (Arch User Repository) provides a lot of software that you are looking for available on Deb but repackaged for Arch. This falls into both positives and considerations Sane defaults, 100% worked out of the box, dip your toes into Arch without falling in. I may switch to it down the line. Manjaro considerations: Need to be mindful about updates, this is mitigated by what I mentioned above, but you have to be aware and make more decisions than Ubuntu. AUR is wide open and community maintained. Installing apps willy-nilly opens up possibilities for bad or unmaintained software. I've adopted an "install it only if you need it" and read up before I install. With Ubuntu I noticed I cared a little less about this because a lot of stuff is available via Ubuntu and trusted repositories. I'd also chalk that up to a potential false sense of security because of how beginner friendly it is. Everyone should keep this in mind regardless of distro. Involves extra documentation. If I have to look something up I check Manjaro specific info, then fall back to Arch. No something I ever needed with Ubuntu The reason one has not-so-positives, and the other has considerations is because there hasn't been anything that I don't like or been forced to deal with, only decisions I had to make when switching. Different experience. Others do not like what I like about Manjaro, and that's cool. All said- I'm not making a case for Manjaro specifically- just sharing what a compare/contrast looks like between distros and specifically back to back with Ubuntu. There are plenty of alternatives out there. Find one you like, or distro hop for fun and research. I like Gnome, others like KDE, others like i3, knock yourself out- install more than one. The world is your oyster, in space, next to the black holes. Why I mentioned my laptop... I bought a Framework 16 and love everything about it. Modularity, repairability, upgradeablity, company ethos, etc. On top of all that they have first-class Linux support and an internal team that actively works on this. Ubuntu is an officially supported distro, Manjaro is not but I've had zero issues whatsoever. Worth considering if you're in the market for a new machine. I also considered the companies mentioned by @gebeer and in the past I had a System76 as well. There are more great options these days than ever IMHO. I also want to mention- little to no fan noise at all except under real load that are directly related to what I'm doing. Maybe a little during automatic disk backups but those are fast and only when I'm connected to my external. I think the specs on a fresh machine probably help that, but battery life is also great. I also don't have the optional dedicated GPU, the AMD chip does very well with a lot of games. This has happened once for me last month and it was for a completely aesthetic and totally unnecessary it's-okay-to-laugh-at-me-for-installing-this "neat thing". I try to keep things simple but agree that this is an issue with much-customized DEs. My issue stemmed from distro updates coming out faster than the extension. Overall agree and YMMV. Happens less with Ubuntu due to the delayed Gnome releases that can be multiple versions behind current but are stable. Mad respect. I wish I could live on this level of bleeding edge. Feels like I'm watching a someone drive by in a Porsche 911 GT2 from behind the fence at a daycare playground ? GrapheneOS here. You have to like not having a lot of things though haha. Bravo. Did this years ago and it's liberating for many reasons- this forum is pretty much the only "social" account I have. As for privacy, I'll send you the dossier I purchased from a data broker with a map of your activities on and offline for the past 6 months, no need to send me your address, I know where to mail it ?1 point
-
RockMigrations now has a feature to easily make sure to fire certain migrations only once: $rm->once( "2024-02-11: Simple demo of the new once() feature", function() { bd('I will be executed only once!'); } ); Extensive docs are already in place: https://github.com/baumrock/RockMigrations/tree/dev/docs/once1 point
-
I am using this module for SEO, LANGUAGE and ELEMENTS (uikit components) USAGE EXAMPLE : LANGUAGE On my private module, i added my custom configs path to Mystique module by using : Mystique::add('my-module-configs-path'); - Create config file <?php namespace ProcessWire; // Filename: MyModule/configs/Mystique.language.php // This options normally coming from a file array, i added 2 options for example $options = [ 'tr' => 'Türkçe', 'en' => 'English' ]; $defaultValue = 'en'; /** * Resource : MyModule => Language */ return [ 'title' => __('MyModule: Language'), 'fields' => [ 'title' => [ 'label' => __('Language title'), 'description' => __('Title of language'), 'type' => Mystique::TEXT, 'columnWidth' => 50 ], 'code' => [ 'label' => __('Code'), 'description' => __('Language short code'), 'type' => Mystique::SELECT, 'options' => $options, 'defaultValue' => $defaultValue, 'required' => true, 'columnWidth' => 50 ], 'flag' => [ 'label' => __('Flag'), 'description' => __('Language flag code'), 'type' => Mystique::TEXT, 'columnWidth' => 50 ], 'direction' => [ 'label' => __('Direction'), 'checkboxLabel' => __('Right to left'), 'description' => __('Direction of language'), 'type' => Mystique::TOGGLE_CHECKBOX, 'type_fallback' => Mystique::CHECKBOX, 'columnWidth' => 50 ], 'currency' => [ 'label' => __('Currency'), 'description' => __('Code of currency'), 'type' => Mystique::TEXT, 'columnWidth' => 50 ], 'symbol' => [ 'label' => __('Symbol'), 'description' => __('Symbol of currency'), 'type' => Mystique::TEXT, 'columnWidth' => 50 ], 'grouping_separator' => [ 'label' => __('Grouping separator'), 'description' => __('Thousand separator for amount'), 'type' => Mystique::TEXT, 'columnWidth' => 50 ], 'decimal_separator' => [ 'label' => __('Decimal separator'), 'description' => __('Decimal separator for amount'), 'type' => Mystique::TEXT, 'columnWidth' => 50 ], 'separator' => [ 'label' => __('Use separator'), 'checkboxLabel' => __('YES'), 'description' => __('Apply space between amount and currency symbol ?'), 'type' => Mystique::TOGGLE_CHECKBOX, 'type_fallback' => Mystique::CHECKBOX, 'columnWidth' => 33 ], 'show_decimal' => [ 'label' => __('Decimal'), 'checkboxLabel' => __('YES'), 'description' => __('Show amount decimals ?'), 'type' => Mystique::TOGGLE_CHECKBOX, 'type_fallback' => Mystique::CHECKBOX, 'columnWidth' => 33 ], 'symbol_after' => [ 'label' => __('Symbol after'), 'checkboxLabel' => __('YES'), 'description' => __('Display symbol after amount ?'), 'type' => Mystique::TOGGLE_CHECKBOX, 'type_fallback' => Mystique::CHECKBOX, 'columnWidth' => 33 ], ] ]; - Select config file from Mystique field settings - Add Mystique field to language template Access data via api (in this example mystique field name is : lang) <?php $language = $user->language; // lang is Mystique field echo 'Title : ' . $language->lang->title . '<br>'; echo 'Code : ' . $language->lang->code . '<br>'; echo 'Flag : ' . $language->lang->flag . '<br>'; echo 'Direction : ' . $language->lang->direction . '<br>'; echo 'Currency : ' . $language->lang->currency . '<br>'; echo 'Symbol : ' . $language->lang->symbol . '<br>'; echo 'Grouping separator : ' . $language->lang->grouping_separator . '<br>'; echo 'Decimal separator : ' . $language->lang->decimal_separator . '<br>'; echo 'Separator between amount and symbol : ' . $language->lang->separator . '<br>'; echo 'Show decimal : ' . $language->lang->show_decimal . '<br>'; echo 'Show symbol after amount : ' . $language->lang->symbol_after . '<br>'; Output: Title : English Code : en Flag : gb Direction : 0 Currency : GBP Symbol : £ Grouping separator : , Decimal separator : . Separator between amount and symbol : 1 Show decimal : 1 Show symbol after amount : 01 point