Leaderboard
Popular Content
Showing content with the highest reputation on 12/03/2021 in all areas
-
ProcessWire 3.0.190 has 15 commits relative to 3.0.189 and contains a mixture of issue resolutions and feature additions. We’ll review these below, in addition to updates for the PageAutosave and ProFields Table modules— https://processwire.com/blog/posts/pw-3.0.190/17 points
-
PageMjmlToHtml Github: https://github.com/eprcstudio/PageMjmlToHtml Modules directory: https://processwire.com/modules/page-mjml-to-html/ A module allowing you to write your Processwire template using MJML and get a converted HTML output using MJML API. About Created by Mailjet, MJML is a markup language making it a breeze to create newsletters displayed consistently across all email clients. Write your template using MJML combined with Processwire’s API and this module will automatically convert your code into a working newsletter thanks to their free-to-use Rest API. Prerequisite For this module to work you will need to get an API key and paste it in the module’s configuration. Usage Once your credentials are validated, select the template(s) in which you’re using the MJML syntax, save and go visualize your page(s) to see if everything’s good. You will either get error/warning messages or your email properly formatted and ready-to-go. From there you can copy/paste the raw generated code in an external mailing service or distribute your newsletter using ProMailer. Features The MJML output is cached to avoid repetitive API calls Not cached if there are errors/warnings Cleared if the page is saved Cleared if the template file has been modified A simple (dumb?) code viewer highlights lines with errors/warnings A button is added to quickly copy the raw code of the generated newsletter Not added if the page is rendered outside of a PageView Only visible to users with the page’s edit permission A shortcut is also added under “View” in the edit page to open the raw code in a new tab Multi-languages support Notes The code viewer is only shown to superusers. If there’s an error the page will display: Only its title for guests Its title and a message inviting to contact the administrator for editors If you are using the markup regions output strategy, it might be best to not append files to preserve your MJML markup before calling the MJML API. This option is available in the module’s settings. If your layout looks weird somehow, try disabling the minification in the options.6 points
-
Short URLs VS Flat URL Structure Does URL Length Affect SEO? https://www.searchenginejournal.com/does-url-length-affect-seo/425230/ Google: No Benefit to An Artificially Flat URL Structure https://www.searchenginejournal.com/google-no-benefit-to-an-artificially-flat-url-structure/400609/4 points
-
If you want to have a bit of fun, I recommend the EXIF specs: 2.3 (2010) 2.3 (2012 revision, including fixes in the orientation part) 2.31 (2019) All of them say of orientation 8 “The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom,” so 90° CCW seems correct. Further down you can find such gems as “Orientation = 8 is equivalent to an arrangement that is turned Orientation = 3 90 degrees clockwise”. Skip to Orientation 3: “Orientation = 3 is equivalent to an arrangement that is turned Orientation = 6 90 degrees clockwise” … “Orientation = 6 is equivalent to an arrangement that is turned Orientation = 1 90 degrees clockwise”. Right. Thankfully, Orientation 1 is self-sufficient: “Orientation = 1 is created when 0th row of the coded image data stored in the Exif image file and the visual top of the display screen, and 0th column and visual left, will each be matched for display”. Hooray. I feel like I’m in an escape room.4 points
-
When you look at the WireHTTP code you can see that when you're leaving the `use` options to `auto` (and no `fallback`) it will first try to send a cURL request and, should it fail, send another one using socket. In your case that's exactly what's happening since your tests return 404s.4 points
-
And not to forget URL hooks: https://processwire.com/blog/posts/pw-3.0.173/#making-short-urls-of-all-blog-posts4 points
-
Hello @SwimToWin, just out of curiosity: Is there a source for this statement? I don't quite believe that this makes any difference at all. Also you can already achieve this by using for example URL segments on your homepage: https://processwire.com/docs/front-end/how-to-use-url-segments/ You would just have to check the URL segment with the page somewhere else in the page tree. Regards, Andreas4 points
-
Agree with @FireWire. This looks like the behaviour is wrong and an issue should be raised in the issues repository. The problem seems to lie in this line: https://github.com/processwire/processwire/blob/d78276e2c265f6b70384a13eb4febd4811a1db77/wire/core/WireHttp.php#L563 Every statuscode should be treated as a successful response, as long as the server was able to contact the remote server. EDIT: The comment on top of the line of code linked above says `no need to fallback to sockets`, but then the $result is set to false. I think this is meant to be a `$result = true;` instead of `$result = false;`. Then the rest of the logic would seem to be correct again.3 points
-
Fieldtype modules Not really a tutorial, but a bunch of stuff I learnt in building a fieldtype module (FieldtypeMeasurement). That module is used as a starting point for many of the examples. Happy to take corrections and improvements ? Basics For a (full-featured) module, you actually need two module files: FieldtypeModuleName.module; and InputfieldModuleName.module The Fieldtype module defines the general settings for the fieldtype (how it appears in the setup->field page), together with how it interacts with the database, while the Inputfield module defines how the field appears when editing it in a page. In addition, for complex fields, you can define a class to hold your field values in an object. This allows you to provide custom methods for use in the API. Otherwise you can store field values as any existing type or ProcessWire object The chart below summarises the interactions of these elements and the subsequent sections describe the methods in more detail. Fieldtype Module The important methods are described below. __construct() Generally not much is required here (apart from parent::__construct();). If you have a php script with the field object then include it (require_once() ). SQL database interaction getDatabaseSchema(Field $field) This is essential. It states what data will be saved to the SQL database (via the sleepValue function - see below). An example is: public function getDatabaseSchema(Field $field) { $schema = parent::getDatabaseSchema($field); $schema['data'] = 'double NOT NULL'; // value in base units $schema['magnitude'] = 'varchar(64)'; // value in current units - needs to be text to store composite values $schema['unit'] = 'text NOT NULL'; $schema['quantity'] = 'text NOT NULL'; return $schema; } 'data' is required and is a primary key field which means that 'text' cannot be used, although varchar(64) is OK. Often (as here) it would be a numeric field of some type. Other items can be defined as required. ___sleepValue(Page $page, Field $field, $value) This determines how the ProcesssWire field object is mapped to the SQL schema. You need to return an array where the keys are the elements defined in the schema, e.g.: $sleepValue = array( 'data' => $data, 'magnitude' => $magnitude, 'unit' => $value->unit, 'quantity' => $value->quantity ); return $sleepValue; ___wakeupValue(Page $page, Field $field, $value) This is basically the inverse of sleepValue - mapping the array from the database into the field object. In the example below, the field object (Measurement) extends WireData. Properties in WireData objects can be stored in the 'data' property via 'get' and 'set' methods. getBlankValue() (see next section) performs the initial setting of these - config values for the field (see below) can be set, but otherwise the settings are just placeholders. Properties set to a WireData object can also be set or accessed directly, like $item->property or using array access like $item[$property] public function ___wakeupValue(Page $page, Field $field, $value) { // if for some reason we already get a valid value, then just return it if($value instanceof Measurement) return $value; // start a blank value to be populated $measurement = $this->getBlankValue($page, $field); // if we were given a blank value, then we've got nothing to do: just return a blank Measurement object if(empty($value) || !is_array($value)) return $measurement; // create new Measurement object $measurement->quantity = $value['quantity']; // ... custom processing ... $measurement->baseMagnitude = $value['data']; if($value['unit']) { $measurement->unit = $value['unit']; $units = $measurement->getUnits(); if(array_key_exists($value['unit'], $units) && isset($value['magnitude'])) { $measurement->magnitude = explode('|', $value['magnitude']); } else { $measurement->magnitude = $measurement->baseMagnitude; $measurement->unit = $measurement->units->base; $this->error('... error msg ...'); } } else { //... } if(!is_array($measurement->magnitude)) $measurement->magnitude = [$measurement->magnitude]; return $measurement; } getBlankValue(Page $page, Field $field) This should return an empty item of the appropriate type. For instance, if your field object is an array, just return array(); If the field type is an object then you will need to return a 'new ObjectClassName()'. Pre-fill any config values from the Fieldtype settings but leave blank those which are set in the Inputfield, In the above example, the field object data was set as follows: public function getBlankValue(Page $page, Field $field) { /* @var $field FieldtypeMeasurement */ $measurement = new Measurement($field->quantity, null, []); if ($field->quantity) $measurement->set('quantity', $field->quantity); $measurement->set('magnitude', []); $measurement->set('shortLabel', null); $measurement->set('plural', null); return $measurement; } If your object has configurable fields that can be modified according to context (as defined in getConfigAllowContext() - see below), then you will need to deal with this in getBlankValue too, e.g. : public function getBlankValue(Page $page, Field $field): Measurement { //NB Field details may differ between templates so we need to get the field in context $context = ($page && $page->id) ? $field->getContext($page->template) : $field; ... $measurement = new Measurement($context->quantity, null, []); ... return $measurement; } But note that this does not completely deal with the situation where the field is in repeater matrix items where the types might have different contexts - there you might need: public function getBlankValue(Page $page, Field $field): Measurement { //NB Field details may differ between templates so we need to get the field in context $context = ($page && $page->id) ? $field->getContext($page->template) : $field; ... // if($page instanceof RepeaterMatrixPage) { // This does not always work - see edit note if($page->template->pageClass == 'RepeaterMatrixPage') { if($page->getField($field->name)) { $context = $page->fieldgroup->getFieldContext($field, "matrix$page->repeater_matrix_type"); } } ... $measurement = new Measurement($context->quantity, null, []); ... return $measurement; } See this post for more details. Configuration ___getConfigInputfields(Field $field) This defines how the Details tab in the field setup page will look. The best thing to do here is to find a fieldtype module that is similar to the one you want if you are uncertain. Broadly the process is: define the config object - $inputfields = parent::___getConfigInputfields($field); for each config item, use the appropriate input field, e.g . $f = $this->modules->get("InputfieldSelect"); assign the relevant attributes. $f->name = $f_name; is important as it enables the item to be subsequently referred to as $field->f_name in, for example, getBlankValue(). append each item ($inputfields->append($f);) and return $inputfields; ___getConfigAllowContext(Field $field) This determines if the above input fields are allowed to have unique values per Fieldgroup assignment enabling the user to configure them independently per template in the admin, rather than sharing the same setting globally. E.g. public function ___getConfigAllowContext(Field $field) { $a = array('quantity', 'units', 'hide_quantity', 'show_update'); return array_merge(parent::___getConfigAllowContext($field), $a); } In this example the settings 'quantity', 'units', 'hide_quantity' and 'show_update' can be varied in different template contexts. Link with the Inputfield module This is done with getInputfield(Page $page, Field $field) e.g.: public function getInputfield(Page $page, Field $field) { $inputfield = $this->wire('modules')->get('InputfieldMeasurement'); $inputfield->setField($field); return $inputfield; } If you want to reference the current page in the inputfield, you will also need to include $inputfield->setPage($page); If your fieldtype is an object and you want full context flexibility including for different repeater matrix item types, then you may need to use this: public function getInputfield(Page $page, Field $field): Inputfield { $inputfield = $this->wire('modules')->get('InputfieldMeasurement'); if($page->template->pageClass == 'RepeaterMatrixPage') { if($page->getField($field->name)) { $field_in_context = $page->fieldgroup->getFieldContext($field, "matrix$page->repeater_matrix_type"); if($field_in_context) { $field = $field_in_context; } } } $inputfield->setField($field); $inputfield->setPage($page); return $inputfield; } Inputfield Module __construct() Generally not much is required here (apart from parent::__construct();). If you have a php script with the field object then include it (require_once() ). Configuration ___getConfigInputfields() This is pretty much exactly the same construction as the similar method in the Fieldtype class. The only difference is that these settings will appear in the 'input' tab of the fieldtype settings, rather than the 'details' tab. ___getConfigAllowContext(Field $field) This is the equivalent to the Fieldtype::getConfigAllowContext() method, but for the "Input" tab rather than the "Details" tab. Input and output The key methods for this module are to render it from the fieldtype and database and to process the user inputs. ___render() $field = $this->field will have the field config settings from the fieldtype module. $this->attr('value') will have the current values for the field. If there is no current values then, if using a field object, you will need to create a new object, e.g.: if($this->attr('value')) $value = $this->attr('value'); // Measurement object else { $value = new Measurement(); } You can then use $field and $value to display the inputfield (which might be a fieldset) as required using the appropriate pre-existing inputfield modules. (Again, find an existing module that is similar, if you are uncertain). renderValue() This is required where the field is locked (not editable) and therefore render() does not apply. Get the value with $value = $this->attr('value'); and then apply the required formatting, returning the output string. ___processInput(WireInputData $input) Here you take the inputs and update the field values. As in render(), set $value = $this->attr('value') ; and then modify $value for the inputs. For example, set $name = $this->attr('name'); and then assign the inputs thus: $input_names = array( 'magnitude' => "{$name}_magnitude", 'unit' => "{$name}_unit", 'quantity' => "{$name}_quantity", 'update' => "{$name}_update" ); You can then loop through the inputs and carry out the required updates. The example below is slightly convoluted but illustrates this: foreach($input_names as $key => $name) { if(isset($input->$name) && $value->$key != $input->$name) { if($key == 'magnitude') { $input->$name = trim($input->$name); if(!is_numeric($input->$name)) { $magnitude = explode('|', $input->$name); $magnitude = array_filter($magnitude, 'is_numeric'); $value->set($key, $magnitude); } else { $value->set($key, [$input->$name]); } } else { $value->set($key, $input->$name); } $this->trackChange('value'); } } When all is done, return $this; Custom classes As mentioned earlier, for complex field types it may be useful to set up custom classes to hold the data. Typically a custom class would extend WireData, which is ProcessWire's class designed for runtime data storage. It provides this primarily through the built-in get() and set() methods for getting and setting named properties to WireData objects. The most common example of a WireData object is Page, the type used for all pages in ProcessWire. Properties set to a WireData object can also be set or accessed directly, like $item->property or using array access like $item[$property]. If you foreach() a WireData object, the default behaviour is to iterate all of the properties/values present within it. Do not declare any such properties in your class (or declare properties with the same name) otherwise you will end up with two properties, one in the 'data' array and one outside it and endless confusion will result. It is advisable to put any such classes in your own namespace. In that case, you will need to include 'use' statements in your script - e.g. use ProcessWire\{FieldtypeMeasurement, WireData}; use function ProcessWire\{wire, __}; and also include use statements in your module scripts, e.g. use MetaTunes\MeasurementClasses\Measurement;2 points
-
Thanks @teppo for pointing me to that bug report. It looks like it's the same issue indeed. I'll add a comment to that issue. Edit: done.2 points
-
I just published the new release! In the end I added a condition checking ProcessWire's version and calling the `getPage()` replacement, which uses a new `$pages->request()` method. Let me know if you notice anything else!2 points
-
The first part with the errors on initial save has been solved but I still need to find an alternative for the second part. In more recent dev versions Ryan removed a function I was relying on in my code (namely ProcessPageView::getPage) and I need to look for an alternative. I'll publish an update once it's all good.2 points
-
Well... https://github.com/Toutouwai/VirtualParents2 points
-
Ah, sorry, I could have noticed that yesterday, since it’s in the same line ? You’re using $template but haven’t defined a variable with that name. $page->template->label should work. Btw, when you do this if ($page->matches('customer_project')) return; make sure to go to that page’s settings tab and check the “unique” box to prevent any other pages from getting the same name (theoretically possible in other parts of the page tree). Additionally you can probably make this faster by comparing $page->name directly. The matches() function first needs to parse the selector string and figure out what to do with it. Alternatively, test the entire path with $page->path or $page->url, that way you guarantee uniqueness.2 points
-
Here's a detailed example of how to achieve this with URL segments:2 points
-
I’m still not 100% on our ultimate goal here. Do you really want to see the IDs in the tree? If it’s just about the way pages look in the tree, you can configure that in the template settings. In the Advanced tab there is a setting called “List of fields to display in the admin Page List” that you could configure to something like ”({id}) {template.label} {date}“ to get pretty much what you’ve described. Depends on the default date output format that is set up in the date field. Obviously you can also just hardcode the template’s label instead of {template.label} since this is template-specific anyay. In any case, this technique is completely independent of the page’s title. In fact, pages don’t need to have titles at all. You can uncheck “global” in the title field’s advanced settings and it will stop showing up in the Add screen. If these pages don’t need titles at all, because a combination of other values is sufficient, you can then remove the title field from the templates entirely. Or, if you want to keep it around because it can be a nice convention for all pages to have a title, you can make the field hidden for these templates, and generate pages’ titles on saving the page. The hook might look like this: $this->addHookBefore("Pages::save(template=renovation|delivery|recycling)", function(HookEvent $event) { $page = $event->arguments(0); $page->of(false); $page->set('title', $page->template->label . ', ' . date('Y-m-d', $p->date)); }); If these pages are for internal use and don’t need a name (the bit that identifies the page in the url), you will spare users the need to make something up on the Page Add screen. Unfortunately I believe this is only possible if the parent page accepts only a single template for children. In that case you could go to Family tab of the parent page’s template settings and enter a “Name format for children”, pretty much like the page list fields above. The Page Add screen is then bypassed entirely, because ProcessWire knows everything it needs to know (parent, template, name). I’m always in favour of skipping the Page Add business if possible, but in your case you need to choose a template anyway. To get rid of the name input, you might hook ProcessPageAdd::buildForm: $this->addHookAfter("ProcessPageAdd::buildForm", function(HookEvent $event) { //maybe check the parent page if you don’t want this to happen indiscriminately. //also, since you have multi-language inputs, you may have to adjust for that. //feels hackish, there may be a cleaner way to achieve this. $form = $event->return; $nameField = $form->getChildByName('_pw_page_name'); $nameField->wrapClass = 'InputfieldHidden'; //ProcessWire won’t let you proceed without a name, so generate something here, or //just set a static value. PW will automatically make it unique by adding a number. //Be aware that it will increment any number at the end of the name if it’s not unique, //so if you add two pages with the name “2020-12-31”, the second one will end up as //“2021-12-32”. Also, you’ll get a warning, so it’s probably best to generate a unique //name yourself. At this point you can’t use the ID because it doesn’t exist yet, though. $nameField->value = 'schnitzelmedpommes'; }); The ability to have default page names with multiple possible templates may actully be a worthwhile feature to add to the ProcessWire core. I’m not sure why it wouldn’t work, and philosophically it would fit PW’s ideal to be a “Content Management Framework”. Not every page needs a deliberate name if it just stores data.2 points
-
We are a digital agency based in Nuremberg, Germany. We are currently seeking a remote ProcessWire developer to extend our development team (currently 3 dev's). Your skillset should include: ProcessWire, Node.js, Gulp, SCSS, Bootstrap 5. Medical projects would be your main focus (NDA required).1 point
-
The link abstraction part sounds a lot like https://github.com/processwire/processwire-issues/issues/1244 to me. Just cross-linking for reference.1 point
-
I have to manually enter the link in the source code, as choosing it from the link dialog in CKEditor points to the page in the same language. So as @wbmnfktr says, it's no use for a non-developer. Edit: Just to clarify, before turning off "Link abstraction", I could edit the link manually to point to another language and the changes were correctly saved, but it always redirected me the current language when clicking on the link on the front-end. Now at least there's a workaround, even if it's not client-friendly at all. There should be a visual way to select other languages in the tree.1 point
-
1 point
-
1 point
-
1 point
-
This doesn't indicate a properly working Apache for all scenarios at all. It's just the most basic startup screen you could imagine for LAMP setup. So... you installed everything in just one folder (/var/www/html/PROGRAMMSUBFOLDER)? No... set up VirtualHosts. That's a one-time-investment in a solid dev environment. From there... you could go in any direction. With ProcessWire, WP, Drupal, Typo3... whatever. That's the default behaviour when installing ProcessWire into a subfolder. While it works... I wouldn't recommend it. Only when you really know what you are doing, testing for example, or when you already installed Processwire 100 times. ProcessWire was ready to go. Your setup wasn't. Sorry when this sounds a bit rude but using a non-working or better to say not fully configured environment as a base for whatever kind of (web-) development and then blaming the software because it doesn't like it that much... is unfair. I can't and won't blame you but I want to move your focus to the reason for your experience here. It wasn't ProcessWire. Sure installation is sometimes a bit more than just clicking but in this case there were way more steps than really necessary. In case you want to experience a super solid installation that's a breeze... use something like Laragon on Windows, MAMP on Mac or ... let's skip the Linux part here. One last word here: Even though my response here could be read a bit harsh... I really appreciate that you stayed the whole way, worked through everything from start to finish. And I wish and hope you start to love ProcessWire like each and everyone here in this thread and community.1 point
-
@wbmnfktr thanks for your answer. So we're stuck in a loop and can't break out of the currently selected language it seems.1 point
-
Oof doesn't sound good (thus the alpha state)... I'll have a look, thank you for bringing this up!1 point
-
As this module was just recommend to me I had to give it a try. Got the necessary API keys and grabbed the latest copy from Github. The result so far: Double checked the entered credentials, picked some templates and ... I'm running the latest PW 3.0.189 here and have to remove the module to bring the site back to live.1 point
-
The error happens because $page is not defined, so you can’t call matches() on it. Fixing it is slightly involved, because we’re hooking ProcessPageAdd::buildForm, which means you can’t just do $event->object->page. $event is the HookEvent. It has information about the hook itself, the affected object and in this case the return value. $event->object is the object whose method we’re hooking, i.e. ProcessPageAdd. ProcessPageAdd should know the parent page to which we’re about to add a child, but I’m not sure how best to access it. $event->object->page is the page ProcessPageAdd belongs to. This will be a system page with the ID 6. It’s just “this is the Page Add Screen”, so that’s not what we need. However, the form that PW has built contains a hidden field for the parent page which we can access: $event->return->getChildByName('parent_id'). This should contain the parent’s ID, but not the page object itself. So this might work: $this->addHookAfter("ProcessPageAdd::buildForm", function(HookEvent $event) { $form = $event->return; $parentField = $form->getChildByName('parent_id'); $parent = pages()->get($parentField->value); if ($parent->matches('dashboard_servicepage_totalrenovation|dashboard_service_bathroomrenovation|dashboard_service_extension|dashboard_service_demolition|dashboard_service_recycling')) return; $nameField = $form->getChildByName('_pw_page_name'); $nameField->wrapClass = 'InputfieldHidden'; $nameField->value = 'Newpage'; });1 point
-
Honestly I'm not that familiar with WireHttp, it was just a way for me to have a look at the source code and learn something as well ? Looking again at the code it seems you can get more information about the error by calling print_r($http->error). Maybe it's not the 404 triggering an error in the cURL call but something else ? Again no expert, just trying to help.1 point
-
Got it. This introduces something that isn't noticeable even when reading the method documentation. In HTTP terms a 404 status isn't a failure, it's a successful response from the remote server that should be interpreted by the application making the request. When I read fallback, I assumed that it's because the request attempt failed, for example if CURL isn't available on the system it falls back to fopen. A use case I have is to check that a page exists and then let the user know, so a 404 is useful because the user is shown the error, they can fix the URL, and then the new URL is tested. Sending via 2 different methods the user must wait 3x longer. The immediate solution is to manually add parameters to every WireHttp call to disable the default configuration, but that seems like an extra step to keep WireHttp from ignoring a valid response. All that said, does this have some sort of benefit I'm not seeing? When should a 404 be treated like a failure rather than an informative response to a successful request? First time using WireHttp. I've always written my own CURL methods, just trying to make sure I'm not missing a benefit that this has.1 point
-
Hopefully those other suggestions will help answer your question, but like @AndZyk I'd be interested to see what the justification is for not organising your pages in sections. My feeling is that hiding navigational elements is more likely to have a detrimental effect on usability (and hence SEO). I can't be the only one who occasionally edits a URL to navigate up a level (ok, I might be). Perhaps it's different if you have a limited number of products on a site but I think having a decent hierarchy is going to be better for users.1 point
-
You sir deserves a medal ? That worked. Changed the second functions with setAndSave also. I dont getting the template label though.. maybe you can give me some help tomorrow, thanks again.1 point
-
Hi, I’m in bed but regarding maximum function nesting level, consider adding the noHooks option to your setAndSave call: $page->setAndSave('title', "($id) {$template->label} | $address", ['noHooks' => true]); I suspect you’re getting into an infinite loop because setAndSave triggers the hook on Pages::saved.1 point
-
In this way it will generate an image variation and the original image will stay untouched, but as I understood @picaricawant to resize the original image. If so, you can do something like $this->addHookAfter('InputfieldImage::fileAdded', function(HookEvent $event) { $inputfield = $event->object; if ($inputfield->hasField != 'image' && $inputfield->hasField != 'images') return; $image = $event->argumentsByName("pagefile"); $maxSize = 780; $portrait = $image->height > $image->width; $property = $portrait ? 'height' : 'width'; $width = $portrait ? 0 : $maxSize; $height = $portrait ? $maxSize : 0; // if the current size exceeds the max, proceed a resize if ($image->$property >= $maxSize) { $is = new ImageSizer($image->filename, ['quality' => 100]); $done = $is->resize($width, $height); } });1 point
-
Going through this topic, I am hopeful the Intellisense after setting up VSCode will help me discover more in the core that's difficult to learn from external documentation. As much as I loved Atom and its graphical project viewer extension, the IDE capabilities are unfortunately problematic in my experiences. So here I am, giving VSCode another shot. Oh yes, since going through this topic, some have added extensions to their projects that VSCode has since added to the core editor, so some of you might be able to reduce the count of some of your extensions. Thanks to everyone for providing their findings (and snippets) so far! Color-coded bracket matching: Now in a core setting called Editor > Bracket Pair Colorization Renaming of matching HTML tags is part of the core via the rename ability (place cursor in/on tag name, press F2), though it currently doesn't work in PHP files (work in progress, I guess?) - alternatively, for simple matching replacements, you can double-click on the element name and press CTRL+D (or CMD+D on Mac) for automatic multi-select, then type the new tag name. These all have issues, so tag-rename or auto-rename-tag might still be preferred. Reformatting/Beautifying: SHIFT+ALT+F will automatically reformat the code of the file in focus, or currently highlighted code; also available from the right-click context menu (not yet sure how to define different formatting rules). URLs typed in the editor will be openable by default via CTRL+Click via Editor > Links. Not sure if people know, but it also offers code folding: CTRL+SHIFT+[ to fold/collapse, CTRL+SHIFT+] to unfold/open...or just use the caret symbols next to the text editor's line numbers. I think everything else (questioned raised) has been covered, or not yet able to be solved.1 point
-
Hmm, I think there's a few mistakes here. You should be hooking to InputfieldImage::fileAdded() instead of InputfieldFile::fileAdded() as you wouldn't want to resize files. Also in your first code you're trying to resize every images along with the current one uploaded, I don't think there's a need for that. Your hook could simply be: $this->addHookAfter('InputfieldImage::fileAdded', function(HookEvent $event) { if ($event->object->name === 'image_slider') return; $image = $event->arguments(0); // no need to save the page or the image as it is automatically generated / saved as a variation if($image->width > $image->height) { $image->width(1600, true); // from the doc: a boolean is assumed to be for "upscaling" } else { $image->height(1600, true); } }); And then afterwards you can call your image with: $image = $page->images->first(); $image = $image->width > $image->height ? $image->width(1600) : $image->height(1600); echo $image->url; However seeing how you check for a max-width/height why not just rely on the admin UI, in the image field settings ("Input" tab), to simply set a max size ?1 point
-
Here it is! Great! Now it must be easier to start with Wireframe from a blank slate installation.1 point
-
Hey @Ivan Gretsky No reason whatsoever — probably just forgot. Submitted ?1 point
-
Well Rick and Chris - some amazingly good news at last!! Rick - Apache worked perfectly. Default page etc. after installation. I've loaded some programs with an associated 'index' file and these all worked perfectly, too. And I did load PW as suggested fixing every problem (bar the lack of zip) as it occurred. This was my frustration - PW indicated that it was 'up and good to go'. Except it clearly wasn't!! Then as suggested I 'fixed' the 000-default.conf file and this led to the error I indicated (and which Chris has kindly commented on). There was another issue with this - I was no longer able to call up the index file that showed my applications. So, I changed the config file setting to read DocumentRoot /var/www/html (removed the pwire directory) and same for <Directory /var/www/html/........ I also commented out the entire rewrite options in.htaccess And as if by magic, it all works!!! Using the 'vanilla' IP address of the server shows me my index file and associated applications. Adding /pwire to the URL takes me to the PW home page - and all the links work! Login to admin; site map; about - whoopee!! ? Now, as fantastic as this is it would have been nice if PW on installation, had 'warned' me that I might need to fix an Apache config file and not left me wondering why this "easy to use" CMS wasn't...... But there we are. Thanks a million to all the patient and very helpful contributors. Very much appreciated!1 point
-
1 point
-
I am finishing the next release right now and will be pushing a new version. In this version you can customize all Fluency UI strings for any default language, using the translation service if desired.1 point
-
This has been an intermittent issue for me with PW as long as I can remember.1 point
-
I’m not quite sure if this is of interest for anyone and if this is the right forum for my post, but I got the client request to build a module extension for Fluency which translates all the text fields in a page with only one click. The module is not really ready for public (or the modules section), as it has no config page yet and was only tested in one ProcessWire installation, but maybe it is useful as a starting point for anyone who is in the same situation as me: https://github.com/robertweiss/ProcessTranslatePage The module checks for fluency-translate permissions and adds a ›Translate and save‹-button to the edit-page. It supports all core language fields, Repeater, FieldsetPage the pro modules Repeater Matrix, Combo and Functional Fields. Caution: for now, the (language-)settings have to be manually edited in the hookPageSave-Method (Lines 64–69).1 point
-
@FireWire Do you think you can bring an update to module to translate from secondary language to main language? Eg: Site Main lang is DE and sec lang is EN , but the article writer writes the text in english and the client would be able to translate from EN to DE (main language)1 point
-
Thanks for your thoughts @FireWire - I think I'll be having to switch to Lingvanex sooner than later, so there might be a PR coming you way. Let me know if you already have any thoughts on how you would like to implement different translation engines so that I hopefully do it in a way that you're happy with.1 point
-
Really no problem at all. I've released a newer version since then that addresses an issue that I didn't see come up in testing previously. Just a courtesy tag in case the bugfixes end up helping someone. I haven't heard of Lingvanex before so I didn't know to look into them. Initially when I found DeepL I was really impressed by the service but needed someone else to really verify what was going on because I only speak English. I had a coworker who speaks Spanish look at the results and he was very impressed. I kind of stopped there and didn't think to look further. Overall if someone was able to verify the quality of translation of any translation then that's all that matters. I don't have any personal allegiance to DeepL, it's just what I found and what I heard about on the PW forums which also nudged me towards them. It would be interesting in the future to update Fluency to allow the dev to select a translation engine, and the way the module is built I think it could be done well. I wish I could work on that now but I just had 3 clients contact me for work and that's in addition to my day job...1 point
-
Pushed the fix that removed the bd() call. Thank you for the reminder. I put some work in over the weekend on the permission feature. The new permission is named "fluency-translate" in case you want to rename yours to match the later releases. This release also formally adds the 5th Fluency->translate() argument to feed in additional API parameters. Everything is always a time crunch between holidays here, looking forward to when I can get back to working on more changes. Permission will be the next feature. Excellent to hear that it's in production! We've been using it and it's been smooth sailing.1 point
-
With the much improved docs, these days, this should not be your first point of call ?. Yes, this should be the first place you check. By default, yes. However, there are options to refine how the sanitizer should work. Did you have a look at the white/blacklist options? This works fine with a Textfield called bid with a value of $100. <?php namespace ProcessWire; $allow = ["$"]; $selector = $sanitizer->selectorValue("$100", ['whitelist' => $allow]); $bids = $pages->find("bid=$selector");1 point
-
0 points