Jump to content

ESRCH

Members
  • Posts

    80
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by ESRCH

  1. Really nice site. I'm actually really impressed at the speed with which the pages load, considering the large number of images in the site. I am browsing on my phone, and the pages switch instantaneously, it's amazing. I imagine that you are using Pro Cache? Do you have other tips on how you achieved such speed?
  2. Sorting by subfields is now supported (see https://github.com/ryancramerdesign/ProcessWire/pull/862). It was my first contribution, so I'm pretty proud
  3. Let's say you have two users with the following sets of programs (for different weeks for example): - User 1: Program 1 (Week 1), Program 3 (Week 2), Program 7 (Week 3) - User 2: Program 3(Week 1), Program 4 (Week 2), Program 1 (Week 3) Now on the front-end, you need to show him his program by week: "Dear User 1, Here is your weekly program for the next month: Week #1: Program 1 Week #2: Program 3 Week #3: Program 7" Well, by defining the link to the user on the program template, you can't define in which order the programs can be sorted for a specific user, since the only selector you could use would be: $programs = $pages->find("template=program, user=$user, sort=??"); But we might be going a little off-topic here and mixing up Christophe
  4. If there is a clash between the modules, you might also want to try prioritizing the hooks, to see whether it makes any difference.
  5. That is more difficult, and I would argue that it isn't necessary. The notice that a value is missing is a useful reminder, even if you are not yet publishing the page.
  6. I like this kind of discussion Separating the fitness programs is a good idea, especially if they are reusable (can be attributed to different users). However, the problem with including a "user" field in the fitness-program template rather than a fitness_program field in the user template, is that it isn't possible to control the order in which the programs appear. The only available sorting mechanism would be from oldest to newest (or the opposite) by sorting by id. If the coach decides at some point that he wants to reuse the fitness programs, he can't set the order of the programs per user. So I would argue in favor of having a fitness_program field in the "user" template
  7. Yes, that's an interesting approach, and very flexible. A concrete way of doing this could be to create a fitness-program template, with a title field, a videos multi-page field and a description textarea field. You can then create a PageTable field called fitness_programs that uses that fitness-program template, and add it to the user template. This way, the coach can create for example weekly or monthly programs by adding a fitness program to a user like this: Title: Week #1 Videos: Video 1, Video 4, Video 5 Description: Do 5 times: Crunches 20x Push-ups 15x Chin-ups 12x
  8. @mr-fan, Indeed, ProcessWire is quite unique in that you never feel that something is too difficult to do from the outset. I explored Drupal a little before, and there were many times when I was wondering how to approach a project. PW is very open and allows you to have a very consistent structure in your project (Fields > Templates > Pages). And the hook system is very well done to be able to expand the CMS when needed. I do love this CMS
  9. The user template and the profile page are not quite the same thing: The "user" template is basically similar to any other template in Processwire. In the same sense that you might have a "product" template with fields "reference", "title" and "price", you have a "user" template with fields "email", "pass" (for password) and "roles". You can see this template by going in Setup > Templates, then expanding "Filters" > "Show system templates?" and choosing "Yes". The "user" template then appears, and when you click on it, you can see that it has different fields, and that you can add fields to it (for example "selected_videos"). When editing a user (Access > Users), you can see all these fields and edit them. This is managed by the ProcessPageEdit module, which is the same as for all other pages. The profile page is a special page which shows only a few fields (e-mail and password) for the logged in user. This is managed by the ProcessProfile module. So in your case, you can simply add the "selected_videos" to the user template, so that the coach can attribute videos to each user.
  10. ESRCH

    My first PW site

    Hey, thanks for the code, that's really useful. And I understand your English perfectly! Developing a custom cart solution is pretty straightforward with the $session variable, otherwise you can also check Foxy Cart. I haven't used it myself, but I remember some people mentioning that they did and they seemed pretty happy with it.
  11. Hi doolin, I would suggest checking this post from Soma, which "corrects" ryan's original code for the custom login. Concerning the redirection after logging out, I am assuming that you are using the link in the admin area, right? Since the admin doesn't know about your custom login page, it can't redirect to it. You need to hook into the Session::logout function to force redirection to the right login page, for example with a module: class CustomLogout extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Custom Logout', 'summary' => 'Redirects to a custom login page after logout', 'singular' => true, 'autoload' => true ); } public function init() { $this->addHookAfter('Session::logout', function($event) { $this->session->redirect($this->pages->get('/login/')->url); }); } } Concerning the login page itself, it should remain accessible for non-admin users, since they need to access it to login. What you could simply do is make it non-editable by non-admin users by configuring the permissions for the login template (in the Access tab). Removing it from the page tree is somewhat of a hassle...
  12. Oooooh, I love this moment when you first think about the possible structure of a website, and all the great things you can do with it, it's awesome My take on a possible structure could be: Home -- My Program (only accessible to logged in users) ---- Video 1 (video template with a video_file field to store the video) ---- Video 2 ---- Video 3 ---- ... -- About -- Contact You can create a page field called selected_videos, that links to the video template, and that you add to the user template (Setup>Templates>Filters>Show system templates) so that the coach can select the videos he suggests for each user. Then at the beginning of the video template, you can have some code like this to make sure that a user can only see the selected videos: (Edit: I made a typo, so I corrected from $user->has to $user->is) if (!$user->is("selected_videos=$page")) $session->redirect($page->parent->url); To embed your video, here are some resources: https://processwire.com/talk/topic/4580-video-fieldtype/ https://processwire.com/talk/topic/7380-whats-your-favourite-video-embedder-and-why/ https://processwire.com/talk/topic/4956-addinguploading-audiovideo-files-to-pages-media-manager/?p=48085 https://processwire.com/talk/topic/4956-addinguploading-audiovideo-files-to-pages-media-manager/?p=48126 You might also be able to use the Comments Fieldtype and the Comments Manager (with recent updates here, here and here) so that clients can add some comments to the video and encourage each other. Anyway, take these suggestions as you wish. I just love thinking about how to structure a site
  13. I had forgotten about the $item->get('field1|field2') syntax, thanks for the reminder, it's really useful!
  14. Well the easiest way seems to simply use an else if: if ($item->price1) { echo "From euros {$item->price1}"; } else if ($item->price2) { echo "From euros {$item->price2}"; } else { echo 'please ask'; }
  15. ESRCH

    My first PW site

    Hi tuxy, Nice site! I really like the fun design, and I visited it both on my phone and my computer, and the experience is very smooth on both devices, well done! Initially, my reaction to the purchasing process was that it would be better to have a cart functionality, so that a client can add several items before buying. Then I noticed that you use PayPal as a cart solution, which makes purchasing both simple and fast. I didn't know that you could do that, it's a really useful tip, so thanks! I just wanted to mention that the "hier" link on this page doesn't lead anywhere, and that the "Privacy en Disclaimer" page is basically empty. Also, you have an "Andere" product category with a badge showing one item, but no items are visible in the category.
  16. I believe this is actually the default behaviour. If you don't set a required value and you click on "Publish", it will display a warning and not publish it. However, it will save the change.
  17. You can also use the following hook (inside a module): public function ready() { if (!$this->user->isSuperUser()) $this->addHookAfter('ProcessPageEdit::buildFormSettings', function($event) { $wrapper = $event->return; $pageName = $wrapper->get('_pw_page_name'); $event->return = $wrapper->remove($pageName); }); } As written, the module allows only a superuser to change the name, but using a custom permission would probably make more sense, e.g., if (!$user->hasPermission('page-edit-name')) { ... }
  18. The main difference is this: When creating, editing or deleting elements in a PageTable field, you are creating, editing and deleting independent pages, which appear in your page structure. Each element can be viewed, edited and deleted separately in the Page List. Since each element is a page, it can also appear as a result from a $pages->find() query. As the name implies, the PageTable field is simply a table of links to pages, and in this sense, it is very similar to a simple multi-page field. When creating, editing or deleting elements in a Profields Table, you are creating, editing and deleting rows in a table in the database. The elements can't be viewed, edited or deleted except through the owning page, and when querying, you get the owning page rather than the table row. In terms of efficiency, the Profield Table is better, since it allows for less queries/joins to get the different values. Generally speaking, Processwire stores the value of each field in a separate table, so you have a fields_question table, a fields_answer table, a fields_display table, etc. If you want to show all three fields for a page, the system will have to query three different tables to get the values. That's how things work for the PageTable field, since it creates normal pages. The Profields Table field on the other hand stores values for the different columns in a single table. So if you have a Profield Table field called questions with columns called "question", "answer" and "display", you will have a single table called fields_questions with columns called "question", "answer" and "display". When accessing the values of a row, it is more efficient, since you get all three values in the same query to the database. The Profield Table has however some drawbacks: The list of types you can use for the different columns is limited: you don't have a page field, or a file field for example. Since elements in a PageTable field are normal pages, you have access to all field types. The options on those fields (dependencies, visibility, etc.) are also limited. The queries that you can do are also more limited, since you can't query directly for table rows. As an example for the last point, let's say that you have a questionnaire with several questions. If you use a PageTable field called questions that references a question template (with topic, question, answer, display and include_in_email fields), you can count how many people answered that they had children like this: $pages->find("template=question, topic=children, answer=yes"); If you use a Profield Table, that won't work, since you can't search by question (@field.subfield selectors as presented here also don't work). In your case, I think that the best approach is to use PageTable fields as explained in my previous post.
  19. Hi, Here is what you can do to redirect the home page '/' to the French home page: Set page names for both languages for the home page ('en' for English, 'fr' for French) In the LanguageSupportPageNames settings, choose the option "No - Root URL performs a redirect to: /name/". When you go to the root url '/' it will redirect you to '/en/' Finally, create a module to hook into Session::redirect to force the redirection of the root url to the French translation as follows: public function init() { $this->session->addHookBefore("redirect", function($event) { if ($this->page->id == 1 && $event->arguments(0) == $this->page->localUrl('default')) { $event->arguments(0, $this->page->localUrl('fr')); } }); } The hook checks whether you are viewing the home page, and whether you are redirecting to the English url, and if so, it changes the url to the French url. This solves the problem of the home page. The problem remains if someone has saved a direct link to a page without a language prefix, e.g., '/about/', since this will still be redirected to '/en/about/'.
  20. Indeed, I hadn't read the original source code well enough. Then your approach makes sense indeed.
  21. Assuming that the structure of the fields is always the same (Question, Checkbox 1, Checkbox 2), I think that the approach depends on who defines the questions: the user (like a "create your own form" type of page) You (with a fixed set of questions that the user must answer on the page) In the first case, you could use the Profield Table, as suggested by nickie, or even simpler, a PageTable (which is not a Profield): You create a template called question, with the fields question_text (text field), question_answer (text field), display (checkbox field), include_in_email (checkbox field). Then you create a PageTable field questions, that uses this question template. Finally you add this questions field to the target template. This way, the user can add as many questions as he wishes on a page. The second case is more difficult. The "pure" way of doing it would be to create a field for each question's subquestion, i.e children_answer, children_display, children_email, pets_answer, pets_display, pets_email, etc. The problem is that this would create an enormous amount of fields, which becomes inefficient (see this post from Ryan). You could create your own compound Fieldtype to group the three subquestions in one field (see the Events Fieldtype/Inputfield as an example), but this would still require 50-80 different fields, which is a lot. I think that the approach that I would attempt is the following: Create a question template with fields question_text (text field, with visibility set to visible but not editable), answer_text (text field), display (checkbox field) and include_in_email (checkbox field). Create a questions PageTable field that uses this question template. Add the questions field to the target template (let's call it questionnaire). Write a module to hook after Pages::added, so that each time a questionnaire page is created, it adds the question pages under it. Here is an example of what I mean: // Inside a module public function init() { $this->addHookAfter("Pages::added", function($event) { // Activate the hook only if the added page is a questionnaire if ((string)$event->arguments(0)->template == "questionnaire" $this->hookAdded($event); }); } public function hookAdded($event) { $questionnaire = $event->arguments(0); // List of all your questions $questions = array( "Do you have children?", "Do you have pets?", "Do you have rabies?", // etc. ); foreach($questions as $q) { // Create a question page under the new questionnaire $p = new Page(); $p->template = "question"; $p->parent = $questionnaire; $p->question_text = $q; $p->save(); // Add the question page to the questions field of the questionnaire $questionnaire->questions->append($p); } // Save the questions field of the questionnaire $questionnaire->save("questions"); } You should also adjust the permissions for the question template so that a user can't delete them. Yet other approaches would be to create a custom Process module (see the Hello Process Module for an example), or to set up a custom front-end template to answer the questions instead of using the admin back-end.
  22. I think that you should use addHookAfter instead of addHook to be more explicit (the hook needs to run at the end, since it needs to modify the return value). Also, while the code is correct, the logic seems inverted to me: When I give a "permission", it means that I allow more than if I had not given it. In your code, it seems that receiving the 'page-edit-created-onlyassigned' permission restricts what you can do (i.e. you can only edit your own content). It would seem more intuitive to me to have a 'page-edit-all' permission, which would allow a role to edit all content, with the default behavior being more limiting. In this case, your code would look like this: public function init() { if(!$this->user->hasRole("superuser")) $this->addHookAfter("Page::editable", $this, "checkEditable"); } public function checkEditable($event) { $page = $event->object; if (!$this->user->hasPermission('page-edit-all') && $type->created_users_id != $this->user->id) { $event->return = false; } }
  23. I don't think that such drastic changes need to be operated, since it is already possible to create compound FieldTypes that group different values. An example of this is the Events Fieldtype/Inputfield created by Ryan to demonstrate how to create custom fieldtypes. The Date, Location and Notes of an event are stored as different columns in a single table, and could therefore be compared to the Component. What would be needed is a good way to create such compound fields in the admin section. As I understand, this is what the Table ProField does, though it is still a little limited, since you can't use page fields for example. But this would tend to indicate that the changes to be done would not be so drastic.
  24. I also completely agree with this. As a workaround, I put this hook in a general "utilities" module: $this->addHookAfter('ProcessPageEdit::buildFormView', function($event) { $process = $event->object; $tabId = "ProcessPageEditView"; $viewLink = $process->getTabs()[$tabId]; $viewLink = substr_replace($viewLink, " target='_blank'", 2, 0); $process->removeTab($tabId); $process->addTab($tabId, $viewLink); }); But it would be much better if this was the default behavior...
×
×
  • Create New...