Jump to content

Kiwi Chris

  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by Kiwi Chris

  1. I think this could work both ways. One of the things I really like is that it's possible to use the admin UI to design your fields and pages, but RockMigrations then gives you the code generated to copy and paste into your migrations file. If you start prototyping using the UI, and intended to add it to a migration but forgot to, having an indication that a field or template isn't included in a migration is just as useful as indicating that it is. This would be particularly useful when adding RockMigrations to an existing site, as it makes it easier to see quickly what has been see up to be managed by migrations and what hasn't been.
  2. Something like? $database->exec('ALTER TABLE pages AUTO_INCREMENT = 1');
  3. This looks great. I'd been considering building something similar myself as I have a need for it. I do have a need for it to integrate with an existing site, but from the looks of the latest Rock Migrations, there's an easy way to get the configuration of fields and templates to paste them into a migrations file, and that's something else I've been meaning to have a play with, so I might set up a local version of this profile, install Rock Migrations, and see if I can build a migration that allows me to apply this to an existing site.
  4. @kixe Your fork of the module doesn't allow issue reports on Github, so I'll mention it here. There is a hook into AdminRestrictBranch module if present to automatically restrict the page tree to the root of the domain in multisite mode. if ($this->wire('modules')->isInstalled('AdminRestrictBranch')) { if (method_exists('AdminRestrictBranch', '___getBranchRootParentId')) { $this->addHookAfter('AdminRestrictBranch::getBranchRootParentId', function ($e) { $e->return = $this->rootPageID; }); } else $this->warning('AdminRestrictBranch::getBranchRootParentId() is not hookable'); } Where this has an issue is that if a user is only supposed to have access to page tree belonging to domain A as defined in AdminRestrictBranch, and then logs in to domain B, the branch restriction defined in their user profile or role is overridden by the hook in multisite. This means if any user knows other domains under the same installation of ProcessWire using Multisite, they can log in and access the page tree of those domains, even if AdminRestrictBranch is configured to otherwise prevent them from accessing them. A quick fix is to comment out the hook code. A better fix would be to check whether a user or role already has branch restrictions in place defined by AdminRestrictBranch, and if so, defer to those restrictions, but if not, provide default behaviour as exists of restricting to the root of the domain.
  5. Oops! Sorry @adrian I just realised I got my module mentions back to front. I'm using your 'official' version of AdminRestrictBranch, and the Multisite version by @kixe There does seem to be some interaction going on between them that's causing unexpected results. It's not necessarily a fault with AdminRestrictBranch, it looks like an issue with Multisite module as it hooks AdminRestrictBranch::getBranchRootParentId , but it's still worth mentioning here in case someone else runs into the same problem, so that they're aware of potential issues using the two modules together. I found an easy fix was just to comment out the hook code in the Multisite Module.
  6. I'm not sure whether it's an issue with the current version of the core (3.0.203), or some other interaction, but currently I'm getting a weird issue. All users, regardless of what branch they're restricted to, are being restricted to the same branch. ie branch restriction is happening, but regardless of what branch is specified, they all get the same branch. [edit] I seem to have found the source of the problem. It is an interaction between Multisite module and @kixe version ofAdminRestrictBranch. What seems to be happening, is that when a user logs in, they will get the full page tree of whatever domain they have logged in under, regardless of how AdminRestrictBranch is configured. In some ways that's desirable: log in under a domain, and only get that domain's page tree, but it's also a security issue, as if a user knows another domain in the same multisite setup, and logs in with the login that's supposedly restricted to the page tree for another domain, they can see the page tree of the other domain.
  7. Thanks for sharing an interesting use of comments. I think I would find the hook code useful as I have FormBuilder and I can think of scenarios where I could use this. As a matter of interest, if you want to aggregate meta data from all comments and get an average rating for a given piece of meta data, what's the most efficient way to achieve this?
  8. The ProFields Combo field and Table fields create SQL tables behind the scenes, but they're still fieldtypes, so are expected to be added to a ProcessWire template and are linked to the page tree. Sometimes that's not necessary or desirable. With regards to creating custom tables, I'm quite happy writing SQL statements for this, or using the generated CREATE TABLE statements with a database export from mySQL, or for that matter even other dialects of SQL, with a bit of editing if necessary. It's not hard to write a CREATE TABLE statement initially, then an ALTER TABLE statement if subsequent changes are needed. I think this would play nice with your RockMigrations module to generate SQL schema changes in code, and I don't want to turn ProcessWire into mySQLAdmin or Adminer which is installed with Tracy Debugger, but it would be nice to have an end user friendly UI to view and edit custom SQL tables in the ProcessWire admin. You have made me thing of something I hadn't considered, about how to migrate SQL listers and editing forms, if the InputField settings or fields to display in a lister change, but if they're accessible via the API, it should be possible to manage migrations in a similar way to ProcessWire native fields and templates.
  9. @ryanFieldtypeCombo comes pretty close, but like you say, you define the table structure with the fieldtype. Also as a fieldtype it needs to be associated with a template, that links into the ProcessWire page tree, which isn't always desirable with SQL tables from an existing database. I'm thinking there would probably need to be two configurable Process modules. An ProcessSQLLister and ProcessSQLForm module. Names are just suggestions ProcessSQLTemplate could be another option however as it's not an output template, it's an admin UI for editing arbitrary SQL data. ProcessSQLLister would be similar to Lister Pro, except for selecting a source, you'd select an SQL table, then choose what fields from the table to display in the lister. Dealing with lookup fields which are similar to page reference fields, but can refer to an arbitrary database table would probably be the biggest challenge, but the basic lister should be pretty straightforward. Edit functionality would depend on a related ProcessSQLForm being defined for the specified table. ProcessSQLForm would involve picking an SQL table, then selecting fields from the table to include on the form in the order desired, and mapping and configuring a sane InputField type depending on the SQL field type. @kixe has already made FieldtypeSelectExtOption which can handle lookups from arbitrary SQL tables, so that InputField should be able to handle relational reference fields, and core InputFields should be able to map to other SQL fields types. For both, access control at the table level would be desirable. While access control at the field level would be technically possible, I don't think it's necessary at least initially, especially if it adds complication since the fields are SQL fields rather than ProcessWire fields. I can try to mock something up, but if someone else beats me to it, then feel free to go ahead. I think ProcessWire has all the nuts and bolts to do this, it's just a case of putting them together.
  10. There weren't very many CMS/CMF platforms either. I started out with SSIs to start reducing redundancy and duplication, then ended up starting my own CMS around 2000, but I picked a loser in terms of development language, and I realised trying to maintain a CMS for a modest number of clients on my own wasn't really efficient use of time. Someone introduced me to ProcessWire in 2015, and since then nearly all my websites have been converted to it. Web development and database development have progressed together for me, so ProcessWire's separation of content and presentation, and strong access control are critical for me. I evaluated my other CMS platforms before I settled on ProcessWire and I simply didn't like them as they either had a steep learning curve or were too output focused or both. I wouldn't use Word to try to build a relational database, nor would I use WordPress. I think if there is one major thing still on my wish list, it would be the ability to have a UI using ProcessWire inputfields to create data entry forms for arbitrary SQL tables. A common scenario for me is converting offline databases (often Microsoft Access) to cloud based alternatives. Usually it's possible to restructure everything within ProcessWire's pages model, but sometimes I just want to be able to dump the data across and build a UI quickly with no need for data to exist within a page model. I've been playing around a bit looking at building module(s). I'd love the goodness of Lister/(Pro), but instead of picking a template, pick an arbitrary SQL table and specify fields from it, set access control etc in the same way Lister Pro woks, and then have I guess what I'd call an SQLTemplate where you'd pick an arbitrary SQL table, select fields from it, and for each one specify an inputfield, within the contraints of the SQL field type. Of course none of this data would be accessible within ProcessWire's page structure out of the box, however there's already $database->query() to execute an arbitrary SQL query and return a result set, so using arbitrary SQL data within templates is already easy, so the only bit missing is a UI to manage arbitrary SQL tables as easily as ProcessWire pages in admin, but it's already halfway there with inputfields that don't care where their data comes from.
  11. There is an optional module in the core ProcessForgotPassword that you can install to enable people to reset their passwords if they forget. With regard to preventing even super-user role from changing any password other than their own, I think it could be done, but would require a hook in site/ready.php I'd imagine adding a hook before InputfieldPassword::processInput should be able to check the current user, and if they're not the same user as the password belongs to, then abandon any changes. I may not have the right hook method. A hook before Pages::save might be another option, as everything including users are 'pages' in Processwire, so the logic would be something like if($user->name != $page->name && $page->template == 'user'){ //Prevent page saving. } Someone else can probably help give a working example, or if I get time I can have a try and update my post once I've got something working.
  12. In case anyone else finds it helpful, I've been having major issues with both the original deprecated and later version of the module described in this thread not working properly with the latest builds of ProcessWire (>=3.0.200) and it seems like this module hasn't had much love in a long time, but after poking around on Github, I found a fork by @kixe that works for me. https://github.com/kixe/Multisite/blob/master/Multisite.module
  13. Interesting discussion, and I'll add a rather ironic perspective. I inherited a largely non-functional website project that someone else had built in Craft, about 3 years ago, and at the time I found the Craft documentation wasn't particularly clear, whereas I worked out how to use ProcessWire after about 20 minutes of reading the documentation. I converted the whole project to ProcessWire, and actually got the project functional. I had to write several custom modules and deal with a lot of hooks and set up CRON jobs to interact with a third party API, and I found ProcessWire a pleasure to work with. That said, I can understand that there are pain points for some people with ProcessWire, and it's always good to look at other systems to see how they do things in case there's something useful that could be incorporated into ProcessWire. My personal preference other than ProcessWire is Umbraco, which is built on ASP.Net rather than PHP, but in many respects is similar, so I don't have a problem jumping between PHP for ProcessWire and Razor syntax and C# for Umbraco. It also is an open source project, but with commercial add-ons like a form builder (which makes ProcessWire FormBuilder look cheap). Now that .Net and SQL Server run on Linux, it's potentially even more appealing to me, although ProcessWire is still my first choice. Currently I'm a solo developer, but as my workload grows, and also clients are starting to ask for an insurance policy in case something happens to me, the potential to be able to manage collaboration on projects is something that's increasingly on my mind, and out of the box, this isn't something that ProcessWire handles, although there are third party solutions like RockMigrations by@bernhard
  14. It is possible to use pre-built themes with ProcessWire, but since you can't be sure in advance what fields someone will create, rather than building a ProcessWire specific theme, any well documented HTML theme should be easy to adapt to ProcessWire with not much effort. Mostly I think people build sites from scratch, but I did have someone once who wanted to use a theme, and had a limited budget, so it was actually quicker and cheaper to adapt an off-the-shelf HTML theme for them than build from scratch.
  15. How about something like this? This way your editor can recognise the HTML tags as well as the PHP tags. The <?= ?> tag is a PHP shorthand for echo ... that you can insert within HTML. For PHP logic you need the full <?php ... ?> tag. You'll notice I've left a couple of echo statements in because they're short, and it's not really worth closing the PHP tag and opening another one for such short sections of HTML code. <div class="row mb-2"> <?php $items = $pages->find("homepage_item=1"); foreach($items as $item) { // $item === $pages->get($item->id); ?> <div class='col-md-6'> <div class='row g-0 border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative'> <div class='col p-4 d-flex flex-column position-static'> <h3 class='mb-0'><?= $item->title?></h3> <?php if($item->arbitrary_publish_date) { echo "<div class='mb-1 text-muted'>$item->arbitrary_publish_date</div>"; } else { echo "<div class='mb-1 text-muted'></div>"; } ?> <p class='card-text mb-auto'><?= $item->summary ?></p> <a href='<?= $item->url ?>' class='stretched-link'>Continue reading</a> </div> <div class='col-auto d-none d-lg-block'> <svg class='bd-placeholder-img' width='200' height='250' xmlns='http://www.w3.org/2000/svg' role='img' aria-label='Placeholder: Thumbnail' preserveAspectRatio='xMidYMid slice' focusable='false'><title>Placeholder</title><rect width='100%' height='100%' fill='#55595c'/><text x='50%' y='50%' fill='#eceeef' dy='.3em'>Check it out!</text></svg> </div> </div> </div> <?php // echo $item->title; } ?> </div>
  16. That's exactly how migrations files work with Entity Framework in .Net, but you've got to write that manually. I'm OK with that as it's not much to write. For new, changed, or deleted fields, it builds the migration automatically from the current definition of system state based on what's changed. That's exactly what I'd want. The main situation in ProcessWire where tracking data can be useful is with pages used as input for list items. I think I want both; a full description of system state that can be used to install a new instance of a given configuration, but also migrations so that an existing installation can be synchronised with a specific state. Maybe it's not the best approach, but that's similar to how Entity Framework on .Net works, and I work with that as well, so having a similar workflow to something I'm already using would keep things simple, but I understand there may be other solutions that are more efficient for other people. One of the key points for me as well, is I want to be able to do this at the module level, in addition to or instead of the site level.
  17. Some people are wanting continuous upgrades to complete sites, but the kind of scenario I'm facing for the first time, is potentially identical, simultaneous upgrades required to multiple sites with different data, but on an extensible modular level. I've been thinking along the lines of having a method to build a full state, but whenever any objects in that state change, having some way to track what's changed since the last build. Building the full state looks to be relatively easy; specify what fields, templates, and pages are required, and in what order to satisfy dependencies, and then dump JSON files with definitions of all the objects required. Handling changes since the initial build in a reversible way is more of a challenge. I think if I did want reproducible upgrades to whole sites, that would be easily achievable by simply specifying the module dependencies in a configuration file, as they would encapsulate all the fields, templates, and pages required for a given site configuration, I'm moving towards the idea that everything other than the core would basically end up being a module, which in some cases may be responsible for nothing more than maintaining a set of fields templates, and possibly pages (eg for lists) for a specific task. Existing module dependency capabilities mean I can handle if a module depends on existing fields, as I can simply make it depend on the module that installs and maintains those fields. EG, module 1 installs a base set of fields, templates and pages. Module 2 requires some of the object data installed by module 1 but extends on that with additional functionality including its own fields, templates, and possibly pages. Module 3 also requires data from module 1 and extends on it in a different way. All sites will have module 1, but will have either module 2 or 3 but not both. I don't want or need to migrate an entire site, as that would get too messy if I start deploying a number of similar sites, but each with unique user data and sub-components. I still want to be able to use the UI though for rapid prototyping, and then build a deployment configuration once I've tested things out. Obviously changing things via the UI doesn't automatically add dependencies to a module, but that's fairly insignificant to achieve. Microsoft's Entity Framework Core specifically has an issue with this. It can generate automatic migrations with schema changes, but a renamed field or class results in a drop and create, rather than a rename, and their documentation recommends manually editing auto-generated migrations to deal with this. Obviously this problem isn't unique to ProcessWire by any means. ? The way things work there, is class definitions are complete, self-contained defintions of the schema, but separate migration files handle getting to that state if the current schema doesn't match the class definitions. Although .Net is a different platform, I wonder whether the way Entity Framework handles migrations could provide some insight into how to build a workable system for ProcessWire?
  18. I posted over in this thread how to get a JSON definition of each required field, template, and page, using core functions, but that doesn't resolve knowing whether a change has been made. I wonder if it would be possible to store a hashed list of the state of objects at a particular build? A hash might be more useful than a timestamp in a collaborative environment, as what got modified rather than when it got modified is probably more relevant. It should be possible to iterate over the list of objects, compare hashes and build a migration file containing a list of those objects that have changed since the last build. This will not solve all scenarios, but could be a good start. Entity Framework in .Net Core from Microsoft does something like this, and the documentation specifically states that the migration file will need manual editing for some scenarios, specifically if a field has been renamed, as the migration will include code to drop the original field and create a new one, rather than code to rename the existing field, which would obviously result in data loss. If Microsoft can't figure out how to do fully automated migrations with all their resources, then it's obviously a significant challenge, however I like the idea of having automation to produce a migration file that is a starting point which in simple cases may be usable as is, but in more complex cases, at least reduces the amount of code that needs to be written manually.
  19. The concept of RockMigrations makes a lot of sense, but what seemed to make it hard, was it depended on manually building object definitions for migrations in code. It turns out there are ProcessWire core methods to export field, template, and page definitions as JSON, so that makes it a lot less code to write. Where I'd like to get to is have a list of field, template, and page dependencies in a module configuration, and be able to do something like $module->build(); to generate JSON files for all those dependencies in the module directory. Modules already have install() , uninstall() and upgrade() methods so they could look for any object dependencies in the module config and create (or remove) them as required. Here's a working proof of concept I've been playing with in Tracy console. Although I prefer to use the UI when I can, due to the issues around dependencies between fields, templates, and pages, manually specifying an array with the objects in the order they need to be created avoids the issues others have run into of having to make multiple passes to satisfy all dependencies. I could make it smarter by checking the modified timestamp for templates and pages (and hopefully soon fields if Ryan adds it to the core), to only generate new JSON files for objects that have changed since the last build. $requiredObjects = array( 'competitionImage' => 'field', 'compGrade' => 'field', 'competition' => 'template', 'compId' => 'field', 'competitionCalendar' =>'template', 'competitiontopics' => 'page', 'media' => 'page', ); $modulePath = $config->path('MyModule'); $pageExporter = new PagesExportImport(); foreach($requiredObjects as $objectName => $objectType){ switch($objectType) { case 'field': $object = $fields->get($objectName); break; case 'template': $object = $templates->get($objectName); break; case 'page': $object = $pages->find("name={$objectName}, include=hidden"); break; } if($object){ $file = $modulePath . "data/{$objectType}s/". $objectName . '.json'; if($objectType != 'page'){ $data = wireEncodeJSON($object->getExportData(),true,true); }else{ $data = $pageExporter->exportJSON($object); } file_put_contents($file, $data); }else{ //Object doesn't exist! echo $objectName; } }
  20. I've sometimes had this kind of issue when I intended to assign something to a variable to output later, and instead output it with an echo statement. Also HTML code in a template will immediately render instead of being assigned to a PHP variable if you don't use PHP output buffering. Check the source code of the output.
  21. Tracy was useful in testing out what I'm trying to achieve. I'm trying to get away from copying and pasting though. I used the Tracy console, and this code is on the track of what I want: $modulePath = $config->path('MyModule'); //moduleFields is an array of field names foreach($moduleFields as $fieldname){ $testField = $fields->get($fieldname); $data = wireEncodeJSON($testField->getExportData(),true,true); $file = $modulePath . 'data/fields/'. $fieldname . '.json'; file_put_contents($file, $data); } This gives me a nice directory of field definitions that are required by a given module. ProcessWire already handles module dependencies including module versions with the requires property in getModuleInfo(), so if I define fields that are used in multiple places in a base module and specify that as a dependency of other modules that install other fields, then I can make sure I end up with all the fields that I need. Because I'm using a manually created array of field names, if there are fields that depend on other fields, I can list them in the right order to satisfy dependencies. Fields like page reference fields can depend on a template as well, so my array might need to specify both object name and type to install all the dependencies in the correct order, but I think I'm on track to being able to build a reproducible configuration I can easily deploy to multiple sites. I think it might not be too hard to build and admin module to provide a UI to build the dependency configuration files for custom modules either, as ProcessWire already supports adding and reordering items in lists in various Process modules. Edit: The reason I'm outputting one JSON file per object rather than just one big JSON file as the built in exporter gives you if you select multiple fields, is that I think it will be better for source version control, especially if a modified timestamp property is implemented for fields, and if there's a need for multiple collaborators on a project. Unmodified object definitions don't need to be regenerated. Additional Edit: Usually a module provides some kind of functionality, but there's no reason why a module can't just exist to install/uninstall a bunch of fields and templates, and otherwise just sit dormant. If it's not an autoload module, it's not going to do anything unless it's called from somewhere, and a module seems like a good way to encapsulate a whole lot of stuff. With the right design around dependencies and inheritance, it should be possible to change 'skins' or 'themes' for a site; something that's not possible with site profiles, as they're basically just a dump of a specific site state. eg, you could have baseModule that installs xyz fields and templates, then themeModule1 and themeModule2 that each provide different front end presentation, but depend on baseModule, so there can be certainty that all the fields they need exist.
  22. I've found what seems to be an undocumented method of the Field class that's used by the built in field import/export that I think could be useful in automation. $field->getExportData() returns details of the object, but needs a little bit more work to turn into a JSON object, but builtin ProcessFieldExportImport shows how to do that. There's a corresponding $template->getExportData() method. I tried this: $testField = $fields->get('headerImage'); echo wireEncodeJSON($testField->getExportData(),true,true); and I got a nice JSON object with the field definition in return. I'm lazy, and forgetful, so I like using the admin UI to build my fields and templates, because it reminds me of all the properties of a field and what they do, right there on screen. Because I'm forgetful, where the UI gets a bit less useful is exporting fields, as I've got to try to remember which ones I changed. Adding a modified property and sorting by this as I previously suggested would help, but if I want to deploy the same configuration to a bunch of sites, manual export/import isn't really scalable. With this, I can potentially be lazy and forgetful, as I don't care how a field is made, I can simply grab it's definition and write to a JSON file, but I don't have to try to remember what fields are required for specific functionality as I can simply provide an array with a list of fields (and templates) required in a module, and let it generate them from the JSON files. I think what would be useful at the core level would be proper documentation for these import/export methods that already exist, and maybe a wrapper function so that it's possible to get directly as JSON data rather than requiring an extra step. eg $field->getJsonData() or something like that. I'm sure these JSON files could also provide field and template definitions for Bernhard's RockMigrations.
  23. Templates have a modified property, but fields don't. This might be a useful and simple core feature to implement that could make it easier for anyone wanting to track changes. The Templates Export function shows the modified field, but it's sorted by template name. For quick manual exports, having the option to sort by modified timestamp would be an improvement. Once fields have a modified property, they also need to have the option to have the export function list them by modified timestamp. I see the base Wire class that everything else in the core extends has change tracking properties and methods, although currently there doesn't seem to be any built in method to enable persisting that with fields and templates when they're changed via the UI. Up to date, I haven't really required the sort of version control others are discussing, but I have a couple of sites now, where I'm looking at bundling up functionality as modules for automated deployment to other sites, and the manual exporting of fields and templates doesn't really cut it, but I've built my data structures via the UI, so having an efficient way to convert that to code that can be used for multiple deployments would be useful. With Visual Studio, I'm used to working with the option of using either visual designers or declarative code to build apps, and either way end up with code that can be included in version control.
  24. The JSON that this feature generates for import/export mostly works for me, however the issue is having to manually select fields/templates via the UI. I notice that templates include a timestamp for when they were changed in the data field of the templates table, but fields don't. If both did, then it should be possible to get fields and templates that have changed since the last build time of a module or template. I use the admin UI, and don't want to write more code than I have to. Specifying what fields and templates that a module depends on in code and letting the system pull a config file with the definition of those fields and templates from the database would be UI friendly, but not rely on having to remember what fields or templates are required for a specific purpose, but not require much code either. This is similar to a database first workflow I have with SQL Server and ASP.Net Core. I can reverse engineer any tables I want from SQL Server to get a class definition, so I don't need to worry if the definition of something was manipulated outside my code; I can always grab the current definition without having to write any code. For those who have a licensed copy of Padloper 1, it's interesting to see how it creates the fields and templates it needs. It appears to be using JSON files based on the field and template import/export feature, but has its own code to import them. With a timestamp and possibly a version number added to the data in the fields and templates table, I wonder if that would make a hybrid UI/code based update model easier to work with? Of course for more complex migrations, RM is more capable, but I wonder if even there, it can grab the field and template definitions if they're exported as JSON?
  25. This is potentially progress, as it suggests ProcessWire is at least being given control. ProcessWire throws an internal server error instead of displaying a message if something went wrong. Maybe check site/logs/errors.txt or exceptions.txt also, if you haven't already, in site/config.php add $config->debug = true; as that should display errors.
  • Create New...