Jump to content

Liam88

Members
  • Posts

    45
  • Joined

  • Last visited

Posts posted by Liam88

  1. Hey,

    I have the usual CKeditor set up with the insert image(s) button.

    image.png.213ee6477850c5f2c4d58bc8b480953a.png

    I have done some googling but struggling to find a way to add video support in that bar.

    Does anyone have any advice they could offer.

    Thanks

  2. 21 minutes ago, flydev ?? said:

    I am used to use the Delayed Output Strat so I can't tell you right now what's going on for real

    Yeah I'll have to search if there are any other threads for markup regions strat.

    Getting the same output with the suggestion above so did a bit of searching and found this - https://processwire.com/blog/posts/processwire-2.6.8-brings-new-version-of-reno-admin-theme-and-more/#new-this-gt-halt-method-for-use-in-template-files

    Adding $this->halt to the end of each case prevents the continued render when using it within _init.php (the prepended file).

    This does not work if just adding to _main.php. 

    This is the action area now - 

    <?php
    if($config->ajax && $input->post->bookmark){
    
      bd($input->post->bookmark); // debug with tracy, uncomment if you have it
      $bookmarkid = $sanitizer->int($input->post->bookmark);
      $action = $sanitizer->name($input->post->action);
      $bookmarks = $user->getUnformatted('bookmarks');
      switch($action) {
        case 'save': // save logic
          if(!$bookmarks->has($bookmarkid /* this was bookmark, now bookmarkid */)) {
            // add bookmark
            $bookmarks->add($bookmarkid /* same change here */);
            $user->setAndSave('bookmarks', $bookmarks);
            $message = 'Borat saved bookmark "'. $bookmark->id .'" ?';
    		$this->halt(); 
          }
          else {
            $message = 'Nothing done';
          }      
          $success = true;
          break;
        case 'remove': // remove logic
          if($bookmarks->has($bookmarkid)) {
            $bookmarks->remove($bookmarkid);
            $user->setAndSave('bookmarks', $bookmarks);
            $message = 'Borat removed bookmark "'. $bookmark->id .'" ';
    		$this->halt(); 
          } else {
            $message = 'Nothing done';
          }
          $success = true;
          break;
        default:
          $message = 'error';
          $success = false;
      }
        
     $json = array( 
        'id' => $bookmarkid,
        'action' => $action,
        'message' => $message,
        'success' => $success
      ); 
      header('Content-Type: text/json; charset=utf-8');
      echo json_encode($json);
      return;
    }
    ?>

    Now I get this within preview:

    image.thumb.png.024869a10ad8db0943aaf9b03916a625.png

    and FINALLY it now saves into the user area. 

    Celebrate Meme Discover more interesting Birthday, Celebrate ...

    A huge thank you @flydev ??. Learnt so much through this thread and hoping it helps others!

    I'll even keep in borat in recognition of your input.

    • Like 1
  3. So another update

    Script looks like this - 

    jQuery(document).ready(function($) {
        // when clicked, send ajax request to server
        $('button.bookmark').on('click', function(e) {
          var btn = $(this).hasClass('clicked') ? false : $(this).addClass('clicked');
          if (!btn) {
            console.warn(`⚠️ Bookmark already saved to profile`);
            return false;
          }
          $.post('<?=$pages->get('/')->url?>', { action: $(this).val(), bookmark: btn.data('id') })
            .done(function(data) {
              console.log(data, "? response from ajax req");
              console.info(` Bookmark id => ${data.id} ${data.action} `);
            });
        });        
      }); 

    I have put this in _main.php (all template is appended to this via config.) at the top so before anything. I just included it within the namespace opening within the template. I left out the if user is logged in as this feature will only be available for logged in users.

    <?php namespace ProcessWire;
    if($config->ajax && $input->post->bookmark){
    
      bd($input->post->bookmark); // debug with tracy, uncomment if you have it
      
      $bookmarkid = $sanitizer->int($input->post->bookmark);
      $action = $sanitizer->name($input->post->action);
      $bookmarks = $user->getUnformatted('bookmarks');
      switch($action) {
        case 'save': // save logic
          if(!$bookmarks->has($bookmark)) {
            // add bookmark
            $bookmarks->add($bookmark);
            $user->setAndSave('bookmarks', $bookmark);
            $message = 'Borat saved bookmark "'. $bookmark->id .'" ?';
          }
          else {
            $message = 'Nothing done';
          }      
          $success = true;
          break;
        case 'remove': // remove logic
          if($bookmarks->has($bookmark)) {
            $bookmarks->remove($bookmark);
            $user->setAndSave('bookmarks', $bookmarks);
            $message = 'Borat removed bookmark "'. $bookmark->id .'" ';
          } else {
            $message = 'Nothing done';
          }
          $success = true;
          break;
        default:
          $message = 'error';
          $success = false;
      }
        
      // build the response data array that will be returned in `data` from `.done(function(data) {`
      $json = array( 
        'id' => $bookmarkid,
        'action' => $action,
        'message' => $message,
        'success' => $success
      ); 
      // convert data and send as JSON
      header('Content-Type: text/json; charset=utf-8'); // forgot this line
      echo json_encode($json);
      return;
    }
    ?>

    So now I get this within preview (video below). Still full html render output (Any thoughts why would this be?) but now the JSON is appended. I have also tried placing the if AJAX within the _init.php file. This just prepends it (expected) to before the HTML output. So I suppose my issue is I'm rendering the full HTML output as the JSON just shows as part of it.

     

     

  4. 4 minutes ago, flydev ?? said:

    You need to show us what is inside the "preview" tab to see what's the answer returned (the payload is what you send, the preview is the answer you get)

    The preview just renders the page HTML. It isn't giving a JSON breakdown. 

    So you're getting the JSON response, I'm getting a full page render. Once back on later I'll update with a. Screenshot.

  5. Thanks again @flydev ??

    Correct, all is within a single template. This is then appended to _main.php. The full template is in my reply above.
    To be honest I'm stuck on this so instead of this seeming like a game of circles I'll take some time out to get to grips with it.

    From what I can tell, I can not see anything wrong but again that is my lower knowledge barrier.

    On button click, I do not get anything firing in console. When I click a second time I then get "⚠️ Bookmark already saved to profile"

    A quick question, should any of this part be included and should it be within the loop? 

    <?php
    if($user->isLoggedin() && $action) {
    $bookmarks = $user->getUnformatted('bookmarks');
    if($action === 'remove') {
    // remove bookmark
    if($bookmarks->has($posts)) $bookmarks->remove($posts);
    } else if($action === 'save' && !$bookmarks->has($posts)) {
    // add bookmark
    $bookmarks->add($posts);
    }
    // save bookmarks
    $user->setAndSave('bookmarks', $bookmarks);
    $this->halt();
    }
    ?>

    Within console -> network I get this when clicking a button and within network -> preview I just get the full page html which I'm guessing shouldn't be the case.

    This is the page in question - https://ad-bank.co.uk/all-ads/

     

    Anyway, I'll take some time out to get to grips on this but appreciate all the info and direction on this. 

  6. 10 hours ago, flydev ?? said:

    Get rid of writing the $action = $input->post->option('bookmark', [ 'save', 'remove'] );  block in a loop, you do not need that.

    If you look at my example (made some corrections for consistency), you are capturing the action made by the user in the `$input->bookmark->action`  and the id in `$input->bookmark->id` (form data built in the $.post() ajax jquery code):

    (I don't know what is the `$input->post->option('a', ['b', 'c'])`) thing, but we dont care)

    bd($input->post); // debug with tracy
      /** contain:
       *  action: 'save'
       *  bookmark: '1024'
       */

     

    Then just handle the request :

    <?php 
    /** threat ajax (pw) => https://processwire.com/api/ref/config/#pwapi-methods-runtime
     *  Better to write a dedicated template which will receive the request.
     *  That is a good candidate and exercise to try the module AppApi ?
     */
    if($config->ajax && $input->post->bookmark) {
    
      // bd($input->post->bookmark); // debug with tracy, uncomment if you have it
      /** contain:
       *  action: 'save' or 'remove'
       *  bookmark: '1024'
       */
      
      $bookmarkid = $sanitizer->int($input->post->bookmark);
      $action = $sanitizer->name($input->post->action);
      switch($action) { // which action ?
        case 'save': // save logic
          $message = 'Borat saved bookmark "'. $bookmarkid .'" ?';
          $success = true;
          break;
        case 'remove': // remove logic
          $message = 'Borat removed bookmark "'. $bookmarkid .'" ';
          $success = true;
          break;
        default:
          $message = 'error';
          $success = false;
      }
        
      // build the response data array that will be returned in `data` from `.done(function(data) {`
      $json = array( 
        'id' => $bookmarkid,
        'action' => $action,
        'message' => $message,
        'success' => $success
      ); 
      // convert data and send as JSON
      header('Content-Type: text/json; charset=utf-8'); // forgot this line
      echo json_encode($json);
      return;
    }
    ?>
    
    
    <!-- the only one loop -->
    
    <!-- you dont really need a form -->
    <!-- <form action='<?=$page->url?>' method='post'> -->
    
    <?php // dummy bookmarks loop logic for the show
    $bookmarks = $pages->find("template=dummypage, limit=5, sort=sort");
    foreach ($bookmarks as $bookmark):
    ?>
    <?php if($user->isLoggedin()): ?>
        <!-- show button to save and remove this page to bookmarks -->
    	<!-- of course, make your own logic to show one or other button -->
        <!-- add a data attribut to each button -->
        <button class="button bookmark" name='bookmark' value='save' data-id='<?= $bookmark->id ?>'>Save <?= $bookmark->id ?></button>
        <button class="button bookmark" name='bookmark' value='remove' data-id='<?= $bookmark->id ?>'>Remove <?= $bookmark->id ?></button>
    <?php endif; ?>
    <?php endforeach; ?>
    
    <!-- </form> -->
    
    
    
    <script>
      jQuery(document).ready(function($) {
        // when clicked, send ajax request to server
        $('button.bookmark').on('click', function(e /* add event arg */) {
          var btn = $(this).hasClass('clicked') ? false : $(this).addClass('clicked');
          if (!btn) {
            console.warn(`⚠️ Bookmark already saved to profil`);
            return false;
          }
          $.post('<?= $page->url /* send to the page which have the logic and return json answer */ ?>', { action: $(this).val(), bookmark: btn.data('id') })
            .done(function(data) {
              console.log(data, "? response from ajax req");
              // $(this).removeClass('clicked'); // remove `clicked` class, can be added on the foreach loop if the bookmark is already saved and then locked, or whatever..
              console.info(` Bookmark id => ${data.id} ${data.action} `);
            });        
            
          //e.preventDefault(); // you didn't need a <form>, and if you really want it, add this line to prevent default behavior and stop the redirection
        });        
      }); 
    </script>

     

    I will make you an example to save the page, but if I were you, I would just save a "page (ID)" in a page-reference field in the profile.

     

    ajx.gif

    As always, thank you @flydev ??

    Straight implementing your snip I'm getting undefined response - 

    image.png.6e2cfa36d435cbbad59604840bcf72d4.png

    This is the whole template file for /all/ url mentioned above. From what I can see it's implemented right?... So where you mention the "only one loop" is where I have placed the main template build. 

    <?php namespace ProcessWire;
    $items = $pages->find($selector); //selector built in _func template
    $total = $items->getTotal();
    
    if($config->ajax && $input->post->bookmark){
    
      bd($input->post->bookmark); // debug with tracy, uncomment if you have it
      
      $bookmarkid = $sanitizer->int($input->post->bookmark);
      $action = $sanitizer->name($input->post->action);
      switch($action) { // which action ?
        case 'save': // save logic
          $message = 'Borat saved bookmark "'. $bookmarkid .'" ?';
          $success = true;
          break;
        case 'remove': // remove logic
          $message = 'Borat removed bookmark "'. $bookmarkid .'" ';
          $success = true;
          break;
        default:
          $message = 'error';
          $success = false;
      }
        
      // build the response data array that will be returned in `data` from `.done(function(data) {`
      $json = array( 
        'id' => $bookmarkid,
        'action' => $action,
        'message' => $message,
        'success' => $success
      ); 
      // convert data and send as JSON
      header('Content-Type: text/json; charset=utf-8'); // forgot this line
      echo json_encode($json);
      return;
    }
    ?>
    
    <div id="content-main" class="adbank" pw-append>
      <!-- start of page header -->
    <header class="small-header">
    	<div class="full-width">
    		<div class="row flex header-content">
    			<h1><?php echo $page->headline ?></h1>
    			<?php 
    			if ($page->summary != ''){
    				echo''.$page->summary.'';
    			}
    			?>
    		</div>
    	</div>
    </header>
      <!-- end of page header -->
    <div class="bread-plus-filter">
        <div class="full-width">
            <div class="row flex">';
                <!-- Breadcrumbs for all pages except home page -->
                <?php include_once "inc/breadcrumb.php"; ?>
                <div class="filter-surround">
                    <div class="filter-row">
                    <p><?=$total?> Results</p>
                      <!-- filter button -->
                    <button class="button filter-toggle open-menu" type="button" aria-label="Toggle filter">
                        Filter		
                    </button>
                    </div>
                </div><!-- close of filter surround -->
            </div>
        </div>
    </div>
    
    <!-- Main blog post section -->
    <section id="main-post-area" class="ab-post-area">
    	<div class="full-width">
    	<?php if(count($items) > 0){
    	}else{
    		echo'<h2>Sorry, no results match that filter</h2>';
    	}
        ?>
        <div class="row">
        <!-- main creative grid -->
    			<div class="creative-posts-container grid">
                    <!-- colcade columns -->
                    <div class="grid-col grid-col--1"></div>
                    <div class="grid-col grid-col--2"></div>
                    <div class="grid-col grid-col--3"></div>
    				<!-- loop out the posts from the selector -->
                    <?php foreach($items as $posts): ?>
                        <div class="creative-post grid-item <?=$posts->ab_channels->title?> <?=$posts->ab_placement->title?> <?=$posts->ab_content->title?> <?=($posts->check_1 ? ' no-title' : '')?> <?=($posts->image_1->height / $posts->image_1->width >= 1.5 ? 'long' : 'short')?> ">
                            <div class="creative-post-options">
                              <!-- posts buttons including view brand, view post and save -->
                                <div class="actions">
                                    <a href="<?=$posts->adbank_brands->{httpUrl}?>" class="action" role="link" aria-label="View more of <?=$posts->adbank_brands->{title}?>" title="View more of <?=$posts->adbank_brands->{httpUrl}?>">View Brand</a>
                                    <a href="<?=$posts->httpUrl?>" class="action" role="link" aria-label="see more info about this advert" title="see more info about this advert">View Ad</a>
                                    <?php if($user->isLoggedin()): ?> <!-- if user is logged in -->
                                        <?php if($user->bookmarks->has($posts)): ?> <!-- if user has saved then show this button -->
                                            <button class="button action" type='submit' name='saved' value='saved' disabled>Saved</button>
                                        <?php else: ?>
                                            <!-- if they haven't saved then show this button to add this page to bookmarks -->
                                            <button class="button bookmark action" type='submit' name='bookmark' value='save' data-id='<?=$posts->id?>'>Save</button> <!-- changed to $posts->id from bookmarksId to match the foreach output -->
                                        <?php endif; ?>
                                    <?php else: ?>
                                  <!-- if user is not logged in then show this button to fire a login modal -->
                                        <button class="button action save-modal" role="button" title="save this ad bank post" aria-label="save this ad bank post" href="">Save</button>
                                    <?php endif; ?>
                                    </div>
                                </div>
                          <!-- loop through posts type and include the relevant markup -->
                            <?php
    							if($posts->ab_channels->title === "facebook-ads"){
    								include "inc/adbank/facebook-ads.php";
    							}else if($posts->ab_channels->title === "instagram-ads"){
    								include "inc/adbank/instagram-ads.php";
    							}else if($posts->ab_channels->title === "pinterest-ads"){
    								include "inc/adbank/pinterest-ads.php";
    							}else if($posts->ab_channels->title === "youtube-ads"){
    								include "inc/adbank/youtube-ads.php";
    							}else if($posts->ab_channels->title === "display-ads"){
    								include "inc/adbank/display-ads.php";
    							}else if($posts->ab_channels->title === "tiktok-ads"){
    								include "inc/adbank/tiktok-ads.php";
    							}else if($posts->ab_channels->title === "podcast"){
    								include "inc/adbank/podcast.php";
    							}else{
    							}
                            ?>
                        </div>
                    <?php endforeach ?>
                    
    			</div><!-- end of main creative grid -->
    		</div><!-- End row -->
    	</div><!-- End container -->
    </section><!-- End section -->
      
    <!-- pagination -->
    <?php echo pagination($items); ?>
     <!-- AJAX request -->
    <script>
      jQuery(document).ready(function($) {
        // when clicked, send ajax request to server
        $('button.bookmark').on('click', function(e) {
          var btn = $(this).hasClass('clicked') ? false : $(this).addClass('clicked');
          if (!btn) {
            console.warn(`⚠️ Bookmark already saved to profile`);
            return false;
          }
          $.post('<?= $page->url?> /*should this be $posts->URL>*/', { action: $(this).val(), bookmark: btn.data('id') })
            .done(function(data) {
              console.log(data, "? response from ajax req");
              console.info(` Bookmark id => ${data.id} ${data.action} `);
            });
        });        
      }); 
    </script>
      <!-- end of AJAX request -->
    </div> <!-- end of content surround -->

     

  7. Just an update again.

    So I have the AJAX working on the single page. See below woop!

    Next steps is trying to get this to work with a variable input. I have taken your jquery snip @flydev ??, again thank you.

    Right now I'm just trying to get it to work on this page which has a loop of posts - https://ad-bank.co.uk/all-ads/

    This is where I'm at.

    The main button section. Only showing a "save" button if the user has not saved the page.

    <?php if($user->isLoggedin()): ?>
      <?php if($user->bookmarks->has($posts)): ?>
        	<button class="button bookmark action" type='submit' name='bookmark' disabled>Saved</button>
        <?php else: ?>
        <!-- show button to add this page to bookmarks -->
        	<button class="button bookmark action" type='submit' name='bookmark' value='save' data-id='<?=$posts->url?>'>Save</button>
        <?php endif; ?>
    <?php endif; ?>

    Next is the action element shown above. This is also within the foreach loop so it is repeated for each button. I found this was the only way I could get it to capture the button action.

    Is there a better way to do this without having this action snip repeated for each button? Would it be using the data id attribute which could then sit outside of the loop?

    <?php
    $action = $input->post->option('bookmark', [ 'save', 'remove'] );
    if($user->isLoggedin() && $action) {
    $bookmarks = $user->getUnformatted('bookmarks');
    // I have now removed "remove" from the button section. Kept it in just in case I do wish to use it.
    if($action === 'save' && !$bookmarks->has($posts)) {
    // add bookmark
      $bookmarks->add($posts);
    }
    // save bookmarks
    $user->setAndSave('bookmarks', $bookmarks);
    $this->halt();
    }
    ?>

    Then I have the AJAX request here. This now takes the button data id attribute instead of <?= $page->url ?>. This I found means it grabs the correct url instead of the first url on page that is not saved.

    $(document).ready(function($) {
        // when clicked, send ajax request to server
        $('button.bookmark').on('click', function() {
        var btn = $(this).hasClass('clicked') ? false : $(this).addClass('clicked');
    	// I am passing data id instead of page->url as it will capture the button value needed. Not sure if correct, console shows the correct value.
        if(btn) $.post($(this).data('id'), { action: $(this).val(), bookmark: btn.data('id') })
            .done(function(data) {
            //do something
            console.info(` Bookmark id => ${btn.data('id')} saved to user profile`);
            });
        });
    }); 

    So in console I get a successful output (see below) but it's not saving into the user. Any thoughts why this might be? I'm thinking it's the action part of this but not sure.

    image.thumb.png.236c1e529a6adcbad0afed9e2ba99cf6.png

    Overall, feels good to be making progress on this and learning. If anyone has input on the above issues please fire over.

    Cheers

  8. 10 hours ago, flydev ?? said:

    I don't really get what is your issue, the click that still redirect ? If yes, just add `e.preventDefault()` to your js script to prevent default behavior as your are submiting a form.

     

    <?php 
    /** threat ajax (pw) => https://processwire.com/api/ref/config/#pwapi-methods-runtime
     *  Better to write a dedicated template which will receive the request.
     *  That is a good candidate and exercise to try the module AppApi ?
     */
    if($config->ajax && $input->post) {
    
      bd($input->post->bookmark); // debug with tracy
      /** contain:
       *  action: 'add'
       *  bookmark: '1024'
       */
    
      /**
       * you can write some logic here, eg., to grab the post data sent by the ajax request
       */
      $bookmarkid = $sanitizer->int($input->post->bookmark);
      // eg. you can get a page from that
      $bookmarkedPage = $pages->get($bookmarkid);
      // send response data back
      $message = 'Borat added bookmark "'. $bookmarkedPage->title .'" ?';
      $success = true;
      
      // build the response data array
      $json = array(
        'message' => $message,
        'success' => $success
      ); 
      // convert data and send as JSON
      header('Content-Type: text/json; charset=utf-8'); // forgot this line
      echo json_encode($json);
      return;
    }
    ?>
    
    <?php // dummy bookmarks loop logic for the show
    // foreach($bookmarks as $bookmark) : 
      $bookmark = $pages->get(1024); // forgot this line
    ?>
    <!-- you dont really need a form -->
    <!-- <form action='<?=$page->url?>' method='post'> -->
    <?php if($user->isLoggedin()): ?>
        <!-- show button to add this page to bookmarks -->
        <!-- add a data attribut to each button -->
        <button class="button bookmark" name='bookmark' value='add' data-id='<?= $bookmark->id ?>'>Save bm #1</button>
    <?php endif; ?>
    <?php //endforeach; ?>
    <!-- </form> -->
    <script>
      jQuery(document).ready(function($) {
        // when clicked, send ajax request to server
        $('button.bookmark').on('click', function(e /* add event arg */) {
          var btn = $(this).hasClass('clicked') ? false : $(this).addClass('clicked');
          if (!btn) {
            console.warn(`⚠️ Bookmark already saved to profil`);
            return false;
          }
          $.post('<?= $page->url /* send to the page which have the logic and return json answer */ ?>', { action: $(this).val(), bookmark: btn.data('id') })
            .done(function(data) {
              console.log(data, "? response from ajax req");
              // $(this).removeClass('clicked'); // remove `clicked` class, can be added on the foreach loop if the bookmark is already saved and then locked, or whatever..
              console.info(` Bookmark id => ${btn.data('id')} saved to user profil`);
            });        
            
          //e.preventDefault(); // you didn't need a <form>, and if you really want it, uncomment this line to prevent default behavior and stop the redirection
        });        
      }); 
    </script>

     

    ajx.gif.1b5b743b02c04fda2b1c2b9fefb61b09.gif

     

    giphy.gif?cid=ecf05e47uqm52d4j5pif2nid1o

    Thanks @flydev ??

     

    Tbh I need to spend time to learn more about AJAX and implementation.

    I'll try implement this on the single option page so /all/page-name/ and then work on the /all/.

    Unless based on the above, I don't need dedicated versions for each page? Again, will have to get digging into AJAX this week.

    Cheers

  9. To update where I'm at.

    So I have - 

    • Added a page ref field to the user template
    • Created a front end button that adds or removes the page id to/from the page ref field.

    This means the like module is not needed as I'm not looking to allow anon users to save, only logged in users.

    This is the button. I will most likely remove the "remove" button and just have a "saved" item to signify it's saved. I'll allow users to remove in their profile area which outputs their saved posts.

    <?php if($user->isLoggedin()): ?>
    <form action='<?=$page->url?>' method='post'>
      <?php if($user->bookmarks->has($page)): ?>
      <!-- user already has this page in their bookmarks, show remove button -->
      <button class="button save-button" type='submit' name='bookmark' value='remove'>Remove</button>
      <?php else: ?>
      <!-- show button to add this page to bookmarks -->
      <button class="button save-button" type='submit' name='bookmark' value='add'>Save</button>
      <?php endif; ?>
    </form>  
    <?php endif; ?>

    This is then be actioned by the below. 

    $action = $input->post->option('bookmark', [ 'add', 'remove'] );
    if($user->isLoggedin() && $action) {
    $bookmarks = $user->getUnformatted('bookmarks');
    if($action === 'remove') {
    // remove bookmark
    if($bookmarks->has($page)) $bookmarks->remove($page);
    } else if(!$bookmarks->has($page)) {
    // add bookmark
    $bookmarks->add($page);
    }
    // save bookmarks
    $user->setAndSave('bookmarks', $bookmarks);
    // always good to redirect back to self after POST save request
    $session->redirect($page->url, false);
    }

    This works great for the actual post page. So url example being website.com/all/page-name/

    However, I have a foreach on website.com/all/ and have the save button on each foreach output.

    These in the foreach are called $posts.

    I have been able to get it to work by adjusting the above to be $posts instead of $page. However, I find that it just sends the user to the $posts URL but I'd want them to stay on the current page. I did this posts suggestion:

    However, I find it doesn't redirect to the /all/ page but goes to /all/page-name/

    I also saw a suggested version below to AJAX it which would remove the redirect issue in /all/. So removal of the form element and I'm doing the button show/hide through PHP instead of JS. The snip below doesn't do anything right now and I'm not too sure why.

    Any input from someone with JS/AJAX knowledge is appreciated.

    <?php if($user->isLoggedin()): ?>
      <?php if($user->bookmarks->has($posts)): ?>
        <!-- user already has this page in their bookmarks, show remove button -->
        <button class="button save-button" name='bookmark' value='remove'>Remove</button>
      <?php else: ?>
        <!-- show button to add this page to bookmarks -->
        <button class="button save-button" name='bookmark' value='add'>Save</button>
      <?php endif; ?>
    <?php endif; ?>
    
    <script>
      jQuery(document).ready(function($) {
            // when clicked, send ajax request to server
            $('button.bookmark').on('click', function() {
            var btn = $(this).hasClass('clicked') ? false : $(this).addClass('clicked');
            if(btn) $.post('<?= $posts->url ?>', { bookmark: btn.val() })
                .done(function(data) {
                });
            });
        }); 
    </script>

    Feels good to get this working but just need to hone in the user experience and behaviour. If anyone wants to see the page in question it's here

    Liam

  10. 1 hour ago, flydev ?? said:

    I understand, and my point to suggest you to ask @ryan directly if his pro module can fit your needs, is because ryan is used to give more flexibility instead of locking the user to a finished functionality. I mean, there is maybe some hooks that can be used to link things to an user. Without speaking about that you benefit ryan's code and insight ?

    Anyway, I will might buy it for a project and could give more feedbacks. Stay tuned.

    Yeah, at the end of my reply to yourself I gave ryan an @ but I'll pop him a PM.

    Appreciate all the direction on this by the way. It's a fun side project to get more into processwire and luckily the forum is full of great info and direction.

    • Like 1
  11. On 9/1/2022 at 10:30 AM, flydev ?? said:

    @Liam88 you might try and ask @ryan if you could achieve it with the Pro Module `Likes`:

     

     

    Thanks @flydev ??, it looks like it may by this line:

    "This enables you to have a separate page (or perhaps a sidebar on every page) that [for example] shows the user bookmarks of pages they liked"

    However, I'm not sure it would match the full desired behaviour with the below:

    "FieldtypeLikes is not connected with the user system, and may be used anonymously via any page on your site."

    I want the liked page to be connected to the user so it can be outputted in a "profile" area. Think Pinterest or even more relevant "follow" on here.

    So I'm looking to.

    Have a save button on a page.

    • If the user is logged in then save the page
    • if not then fire a modal with the LRP register execution. Probably could be done with a check whether a user is logged in.

    However, I was hoping there would be a simple way to just have a connection between user id and page id.

    Maybe something like clicking save would add the page id to a repeater but feels quite clumsy and probably slow.

    Overall, not sure on the best practice or best direction to achieve this. The joys of using a side project to learn more.

    Any thoughts from your side @ryan on whether likes module would work is appreciated.

    Thanks

  12. 7 minutes ago, AndZyk said:

    Thank you for explanation.

    This is working for me:

    <?php
    if ($input->urlSegment1) {
        $userID = $sanitizer->int($input->urlSegment1());
        $u = $users->get($userID);
    
        if ($u->id) {
            if ($u->hasRole("login-register")) {
                echo $u->name;
                echo $u->email;
            } else {
                wire404();
            }
        } else {
            wire404();
        }
    }

    If you always get a 404 error, then maybe your ctype_digit check fails.

    Regards, Andreas

    Thanks @AndZyk

    Trying this snip is also firing a 404. 

    If I remove access management set in the template then I can get it to work. Taking your snip as an example I get this.

    image.thumb.png.2c8611600bc984c55bf9f6399cea7fdc.png

    It would just mean I would have to do access management within the PHP (e.g $u->isLoggedIn()) and not leave PW to it.

    However, that feels against the reasons for it being within PW.

    So the summarise, it seems this is an access issue and not a recognising role issue. Unless it's the access control not recognising the role. Who knows haha.

    • Like 2
  13. 22 minutes ago, AndZyk said:

    Hello @Liam88,

    do you mean the free Login Register module or the commercial Login Register Pro module?

    I have no experience with the commercial module but I think neither require URL segments.

    You either just let the module do its default behavior:

    <?= $modules->get('LoginRegister')->execute() ?>

    Or you customize it:

    <?php
    if($user->isLoggedin() && !$input->get('profile') && !$input->get('logout')) {
      // you take over and render your own output or redirect elsewhere
      $session->redirect('/some/other/page/'); 
    } else {
      // let the LoginRegister module have control
      echo $modules->get('LoginRegister')->execute(); 
    }

    Source

    Regards, Andreas

    Hey @AndZyk

    Thank you for your reply. 

    I use the pro module.module.

    I'm not looking to use the login-register/profile? areas but just use it for user management. So that would be create account, change password etc.

    I then have a dedicated user area under /profile/ which does all the custom bits for users. Think Pinterest style where you have an area that shows posts and boards. 

    So in that /profile/ I then use URL segments to grab the relevant posts and boards linked to their user id. So /profile/user-id/

    So the snip I inserted above takes URL seg 1 and then would action based on the behaviour I dictate.

    The template settings are all set up to do this so I shouldn't need bits like is logged in etc. So access management all done via PW. 

    The screenrecord is just to show that I'm logged in and have a login-register role but get a 404 when viewing the /profile/ page. 

    hope that helps explain better on why and the intention.

  14. Hello,

    Just wondering if anyone has come across URL segments not working.

    I have the login register module and creating a dedicated user area for a better user experience.

    So I am using website.com/profile/user-id/ as the user profile page.

    This is set to only show for those with a login-register user role and access is all done through PW.

    Here is the basic snip to just do something if user id in url or not and with or without role.

    $userId = $input->urlSegment1;
    
    if(ctype_digit($userId)) {
      // display profile of user matching id in urlSegment1
      $u = $users->get((int) $userId);
      if($u->id && $u->hasRole('login-register')) {
        echo "<h1>User $user->name info:</h1>";
        // output any fields from user
      } else{
        echo '<h1>Unknown or unavailable user</h1>';
      }
    } else if($userId) {
      wire404(); // something other than user ID in urlSegment1
    
    } else {
      // no urlSegment1 present
      // display links for user profiles?
      foreach($users->get('roles=login-register, sort=name') as $u) {
        echo "<li><a href='$u->id/'>$u->name</a></li>";
      }
    }

    However, all the test profiles I have created that have 'login-register' roles just get 404. If I change it to only show for 'superuser' then I can get mine to show.

    Here is an example.

     

     

    You will see when logged in it shows within the /login-register/ area. Eventually, it would redirect to /profile/user-id/ but kept it like this to show that user is logged in but 404 on profile. The screenshots below confirm set up is correct.

    Any direction on this is appreciated. I'm stuck on why this would be happening. It's like it's not recognising the role. I have added a handful of users to test between behaviours with none working. 

     

    image.png.5207b98c94d29aed89f9756c290c78ed.png

    image.png.705682e510e655bf3b4832dbd8792ad7.png

     

  15. 26 minutes ago, DaveP said:

    You would need to create a role, say 'frontend_user' or some such. (Can't use 'user' because $user is a thing already.)

    Then do something like 

    if($user->hasRole('frontend_user')) {
      // show input form
    }

    See https://processwire.com/api/ref/user/has-role/

    Then https://processwire.com/api/ref/pages/add/ or https://processwire.com/api/ref/pages/new/ should help. You don't need to worry about database IDs and such - PW's API deals with all that

    Thanks @DaveP

     

    I'm using loginregisterpro so I have a lot covered with that.

    I'll take a look at the links you popped in.

    appreciate the direction.

  16. Hello all,

    Looking for input on the best way to implement a Pinterest like save button.

    Aim:

    I want logged in users to be able to save posts to their profile for future accessibility. 

    I would like them to be able to give it a subject, in other words the ability to bucket them into groups.

    Does anyone have a suggestion or an example of something similar?

    I would say my main hurdle is implementing a front end button that would then add a page id into the back end. Guessing that db element would have a page ID and user ID so I can then filter page IDs relevant to User ID.

    TIA.

  17. 8 hours ago, AndZyk said:

    Hello @Liam88,

    you probably see these errors now, because you have enabled the debug mode of ProcessWire on your local copy or XAMPP has display PHP errors enabled.
    I think on your live server display PHP errors is disabled and you should have not enabled the debug mode of ProcessWire.

    The error you get now is, when you try to output a property of something that is not set.
    You should first check if something exists, before you try to access the properties:

    <?php
    if ($page->header_image) {
    	// Do something
    }

    If there is no image, then you cannot access the properties "url" or "description" and get the errors.

    Regards, Andreas

    Thank you Andreas.

    Definitely noticing more issues since moving from live to local. Little elements like I have <? instead of <?php which worked on live but not in local.

    Would you say that anything like the img example above should be within ifs to reduce errors?

    • Like 1
  18. 5 hours ago, bernhard said:

    There is no "blank" keyword in PHP

    Try this:

    if($page->hp_content_rep != "")

    Thank you. I have now changed this out. Interestingly I didn't have this flag as an error when live.

    I have also sorted the depreciated error by using Xampp with php 7.

    Although that error is sorted (and there may be a few more I'll pick up) I'm mainly getting these ones below everywhere.

    All of these were working correctly on live and even on the old local. 

    image.thumb.png.0688242c40bc63a8eacef93c81129b6b.png

    This is line 28

    image.png.894dee97f68e716bd0c2c6c31136030f.png

     

  19. Hello all,

    Ended my hosting and want to move my site back to local. I have downloaded my DB and relevant folders.

    I'm just using Xampp for this which is up and running correctly. Tested with a fresh install of PW.

    Done the following process:

    1. installed fresh PW with created DB
    2. Replaced folder items with existing website
    3. dropped installation DB tables
    4. Imported website DB
    5. Adjusted config DB credentials to match.

    Any direction on what these are? Unfortunately, little knowledge on these elements so direction is much appreciated.

    TIA 
     

    image.png

    image.png

  20. Hello,

    I have a separate sort dropdown and filter section. This is very similar to the processwire demo - https://demo.processwire.com/search/?sort=parent.name

    I also have the same "issue" if you would call it that where i can sort or I can filter, but I can not do both. This is because the url changes.

    So a sort URL may look like:

    website.com/subpage/?sort=random

    and a filter like:

    website.com/subpage/?placement=x&channel=y_z

    I'm looking to be able to sort and filter. So if I change the sort, it won't remove the current filter and vice versa.

    I have the sort dropdown running off one bit of JS and the filter on another with examples of both below:

    This is sort JS

    $(document).ready(function() {
            $(".sort-select").on("change", function() {
                document.location.href = location.pathname+"?sort="+$(this).val();
                //console.log(location.pathname+"?sort="+$(this).val())
                //console.log(location.search)
            });
        });

    This is filter JS

    document.querySelector("form").onsubmit=ev=>{
    	ev.preventDefault();
    	let o={};
    	let noPage = window.location.pathname.split("/").slice(0,-2).join("/") + "/";
    	ev.target.querySelectorAll("[name]:checked").forEach(el=>{
    	(o[el.name]=o[el.name]||[]).push(el.value)})
        if(noPage.length > 1){
    	 	document.location.href = noPage+"?"+Object.entries(o).map(([v,f])=>v+"="+f.join("_")).join("&");
    	}else{
    	 	document.location.href = location.pathname+"?"+Object.entries(o).map(([v,f])=>v+"="+f.join("_")).join("&");
    	}
    }

    This is my input build within the func.php doc:
     

    $selector = '';
    
    // Get the inputs, sanitize and whitelist. Then create an array, then replace _ for | in array for selector filter. Output selector 
    
    if($input->get->sort){
    	$sorted = $input->get->text('sort');
    	$input->whitelist('sort', $sorted);
    	//$selector = $selector .= ",sort=$sorted";
    }
    
    if($input->get->channel){
    	$channel = $input->get->text('channel');
    	$input->whitelist('channel', $channel);
    	$chanArray = explode("_", $channel);
    	$chan = $channel = str_replace('_', '|', $channel);
    	$selector = $selector .= ",ab_channels=$chan";
    }
    if($input->get->content){
    	$content = $input->get->text('content');
    	$input->whitelist('content', $content);
    	$contArray = explode("_", $content);
    	$cont = $content = str_replace('_', '|', $content);
    	$selector = $selector .= ",ab_content=$cont";
    }
    if($input->get->brand){
    	$brands = $input->get->text('brand');
    	$input->whitelist('brand', $brands);
    	$brandArray = explode("_", $brands);
    	$brand = $brands = str_replace('_', '|', $brands);
    	$selector = $selector .= ",ab_brand=$brand";
    }
    if($input->get->style){
    	$styles = $input->get->text('style');
    	$input->whitelist('style', $styles);
    	$styleArray = explode("_", $styles);
    	$style = $styles = str_replace('_', '|', $styles);
    	$selector = $selector .= ",ab_creative_style=$style";
    }
    if($input->get->ugc){
    	$ugcs = $input->get->text('ugc');
    	$input->whitelist('ugc', $ugcs);
    	$ugcArray = explode("_", $ugcs);
    	$ugc = $ugcs = str_replace('_', '|', $ugcs);
    	$selector = $selector .= ",ab_influencer=$ugc";
    }
    if($input->get->place){
    	$placement = $input->get->text('place');
    	$input->whitelist('place', $placement);
    	$placeArray = explode("_", $placement);
    	$place = $placement = str_replace('_', '|', $placement);
    	$selector = $selector .= ",ab_placement=$place";
    }
    if($page->template == 'adbank_brand_page'){
        $brand = $page->title;
        $selector = $selector .= ",adbank_brands=$brand";
    }
    $selector = "template='adbank_pages',limit=12,sort={$sorted} " . trim($selector, ", ");

    Any direction on how to combine these would be really appreciate. I know AJAX may be the best route overall but I don't know how to action that and for time sake trying to get these to both work with page refresh feels more accessible...

    TIA

  21. 4 minutes ago, gebeer said:

    On another sidenote, in this part of your code

    if ($input->get){
    ...
    }else {
    ...
    }

    $input->get will always return true, even if you do not have any GET parameters in your URL because $input->get returns an WireInputData object. You should use

    if($input->get->data) // returns null if there are no URL params

    instead.

    Amazing, thank you. 

    I noticed that when I first did it and changed it to check if count was > etc.

    Now changed to the above.

  22. 5 hours ago, teppo said:

    The problem here is that it depends a lot on your setup, i.e. which output strategy you're using and how your site is set up etc. ?

    If you're using simple direct output (templates/template_name.php directly renders output) then you could do something as simple as this:

    <?php namespace ProcessWire;
    
    // finding results goes here
    
    if ($config->ajax) {
    
        // render results without page "frames", i.e. just the list of cards
    
        // ... and when done, halt the rendering process:
        $this->halt();
    }
    
    // normal page output

    Now you just need to trigger an AJAX request to the same page, read the output, and then replace the part of the page content that you wish to be "dynamically filtered" with new content. Note that for $config->ajax to work, your AJAX request needs to include the "X-Requested-With: XMLHttpRequest" header; jQuery adds this automatically, but if you're using raw XMLHttpRequest, Fetch API, or any other approach to trigger the request then you'll likely have to add that header yourself.

    More examples for AJAX loading content (including alternative approach, where instead of content you return JSON and then render output in JavaScript) can be found from this thread:

    Loosely related, but a couple of issues I spotted in your sample code:

    • You're passing $chan and $cont values to the selector string unfiltered. This is not a good idea: visitors could pass in characters that break the query, or even rewrite the query. Always run user-provided values through Sanitizer methods ($sanitizer->selectorValue()) is a good default, but if you're expecting integers then use $sanitizer->int(), etc.
    • Since you're first finding all results and then limiting them, you will run into performance issues if there's a lot of data. As a general rule of thumb always include a limit in your initial selector — this way the limit is applied in the database, which is much more efficient.

    Hey,

    thank you for the reply and direction.

    I'm going to take a moment to digest the ajax part.

    In the meantime I did update the input part to the below just after doing this post. It would be good to get your view whether this is a better way.

    //Default selector to get ALL products
    $baseSelector = "template='adbank_pages',sort=-created,include=all,limit=12";
    $selector = "template='adbank_pages',sort=-created,include=all,limit=12";
    
    // Get the inputs, sanitize and whitelist. Then create an array, then replace _ for | in array for selector filter. Output selector 
    
    if($input->get->channel){
    	$channel = $input->get->text('channel');
    	$input->whitelist('channel', $channel);
    	$chanArray = explode("_", $channel);
    	$chan = $channel = str_replace('_', '|', $channel);
    	$selector = $selector .= ",ab_channels=$chan";
    }
    if($input->get->content){
    	$content = $input->get->text('content');
    	$input->whitelist('content', $content);
    	$contArray = explode("_", $content);
    	$cont = $content = str_replace('_', '|', $content);
    	$selector = $selector .= ",ab_content=$cont";
    }
    if($input->get->brand){
    	$brands = $input->get->text('brand');
    	$input->whitelist('brand', $brands);
    	$brandArray = explode("_", $brands);
    	$brand = $brands = str_replace('_', '|', $brands);
    	$selector = $selector .= ",ab_brand=$brand";
    }

     

×
×
  • Create New...