Leaderboard
Popular Content
Showing content with the highest reputation on 12/26/2024 in all areas
-
Ok great, please change the name of this thread to "[solved] ..."1 point
-
If $this->prefix is empty you set the type of the "title" field to "text", which would explain your issue!1 point
-
I'd not say it's strange. It makes sense. I just tried to confirm that the log you posted is not related to the issue you are seeing. What I'd do: Confirm that your change is coming from RockMigrations To do so check "Disable all migrations" in RockMigrations module settings. Then set your title field back to "textLanguage" Do a modules refresh, or even better run php site/modules/RockMigrations/migrate.php from the command line (you get more logs) Is your title field still "textLanguage"? yes --> seems like RockMigrations is the issue To confirm remove the tick on "Disable all migrations" Do a modules refresh (or run migrate.php) Is the title field now "text"? Yes --> confirmed that RockMigrations is the issue No --> should not be possible IMHO no --> something else is changing the field type. maybe another module? or maybe some of your own code? If you can confirm that RockMigrations is the issue you should have something like this somewhere in your codebase: 'type' => 'text', "type" => "text", The problem is that it might exist in any variation, like "type" => 'text', with or without comma, etc.; Let me know if you find something.1 point
-
Well... it has Pro's and Con's I guess. For example if you wanted those fields to be textarea (single Language), but then you install language support later that would mean RockMigrations will change the field's type, which might not be intended. But I guess you are right in this case that it's the more likely situation that those fields should be multilang when languages are enabled. I have updated the blocks to use the dynamic version.1 point
-
but wouldn't the more dynamic solution from the accordion template be more versatile? That way you wouldn't even have to touch the demo block phps to have it when u activated pw language.1 point
-
Hi @Yipper thx for the info! I have updated all example blocks like this: public function migrate() { $rm = $this->rockmigrations(); $rm->migrate([ 'fields' => [ self::field_text => [ 'type' => 'textarea', // or textareaLanguage 'inputfieldClass' => 'InputfieldTinyMCE', ... Will be part of the next release!1 point
-
@teppo, just in case you are in doubt what is that what you can gift to the world this New Year, I am quite sure the world will be delighted with the new Wireframe version with themes support)) Well, maybe not the whole world, but certainly some minor parts of it))) I do not know how do to say "happy upcoming New Year" in English or Suomi, so I'll put it here in Russian: "С наступающим!"1 point
-
Have you ever realised that DDEV only works when you are connected to the internet? No? Then all fine 😉 If you did, I have good news for you! DDEV does NOT require a working internet connection! You can, of course, use it for local development without being online - for example on a plane. The only thing you need to know is that if you started the project via "ddev start" while being connected to the internet and then you go offline, then your browser will not find your project any more. All you have to do to solve that is to run a "ddev restart" 🙂 The reason for this is explained here: https://ddev.com/blog/ddev-name-resolution-wildcards/ @gebeer1 point
-
We had a chat a bit with @Ivan Gretsky and understood that probably I need to complete our story with more details. Unlike common images of start-ups, this is not fun at all. As mentioned, we developed this system bootstrapped for 1,000 days with a remote team of 11 (4 female, 7 male) from Ukraine, Georgia, Netherlands, Germany, Switzerland, Poland, and Thailand. My second son was born during this period, and I was literally working on this with a baby in one hand and a laptop in the other. We lost connection with our lead developer, as he was in Kharkiv (Ukraine). We haven’t had a connection with him since July, but I sincerely hope he is safe… If someone had told me that it would take 1,000 days (I had planned for three times less) and several thousand engineer hours, I probably would have never started this development, as it looked so unreal. It took approximately half the time to develop the system itself and another half to debug it to the condition it has now. Of course, during this development, we had to rewrite everything from nearly scratch several times, and it still doesn’t look perfect, but at some point, we understood that it is impossible to develop the code on our own and we need to share it with the community. The code release itself was quite a journey. Especially the last weeks, days, and, most difficult of all, the last hours. Arina (our junior lead developer) and me spent all day in a smoke-filled bar in Belgrade polishing the last version prior to release. And, of course, at the very last moment, we found a very unusual error that was extremely difficult to debug at 1AM. And at 6AM, I had to rush to the airport. There was a 37.5cl bottle of champagne for the three of us: myself, Arina and our director (photo attached), and despite popular images of startups, there was no party at all, only a pretty intensive and really hard time prior to release. So my advise for everyone whom working on large code base are following: - multiply every realistic time estimation for three; - have always backup for lead developer; - be ready to release the code better soon than later, as it will never be accomplished. I write this here now because I wish to learn this before starting this journey. Of-course I expect that there another bunch of rakes around that only waiting for it’s time P.S. If someone could share simple user tracking event module for ProcessWire that we can adopt for use with tirreno, it would be highly appreciated. I was not aware how stars are important for GitHub ranking, so would like kindly ask to put one if you see this software helpful: https://github.com/TirrenoTechnologies/tirreno1 point
-
Thx for the explanation! A huge motivation of RPB was to get rid of the workflow that you show here, because in TinyMCE you have no control over how large your image is, what the final aspect ratio will be, etc, etc. That can lead to severe design issues, for example because clients make it look nice on desktop, but they forget to think about all other screen resolutions. With RockPageBuilder we as developers/designers take care of that and the client just uploads content and provides the text. It's still not an easy to solve problem sometimes, but imho it's the better approach.1 point
-
@wbmnfktr The ecosystem of available packages and services is definitely one of the major draws of Laravel. It almost parallels the Wordpress ecosystem, but ten times more professional. A lot of Laravel packages are very high quality, actively maintained, well tested, etc. That's probably a result of their somewhat "enterprisey" approach to structuring a project. Dependency injection, containers, service providers, those are all great approaches for professional projects, but they do require some commitment to learning these specific concepts. ProcessWire's approach to extension via hooking is almost the complete opposite of Laravel's container resolution approach. They're both flexible and ergonomic, but ProcessWire's a lot more approachable and easier to grok for newcomers I think. Being able to replace an internal handler in three lines without copy-pasting the whole class is really magical.1 point
-
@wbmnfktr was just a minute faster, but I feel exactly the same way: I have to say I am using ProcessWire exactly because it doesn't force me into a direction and/or into a form of "best practice". But nevertheless I think there is already a lot of controller in the ProcessWire core. What you @szabesz want I think is a way to create your own controller manifested as a class and tightly integrated in the request lifecycle. But can't you already do that? That is the beauty of ProcessWire. You can alter anything I can think of with hooks. They will allow you to create a fully-fledged controller system if you want to. But again, I feel like ProcessWire handles most of the controller stuff one would ever need.1 point
-
Hi all. Reading through the discussion about page classes, I have to add my two cents. I feel like we are mixing concepts here. We are talking about OOP concepts where the request arises to extend page classes' capabilities to better allow for separation of concerns. Many OOP concepts stem from or are just a fancy form of the MVC pattern. I strongly believe ProcessWire follows such a form too. Whereas the core handles MC and it's API provides endpoints for the V in Model-View-Controller and hooks for extending and altering the C part. So to really allow for separation of concerns, page classes aren't the right place to start off. A page is just the representation of an entity, a line in the database. Instances of said class that is. And thus Page and page classes belong to the Model part of ProcessWire. And this is exactly where my motivation to side with @ryan and his general scepticism of page class init and ready methods comes from. So it makes sense to add virtual properties or basic relationships to the page class. But the model should never contain business logic which acts outside of the lifecycle of the entity. Having made my point so far, I think Ryan's second to add a new class file to act as a controller (by using the ProcessWire's hooks) makes a lot of sense. And exactly that is why I believe, ProcessWire already offers a very good way to enforce MVC patterns and true separation of concerns. It offers a good API without forcing everyone to use the same architectural patterns so many other systems do.1 point
-
@ryanThank you very much for the code examples you provided for possible hook options related to PageClasses. Personally like the idea of including a page related hook file following the naming convention concept of PageClasses like PageNameHook.php. Will try some of those concepts soon in a real world project I am working on right now.1 point
-
@Jonathan Lahijani I'd need specific examples to respond to or questions to answer. This is a fully built out profile. I think some might expect that I would classify/objectify everything, but I don't do that unless there's a strong reason for doing so. I use classes when there's an OO reason for doing so, and rarely is "group of related functions" one of those reasons, unless for sharing and extending. Using custom page classes or OOP is not at all necessary for most installations. It's only when you get into building larger applications that you might benefit from these things. And even then, it's not technically necessary. One good reason to use custom Page classes is just to have a documented or enforceable type, with no need to have any code in the actual class: /** * @property string $title * @property float $price * @property PageArray|CategoryPage[] $categories * @property string $body * @property Pageimages $photos */ class ProductPage extends Page {} If you add something to the class, it might be to add an API for the type's content that reduces the redundant code you'd need when outputting it. class ProductPage extends Page { /** * Get featured photo for product * * @return Pageimage|null * */ public function featuredPhoto() { $photos = $this->photos; if($photos->count()) return $photos->first(); foreach($this->categories as $category) { $photo = $category->photos->first(); if($photo) break; } return $photo; } } I'd like that too. Maybe "buy" is a longer term goal, but shorter term I'd be interested in suggestions for how best to help promote others modules. @bernhard There's no need to use OOP in ProcessWire, especially for someone new to it. ProcessWire does all the work to make sure that by the time your template file is called, you are output ready. So it's only once you get to be more advanced that you might then start using hooks, and you might never use OOP. If someone wants to add a hook, the most reliable place for that is the /site/ready.php file, or in some file that you include from it (conditionally or otherwise), and that's what I'd recommend. ProcessWire wouldn't even load your ProductPage.php file if no instance was created. But even if it did, why would there be a need for any hooks related to page class "ProductPage" if no page of the type is ever loaded? Maybe I'm missing something. You already know I'm skeptical of hooks being added by Page objects, but now we're talking about hooks that aren't even related to the page class being within it? ? If there are, they still wouldn't be called unless something triggered PW to load the ProductPage.php file. And the primarily reason it would load the file is to create an instance of the class. That makes sense. For most I'd suggest this: $wire->addHook('Pages::saveReady(template=product)', function($e) { // ... }); Or this if you are using custom page classes, and want to capture ProductPage and any other types that inherit from it: $wire->addHook('Pages::saveReady(<ProductPage>)', function($e) { // ... }); If conditional for the requested $page, then wrap the call in an if() if($page->template->name === 'product') { $wire->addHook(...); } If you need to hook the same method for multiple types, it can be more efficient to capture them all with one hook. Maybe you want it to call a saveReady() method on any custom Page classes that have added it. Since you wanted hook type code in the Page class, here's how you could do it without having hooks going into the Page class: $pages->addHook('saveReady', function($e) { $page = $e->arguments(0); if(method_exists($page, 'saveReady') $page->saveReady(); }); Rather than more initialization methods, if you needed hook-related implementation in the custom Page class, the above is the sort of thing that I think would be better. At this point, it's only about being "ready to save THIS instance of the page" which I'd have no concerns about. I could even see the core supporting this so that you could just add a saveReady() or saved() method to the custom Page class, and neither you or the core would even need to use hooks. But back to hooks, if you don't want to load up your /site/ready.php with code, maybe just use ready.php as the gatekeeper and organize them how you want. If you only need hooks for the admin, maybe put them in /site/templates/admin.php. If you want to maintain groups of hooks dedicated one type or another, put them in another file that you include from your ready.php file: include('./hooks/product.php'); I understand you like to maintain these things in or alongside your Page class files. Your MyCustomPage.php class file is one that might be suitable because those hooks won't get added unless an instance of the class is created, or something does a class_exists('ProcessWire\ProductPage'). I think you did something like the following in an earlier example, and it's just fine because it's independent of any instance and doesn't add pointers into any specific instance, and will only ever get added once: class ProductPage extends Page {} $wire->addHook(...); Or maybe you want the hooks in a separate related but dedicated file. It would have the same benefits as the previous example, but isolated to a separate file: class ProductPage extends Page { public function wired() { require_once(__DIR__ . '/ProductPageHooks.php'); parent::wired(); } } Maybe you want to do it for all classes that extend BasePage.php. Or you could use a trait, but here's an example using inheritance: // site/classes/BasePage.php class BasePage extends Page { public function wired() { parent::wired(); $f = __DIR__ . '/' . $this->className() . 'Hooks.php'; if(file_exists($f)) require_once($f); } } // /site/classes/ProductPage.php class ProductPage extends BasePage {} The word "trivial" means "of little value or importance" and I wouldn't agree with that classification of these files. But I think you might (?) mean that it's really "basic/simple" (which is meaning I think of sometimes too), and that's actually the goal of it, so I would agree with that classification.1 point
-
An approach I sometimes use is the following. It seems to work quite well and is fairly clean: Put all your class-specific hooks in your page class, let's say in a ready() function (can be named anything of course, but ready() is a good convention for me). In /site/ready.php, just instantiate a single instance of the page class and call its ready() method. So, if we have let's say a NewsarticlePage class and we want to keep all news article related hooks together, we might have something like this in the page class: <?php namespace ProcessWire; class NewsarticlePage extends DefaultPage { public function ready() { $this->addHook('ProcessPageEdit::buildForm', $this, 'addImportOptions'); $this->addHookAfter("Pages::saved(template=newsarticle)", $this, 'processAfterSaveActions'); $this->addHookAfter("Process::execute", $this, 'processAfterExecuteActions'); } And in site/ready.php: <?php namespace ProcessWire; //required to trigger ready hooks in custom page classes: (new NewsarticlePage())->ready(); (new SomethingElsePage())->ready(); //etc... You can instantiate one empty page object for each Page class you need to run hooks for. There's some overhead, but not much, and it keeps your site/ready.php clean and your hooks where they make sense. Of course you still have to make sure the hooks only target the desired pages/templates. Inspired by some of @bernhard's earlier posts on the subject.1 point
-
1 point
-
RockFrontend loads uikit.theme.less and default.less in /site/templates/_init.php via $rockfrontend->styles() Probably from installing the UiKit profile? I commented it all out and now it's fine. Took me long enough... sometimes you just have to wait a day or two and have a nice cup of tea(like the British do) ?1 point
-
I just implemented this inside a autoload module and discovered that this hook only works in application ready state. So if you are utilizing this inside a module, you need to call the hook inside ready() method like this public function init() { // handle render of correct page from urlSegements $this->addHookAfter('ProcessPageView::execute', $this, 'hookPageView'); } public function ready() { // need to call this in ready. Not working in init() $this->pages->addHookAfter('Page::path', $this, 'hookPagePath'); } public function hookPagePath(HookEvent $event) { $page = $event->object; // page ROW and all children recursively if ($page->id == 1043 || $page->rootParent->id != 1043) return; $orgPath = $event->return; $pathSegments = explode('/', trim($orgPath, '/')); // $pathSegments[0] is language segment // get rid of $pathSegments[1] 'row' unset($pathSegments[1]); $newPath = '/' . implode('/', $pathSegments) . '/'; $event->return = str_replace('//', '/', $newPath); } public function hookPageView(HookEvent $event) { $page = $event->page; // only act on homepage if ($page->id != 1) return; // get last urlSegment to retieve page with that name if (count(input()->urlSegments())) { $wantedName = sanitizer()->pageName(input()->urlSegmentLast); $wantedPage = pages()->get("name={$wantedName}"); if ($wantedPage && $wantedPage->id) { $event->return = $wantedPage->render(); } else { throw new Wire404Exception(); } } } If knew this earlier it would have saved me some time and frustration...1 point