Jump to content

kongondo

PW-Moderators
  • Posts

    7,379
  • Joined

  • Last visited

  • Days Won

    139

Posts posted by kongondo

  1. Hi all,

    I wanted to update you on the progress of the next MM as discussed from this post onwards. Here's a very short preview of the next MM.

    It is still very early days. Nothing is polished and things may change. My main focus is on the functionality although I spent a bit of time on the GUI. I have spent considerable time thinking about the conceptual design, especially for the API and I am quite pleased with that so far. 

    Before you ask, I don't know when this will be ready. It is not a small re-write. I do know that it won't be until after the summer though, that's for sure. Happy to get early feedback, thanks.

     

     

    • Like 6
  2. 2 hours ago, fruid said:

    Now there's unfortunately no possibility to have any structure in the MM

    @fruid,

    True. This is planned for the next version of MM (see this post). I'll post a demo of it here later today. There is no firm ETA for its release but it will be after summer most likely.

  3. 4 hours ago, fruid said:

    not sure if this has been asked before, is there a way to filter the media by the page that they are used on?

    Hi @fruid,

    Do you mean when viewing the media in Media Manager? If yes, that is not currently possible. What's your use case? I'll have a think about this.

  4. On 5/11/2023 at 1:50 PM, Boost said:

    Hei,

    Is it only me or the ProcessMediaManager by @kongondo doesn't install on the latest PW? I'm getting this error:


    1956687108_Screenshotfrom2023-05-1114-48-19.png.6415261326b0c1a0485ff5d0cad58830.png

    Hi @Boost,

    Are you able to install other modules by uploading their zip files? If not, I am thinking is a permissions issue in your system?

  5. 42 minutes ago, Roych said:

    Ohhh, with a lot of thinking, this is somehow working But not as expected 😉

    Is your issue resolved then? I see your edit as well but I am still confused.

  6. 44 minutes ago, Roych said:

    not realy working. The children are not native children of a page, they are made with MenuBuilder drag&drop option. I want those in my header main menu, but in my footer I only want to show the first row.

     

    That's exactly what I said wouldn't work 🙂. You cannot control non-native children. If the children are MB (drag and drop) children, they are always shown (unless you disable them in the backend using the disable menu item option).

    I don't understand what you mean by 'not really working'. A little more detail would help.

  7. @bernhard

    Very late comments here. I'd started watching but things got in the way and I didn't finish. I've just finished watching. 

    A-M-A-Z-I-N-G!

    Thoroughly enjoyed this one. Thanks for sharing and thanks for representing ProcessWire. It looks like a lot of thought went into the presentation. It was also interesting to hear about your background. I am guessing this perhaps explains why your work/modules are always so polished and of high quality!!  I suppose you don't get into a helicopter without meticulously checking everything works as it should 😀

    I liked the way you showed the basics first and gradually moved into the more advanced topics. I also liked the way you used git history.

    I have learnt some new things as well and my interest is piqued. I have never been a fun of PHP template engines but that latte stuff you showed got me really interested. That is a lot like 'modern-js' like you said! Have you noticed any performance issues with latte?

    I was also very impressed with ddev. I know you have mentioned it before but the 'docker' bit is what has put me off in the past. For some reason, docker was either slow on my machine (a Windows thing maybe?) or just wouldn't work. I am very curious about ddev now. Do you still use a Windows machine? How's ddev in terms of performance?

    Anyway, great stuff and thanks again for sharing!

     

    • Like 3
  8. Hi @Roych,

    4 hours ago, Roych said:

    I want to show only first level of my menu without any children

    There is no setting for this currently. 'include_children' applies to only to the 'real/natural ProcessWire children pages. For instance, if my ProcessWire page tree is as follows:

    Home
    	About
        	History
            Mission
            Team
    	Services
        Plans

    And your Menu Builder Menu is as follows (in the backend):

    Home
    About
    	Services

    If you use 'include_children', your rendered menu will display as follows:

    Home
    About
    	Services
        History
        Mission
        Team

    As you can see, 'include_children' will grab the 'real' children (ProcessWire pages) of 'About'  and display them in the menu. However, without 'include_children', your menu will be rendered as follows:

    Home
    About
    	Services

    You cannot programmatically disables 'Services' from not showing. I.e,, there is no option for you to get:

    Home
    About

    However, you can achieve what you want by using getMenuItems()

    You can have getMenuItems() return an object (WireArray). You can then use WireArray methods to remove children items from the WireArray. Finally, given that this is a single level menu, you can just loop through the filtered WireArray and display them in your markup. Example code (untested):

    <?php
    
    namespace ProcessWire;
    
    $menu = $modules -> get('MarkupMenuBuilder');
    // get the menu items for menu with ID 1030
    /** @var WireArray $menuItems */
    $menuItems = $menu->getMenuItems(1030);
    // OR, if passing options
    // $menuItems = $menu->getMenuItems(1030, 2, $options);
    // ------
    // grab top level menu items only
    // they do not have a parent, i.e. parent_id == 0
    /** @var WireArray $topLevelMenuItems */
    $topLevelMenuItems = $menuItems->find("parentID=0");// you could also use (destructive) filter
    
    $out = "<ul>";
    foreach($topLevelMenuItems as $topLevelMenuItem){
      $out .= "<li><a href='{$topLevelMenuItem->url}'>{$topLevelMenuItem->title}</a></li>";
    }
    $out .= "</ul>";

    Hope this helps.

  9. 12 hours ago, gebeer said:

    on multilang installs, when the title field is set to TextLanguage, MM pages that are creted for each image under Admin->Media Manager->Media Manager: image are published in the default language only. Other languages are disabled.

    Thanks for reporting @gebeer. Added to my TODO.

    • Like 1
  10. 8 hours ago, sodesign said:

    I'll be sure to check out ProcessDatabaseBackups! Can it handle individual parts of a site?

    You can cherry pick what tables to backup up, e.g. 'pages', 'field_body', 'field_images', 'templates', etc.

    8 hours ago, sodesign said:

    How do I add a MM page to the MM field using the API if the field is currently empty? 

    If the MM fields are empty you need to find the connection between the production 'usual pages' with MM fields and the corresponding staging 'usual pages' with MM fields. Given that you used an import, similar to above assumptions, their titles and names will (should) be identical, but their IDs will be different. Hence:

    Production

    A Usual Page -> exported to staging

    • Title: My Usual Page
    • Page ID: 1450
    • Name: my-usual-page
    • mm_field (WireArray of WireData where each WireData has a property id, i.e. $mmObject->id == 1234)

    Staging

    A Usual Page <- imported from production

    • Title: My Usual Page
    • Page ID: 1876
    • Name: my-usual-page
    • mm_field (WireArray of WireData BUT EMPTY -> SO NO values for mm_field)

    Production and Staging 'usual pages' are connected via 'names'. So...

    1. Staging: Use findRaw or Loop through imported staging pages. Save their names and IDs in an array.
    2. Staging: Prepare an OR (piped) selector string of $namesPipedSelectorString from #1
    3. Production: Use findRaw with $namesPipedSelectorString to find the ids, names and mm_fields values in the corresponding pages in production.
    4. Production: Prepare the IDs of the mm_fields in #3 as $idsOfMMPagesInMMFieldPipedSelectorString. If you use findRaw, this will be in the array column 'data'. These are the page IDs of the MM pages in production.
    5. Production: Use $idsOfMMPagesInMMFieldPipedSelectorString in a findRaw to get the names of the MM pages in production. Prepare these in an array of $namesOfMMPagesPipedSelectorString. d
    6. Staging: Use $namesOfMMPagesPipedSelectorString from #5 in a findRaw() to find the page IDs of the corresponding MM pages that were created when you imported from production. In other words, the MM pages in #5 and #6 are identical, expect for their page IDs.
    7. Production & Staging: Prepare an array that contains the names of the exported usual pages, the IDs of the imported usual pages (the ones with empty MM fields), the page IDs of the MM pages in #6.
    8. Your connection is complete. You now know the IDs of the MM pages and their corresponding usual pages where they need to be references in the MM fields.
    9. Staging: Loop through newly imported pages and use the array in #7 to populate the empty MM fields. I.e., in the loop, when you get to a page, e.g. 'my-usual-page', using the array in #7 find the page IDs of the corresponding MM pages. Use each of those to create a WireData object that you add to the WireArray mm_field. Pseudo code below (not tested):
    <?php
    
    namespace ProcessWire;
    
    $importedUsualPages = $pages->find("your-selector");
    
    $arrayOfConnections = [
      'my-usual-page' => [
        'id' => 1876,
        'imported_mm_pages_ids' => [2035, 2036, 2038, 2056]
      ]
    ];
    
    foreach($importedUsualPages as $importedUsualPage){
      $importedUsualPage->of(false);
      $mmField = new WireArray();
      $importedMMPagesIDs = $arrayOfConnections[$importedUsualPage->name];
      foreach($importedMMPagesIDs as $importedMMPageID){
        $mmFieldItem = new WireData();
        $mmFieldItem->id = $importedMMPageID;
        $mmFieldItem->type = 3;// 1-audio; 2-document; 3-image; 4-video
        // add MM item to WireArray
        $mmField->add($mmFieldItem);
      }
      // -----
      // populate mm_field of page
      $importedUsualPage->set('mm_field', $mmField);
      $importedUsualPage->save('mm_field');
    }

     

    Hope this helps. Let me know how it goes.

  11. Hi @alexm,

    3 hours ago, alexm said:

    I assume it's due to this rendering a customised page edit view

    That's correct. PadloperProcessRenderOrders renders the GUI. It has lots of hookable render methods. For instance, in demo-2, we hook into PadloperProcessRenderOrders::getSingleViewTableRow (line#29 ) to display the details of the 'customise' text field for the line item. The hookable methods are not yet documented (sorry). Please find them in that file and inject your markup using one of the hooks. Let me know how you get on.

    • Thanks 1
  12. 10 hours ago, sodesign said:

    I successfully imported the pages using the native Processwire Import/Export, but the media manager fields were empty. I think this is because the page IDs are different on the production site and the staging site.

    I think you are right. It sounds like the import for the media pages themselves (i.e. the media manager pages) worked. However, these were created as new pages using the template 'media-manager-image'. On the other hand, the 'usual' pages with FieldtypeMediaManager field perhaps also got their values imported. One of the values they hold is the page ID of the page where the media (in this case image) really lives. So, in the production site one value could be 1234. However, the newly created page in the staging could have been created with a page ID 5623.  This means that if by coincidence some IDs are identical between the sites, you might get MM images showing up in the wrong pages 😀.  

     

    Back to your script.

    You need to find a connection between production 'media manager pages' (i.e. the pages that use the template media-manager-image) and the staging usual pages media manager fields. The connection between them that has not changed is the page name of the media manager pages, i.e.

    Production

    MM Page

    • Title: My Awesome Image
    • Page ID: 1234
    • Name: my-awesome-image

    Page with MM Field

    • A Frontend Page with a Gallery showing some MM Images in an MM Field
    • MM Field (WireArray of WireData where each WireData has a property id, i.e. $mmObject->id == 1234) [see the docs].

    Staging

    MM Page

    • Title: My Awesome Image
    • Page ID: 5623
    • Name: my-awesome-image

    Page with MM Field

    • A Frontend Page with a Gallery showing some MM Images in an MM Field
    • MM Field (WireArray of WireData where each WireData has a property id, i.e. $mmObject->id == 1234) <- it points to the old value in the production site.

    As you can see, the common things between the two sties is the name/title. 

    One (rather convoluted way) to go about it is (written in browser, not tested and only quickly thought through).

    1. Get the values of the $mmObject->id in your 'new pages [the imports]', i.e., the value 1234 in our example. You could loop through each of the staging pages or just grab them all using findRaw("template=your-template",['id','mm_field']);
    2. Process the the above array to get all the 'data' values in the 'mm_field'. Keep this one one array.
    3. Use the ids you have collected in #2 and do a findRaw in the production site (implode the IDs so you get 1234|1345|4356, etc). What you want are the names, so findRaw("id=$ids,check_access=0",['id','name']);
    4. #3 Will give you the names and IDs of the MM pages in Production. Prepare these names for an OR selector string similar to what you did with $ids in #3.
    5. Use the $names selector string in #3 to find the corresponding MM pages in the staging site, i.e. findRaw("name=$names",['id','name']);
    6. You will end up with two arrays, one for production and one for staging with values $productionArray = [1234=>'my-awesome-image'] and $stagingArray = [5623 => 'my-awesome-image'].
    7. You can process this two arrays so that you end up with $processedArray = [1234 => 5623, etc]
    8. Loop through the newly imported pages in staging, loop through their MM fields and replace 1234 with 5623.

    OR simply...

    1. Install ProcessDatabaseBackups in the production site
    2. Export the site usign ProcessDatabaseBackups
    3. Install ProcessDatabaseBackups in the staging site
    4. Use ProcessDatabaseBackups to backup the current DB in the staging site
    5. Import the exported db from production (#2) into the staging site using ProcessDatabaseBackups
    6. Copy the assets from production site into staging site
    7. Test
    8. Done 🙂
  13. Hi @alexm,

    7 hours ago, alexm said:

    there is a space after the £ symbol which I notice on the demo site too. Where might one remove this space so it displays as £10.00 rather than £ 10.00?

    That's interesting. I am not seeing the space in my local dev nor in the starter demos. However, I am seeing it on the demo site as you point out. Not sure what's going on there. I know the demo site's Padloper is a bit old but that wouldn't be your case. PHP version differences? Meanwhile, maybe try and remove the space post the fact (str_replace())?

    • Like 1
  14. Hi @sodesign,

    8 hours ago, sodesign said:

    script to add a few hundred pages to a site, and each page has a media-manager-image field

    It is not clear to me what you mean by 'media-manager-image field'. Do you mean images in a FieldtypeMediaManager/InputfieldMediaManager field on a 'usual' ProcessWire page or are you talking about the actual image field (media_manager_image) that holds the images for media items in media manager pages  (which live in /admin/media-manager/...)?

    Are the staging and production sites on the same server?

  15. Hi @alexm,

    Thanks for clarifying. I get you now. Although the those hooks would normally work, since the form in cart-edit is being submitted to a 'virtual' URL handled by URL Hooks and because a redirect occurs, execution halts, hence, the 'hooks' get released/discarded and you are left with nada. If anyone knows if my statement is untrue or partially incorrect, please let me know.

    Now, back to your issue, easiest solution is to handle updating the cart yourself using $padloper API instead of sending the form (action) to the virtual padloper URL. This will allow you to process your custom form inputs yourself. Updating the cart is as simple as this:

    <?php
    
    namespace ProcessWire;
    // *** UPDATE CART FOR AN EXISTING CART ITEM ***
    // @note: $id: this is the id of this product as a cart item in the database
    // it is not the page ID of the product!
    // @note: these inputs should match the fields in your custom 'cart-edit' form
    $id = (int) $input->post->padloper_cart_update_product_id;
    $quantity = (int) $input->post->padloper_cart_update_product_quantity;
    // update the cart ($key=>$value pair of cartItemID => cartItemQuantity)
    $updatedCartProduct = [$id => $quantity];
    // update the cart
    $padloper->updateCart($updatedCartProduct, $rem_products = null, $isRedirect = false);
    // handle your custom form input
    $discountCode = $sanitizer->text($input->post->discount_code);
    // ETC...

    Your and PadloperCart::getProductPrice', null, 'discountCodePrice' Hook doesn't need changing.

    Hope this helps. Please let me know if you need further help with this.

    • Thanks 1
  16. Hi @alexm,

    6 hours ago, alexm said:

    I'm trying to hook Padloper::updateCart so I can grab a discount code from an input field named 'discount_code' in cart-edit.php so I can set it to the users session if the discount code matches however I can't seem to hook this. It looks like it's hookable, but have tried hook, hookBefore and hookAfter and simply stuck a bd('Test') and wire('log') in there to check but not getting anything.

    I have tested and it works for me with hook, hookBefore and hookAfter, i.e. all the below work (in ready.php):

    <?php
    
    namespace ProcessWire;
    
    // $this->addHookBefore('Padloper::updateCart', null, 'updateCartHook');
    $this->addHookAfter('Padloper::updateCart', null, 'updateCartHook');
    // $this->addHook('Padloper::updateCart', null, 'updateCartHook');

    padloper_hook_updateCart.thumb.png.0be1e999d956f151131e4572ce8671af.png

    However, it is not clear to me how hooking into Padloper::updateCart helps with what you are trying to achieve. 676 in the example above is the cart_row_id of some product and 6 is the quantity of the product in the cart. What information about the cart are you after in relation to your discount?

    • Like 1
  17. On 4/7/2023 at 11:49 AM, LMD said:

    HTMX call with a bit of javascript in the header

    Others have mentioned how to do it in the Markup or in $config. If you wanted to do it using JS, this is how:

    document.body.addEventListener("htmx:configRequest", (event) => {
    	// add XMLHttpRequest to header to work with $config->ajax
    	event.detail.headers["X-Requested-With"] = "XMLHttpRequest"
    })

    https://htmx.org/events/#htmx:configRequest

    Not meaning to hijack this thread and I haven't read through everything and I don't know how Markup Regions work...just want to mention that I have set up a GitHub repo for htmx + Alpine.js + Tailwind CSS + ProcessWire demos. It is early days but I am hoping to add all sorts of demos there, from basic to advanced ones, including backend and frontend examples. I'll  create a thread for this work at a later time. Meanwhile (and I have nothing against the OP wish), I am happy to take on a challenge  like 'how would you build this complex page using htmx' . OK, maybe not as complex as this app: From React to htmx on a real-world SaaS product 😁: (too much todo, etc.).

    Edit

    First two demos are discussed in this thread:

     

    • Like 6
    • Thanks 1
  18. 9 hours ago, Pete said:

    The HTMX demo works with 2 dummy variations under a product,

    Glad it worked!

    9 hours ago, Pete said:

    but the Alpine demo doesn't show the options

    That's strange. Are the options definitely sent to the browser? That's line #138 here in /demos/demo_alpine_renders_modal/products-alpine-renders-modal.php . If you dump $allProductsVariants here in line #96, do you get anything?

×
×
  • Create New...