2

It's unusual, but I have a client who would like to change the primary logo on scroll. One logo at the top, a second logo on scroll.

I have managed to implement the visible change of logo through css by using an image and then on scroll hiding the image and using a ::before pseudo class (the second logo is text based).

The problem however is I need to change the url in the menu php file based on the class as the two logos need to go to seperate URLS.

Unfortunately I do not know how to write php.

I have found the relevant php file and have tried editing it to:

$logoDiv = '<a href="https://www.link1.com" target="_blank" class="navbar-brand"' . $data_padding_shrink . ' data-minheight="'.(($LOGO->logo_min == "") ? "20" : esc_attr($LOGO->logo_min)).'">';

$logoDiv = '<a href="https://www.www.link2.com" target="_blank" class=".window-scrolled"' . $data_padding_shrink . ' data-minheight="'.(($LOGO->logo_min == "") ? "20" : esc_attr($LOGO->logo_min)).'">';

This does not work and I think it may be more of an 'if/else' statement but I do not now how to complete it.

Edit: So to clarify, I am trying to work out how to change an href destination for an image on scroll. For clarity, I guess you could think of it as the same image, as one is a psuedo on the other.

Any help would be great.

Edit #2 The php from the theme files that outputs the logo is this

$logoDiv = '<a href="'.esc_url( home_url( get_current_blog_id(), '/' ) ).'" class="navbar-brand"' . $data_padding_shrink . ' data-minheight="'.(($LOGO->logo_min == "") ? "20" : esc_attr($LOGO->logo_min)).'">';
        $logoDiv = '<a href="https:url-1.com" target="_blank" class="navbar-brand"' . $data_padding_shrink . ' data-minheight="'.(($LOGO->logo_min == "") ? "20" : esc_attr($LOGO->logo_min)).'">';

I am hiding the image on scroll but showing a pseudo class with text content (the second logo I need to show is actually just text) - so it behaves like one element. I either need to change the url on scroll OR, find a way to add php to add 2 logos, and then hide each one at the appropriate scroll points.

Currently this is how I change the logo from an image to text:

.logo-image.logo-skinnable img {
    opacity: 1;
    transition: opacity 900ms;
}

.window-scrolled .logo-image.logo-skinnable img {
    opacity: 0;
    transition: opacity 900ms;
}


.logo-image.logo-skinnable::before {
    font-size: 29px !important;
    font-family: "Poppins";
    content: 'word logo';
    opacity: 0;
    transition: opacity 700ms;
    position: absolute;
    top: 38px;
}
Outman
  • 3,100
  • 2
  • 15
  • 26
Mr Toad
  • 202
  • 2
  • 12
  • 41
  • 1
    I'm not sure why you would involve PHP in this? PHP doesn't have any clue about anything client. Just print both links and hide/show the correct one depending on if the user has scrolled or not. Also, `class=".window-scrolled"` should be `class="window-scrolled"` (without the dot) – M. Eriksson Jan 29 '19 at 06:36
  • 2
    No need of php here. google for `javascript to change image url on scroll` – Shobi Jan 29 '19 at 06:37
  • Try this https://stackoverflow.com/questions/24239897/change-image-on-scroll-position – Harsh Khare Jan 29 '19 at 06:41
  • Sorry - so the only reason I involved php was because in the theme files, this particular php file controlled the url, I just then assumed I would make the edit here. I initially tried javascript but to no avail. – Mr Toad Jan 29 '19 at 07:02
  • I may be mis-understanding - but the suggestion from @Shobi is to change the image src url - I am actually trying to change the url that the image goes to. Almost like the same image, but it goes to different places at different points. – Mr Toad Jan 29 '19 at 07:16
  • In addition, the suggestion from @HarshKhare - changes the image but not the url – Mr Toad Jan 29 '19 at 07:16
  • When the image changes, does it add `window-scrolled` class to it? – saibbyweb Jan 29 '19 at 10:48
  • Yes it does @saibbyweb – Mr Toad Jan 29 '19 at 19:19
  • Okay, I got it. Do you use jQuery? – saibbyweb Jan 30 '19 at 06:01
  • It would appear so yes, I can see it's loading /js/jquery.js?ver=1.12.4 and /js/jquery-migrate.min.js?ver=1.4.1 in the source code – Mr Toad Feb 01 '19 at 00:37
  • Is there anything in particular that you're trying to avoid? My suggestion would be; render both simultaneously on the page. Use a css rule to hide the second logo using `display:none`, so it is not visible on initial load. Use jQuery to track scroll position and swap the css rules between the two logo elements, hiding the first and subsequently displaying the second. This approach has the added benefit of being pre-rendered, preventing a delay when the logo is swapped – Will B. Feb 03 '19 at 06:56
  • I'm assuming https:// www. www. link2.com is a dummy url. www.www? I also assume that if there are typo's in your question, those typo's are not present in your php code. – Millar248 Feb 08 '19 at 16:09
  • Hi there - yes it is a dummy url as I didn't want the client name in there - this should be the only type/dummy content though. Thanks – Mr Toad Feb 09 '19 at 00:50

2 Answers2

4

The answer demonstrates how to accomplish the desired end-result from the OPs requirements:

I either need to change the url on scroll OR, find a way to add php to add 2 logos, and then hide each one at the appropriate scroll points.

URL is perceived to be the anchor link (<a href=""/>), as the OP has proclaimed that the logo image url is not desired to be changed.

As per my comment, I suggest rendering both simultaneously on the page and use a css rule to hide the second logo using display:none. This will make it not visible on initial load. Then you can use jQuery to track scroll position and swap the css rules between the two logo elements, hiding the first and subsequently displaying the second. Alternatively you may also use absolute positioning, z-index and opacity, as desired to achieve a fading effect of the logos transitioning during scroll.


Method A: find a way to add php to add 2 logos, and then hide each one at the appropriate scroll points

You should be able to render both of the logos in the template, by combining the elements in your PHP $logoDiv variable.

$logoDiv = '<a href="https:url-1.com" target="_blank" class="navbar-brand"' . $data_padding_shrink . ' data-minheight="'.(($LOGO->logo_min == "") ? "20" : esc_attr($LOGO->logo_min)).'">Logo Text</a>
<a href="'.esc_url( home_url( get_current_blog_id(), '/' ) ).'" class="navbar-brand"' . $data_padding_shrink . ' data-minheight="'.(($LOGO->logo_min == "") ? "20" : esc_attr($LOGO->logo_min)).'">';

This approach has the added benefit of being pre-rendered by the browser, preventing a delay for slower systems, when the logo element transitions occur.

jQuery(function($) { //same as $(document).ready()
    var logos = $('.scroll-logo');
    $(window).on('scroll', function(e) {
        if ($(this).scrollTop() === 0) {
            $(logos[0]).addClass('hidden');
            $(logos[1]).removeClass('hidden');
        } else {
            $(logos[1]).addClass('hidden');
            $(logos[0]).removeClass('hidden');
        }
    });
});
.scroll-logo.hidden {
  display: none;
}

/* below rules are for demo purposes only */

div {
  position: fixed; 
}

body{
  height: 8000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

<div>
    <!-- <?php echo $logoDiv; ?> -->
    <a href="https:url-1.com" class="scroll-logo hidden">
      Logo Text
    </a>
    <a href="//chrome.google.com" class="scroll-logo">
      <img src="//www.google.com/chrome/static/images/chrome-logo.svg" alt="Google Chrome"/>
    </a>
</div>

Since as you say, you want to change the href attribute of an element, a similar scroll technique can be used to alter element attributes as well. Allowing you to use a data attribute in order to specify the URL to change to.

Method B: change the url on scroll (using the data-url attribute)

$logoDiv = '<a href="'.esc_url( home_url( get_current_blog_id(), '/' ) ).'" class="navbar-brand"' . $data_padding_shrink . ' data-minheight="'.(($LOGO->logo_min == "") ? "20" : esc_attr($LOGO->logo_min)).'" data-url="https:url-1.com">';

jQuery(function($) { //same as $(document).ready()
    var logo = $('[data-url]');
    var newHref = logo.data('url');
    var originalHref = logo.attr('href');
    $(window).on('scroll', function(e) {
        if ($(this).scrollTop() === 0) {
            logo.attr('href', originalHref)
                .removeClass('hide_logo');
        } else {
            logo.attr('href', newHref)
                .addClass('hide_logo');
        }
    });
});
a.hide_logo img {
   display: none;
}

a.hide_logo:before {
    content: "Logo Text";
}

/* below is for demo purposes only */

div {
  position: fixed; 
}

body {
  height: 8000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

<div>
   <!-- <?php echo $logoDiv; ?> -->
    <a href="//chrome.google.com" data-url="https:url-1.com">
      <img src="//www.google.com/chrome/static/images/chrome-logo.svg" alt="Google Chrome"/>
    </a>
</div>

Method B + Scroll-Spy class

To run as a scroll-spy, listening for the class window-scrolled instead, you simply need to use hasClass instead of checking the position of scrollTop. Change the logo.hasClass to the appropriate element that has the class added to it.

jQuery(function($) { //same as $(document).ready()
    var logo = $('[data-url]');
    var newHref = logo.data('url');
    var originalHref = logo.attr('href');
    var scrollSpy = null;
    $(window).on('scroll', function(e) {
        if (null !== scrollSpy) {
            //cancel previous delay
            window.clearTimeout(scrollSpy);
        }
        //delay scrollSpy to ensure class is not added after checking
        scrollSpy = window.setTimeout(function() {
            if (!logo.hasClass('window-scrolled')) {
                logo.attr('href', originalHref);
            } else {
                logo.attr('href', newHref);
            }
        }, 250); //adjust timeout as desired
    });


    //--- demo purposes only (DO NOT USE BELOW) ---
    $(window).on('scroll', function(e) {
        if ($(this).scrollTop() === 0) {
            logo.removeClass('window-scrolled');
        } else {
            logo.addClass('window-scrolled');
        }
    });
});
a.window-scrolled img {
   display: none;
}

a.window-scrolled:before {
    content: "Logo Text";
}

/* below is for demo purposes only */

div {
  position: fixed; 
}

body {
  height: 8000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

<div>
   <!-- <?php echo $logoDiv; ?> -->
    <a href="//chrome.google.com" data-url="https:url-1.com">
      <img src="//www.google.com/chrome/static/images/chrome-logo.svg" alt="Google Chrome"/>
    </a>
</div>

Alternatively you can also use $('.window-scrolled').length === 0 to determine if any element has the class, or specify a desired element parent of window-scrolled like so $('[selector] .window-scrolled') (replace [selector] with the desired parent element selector ie. div.wrapper).

Will B.
  • 17,883
  • 4
  • 67
  • 69
  • Hi there, thank you for this - the issue I have though is that I am not actually swapping an image, it's essentially the same image but with different hrefs at different points. I can't seem to add two different logos in the php theme files so I have one image, then on scroll I hade the image and display a before pseudo class with text content. Because it's just a pseudo of the other, it behaves like one element - I hope that makes sense - what I need is to change one elements url. – Mr Toad Feb 03 '19 at 09:49
  • I could add the php to the original question – Mr Toad Feb 03 '19 at 09:50
  • @MrToad Render both elements in the same variable, add a `hidden` class to the element you want hidden. Once the template echos the html,from the variable, the css and js will handle the reset. This solution applies to any two elements, not just images. I used images to demonstrate how it would function. . – Will B. Feb 03 '19 at 10:07
  • @MrToad in other words `$logoDiv = '...';` – Will B. Feb 03 '19 at 10:16
  • I need to change the url on the same image - the logo only looks different because I change it to a psuedo class las added to the question – Mr Toad Feb 06 '19 at 07:36
  • @MrToad my answer demonstrates how to change the anchor link of the logo, using two methods, everything else is superficial since the desired end-result is not clear. Method A uses two separate anchor elements, hiding one element until scrolled and reverting back at the 0 position, Method B uses the `data-url` attribute to change the `href` attribute of the anchor element when scrolled, reverting back at the 0 position. Method B also uses the pseudo selector to display the `content` text and hide the image. – Will B. Feb 06 '19 at 13:58
  • Okay so I have managed to get this to work! But... the original logo doesn't swap out immediately on scroll. The class changes, switching the logo at an offset, at a guess, about 700px vertical scroll, though I would need to do some at trial and error with different heights. Is there any way to add a scroll point to this OR, hide is when the class .window-scrolled appears? At the moment, they both show for some of the scroll – Mr Toad Feb 07 '19 at 00:50
  • What are you using for scroll detection? – Will B. Feb 07 '19 at 01:42
  • How would I determine this? – Mr Toad Feb 07 '19 at 01:49
  • @MrToad I was referring to what you are using to add `window-scrolled` to the anchor element. I've added an alternative which will allow you to use a scroll-spy approach instead. It will listen during scrolling for the `window-scrolled` to be added. However it is more preferable to add on to the function that is adding `window-scrolled` to the anchor, as there may be a conflict on order of operations, where `window-scrolled` gets added AFTER the scroll-spy is executed. I attempted to account for the issue with `window.setTimeout`. – Will B. Feb 07 '19 at 13:55
  • @MrToad Otherwise you can adjust the `$(window).scrollTop() === 0` changing `0` to your desired offset of when `window-scrolled` gets added. i.e. `>= 700` – Will B. Feb 07 '19 at 14:16
  • Thank you so much for you time and your efforts. In the end I managed to get method 1 to work, thank you so much for your help. – Mr Toad Feb 09 '19 at 10:37
  • sorry @fyre - how would I swap the links around? so the img logo goes to an independant url and the text goes to the current_blog_id - I tried swapping them like so: `$logoDiv = 'logo_min)).'">Text logo logo_min)).'">';` – Mr Toad Feb 09 '19 at 10:52
  • With method A, just swapping the `href` values should work, unless there is something happening in javascript or the page is cached. Since all it's doing is hiding/displaying elements that have already been rendered in the browser. What is happening instead? – Will B. Feb 09 '19 at 11:03
  • As soon as I swap the href values around, it makes them both go to the same url - that being the offsite url – Mr Toad Feb 09 '19 at 11:13
  • Sounds like javascript is setting the swapped href somewhere. Since if the `href` is rendered in the source code on initial page load (with javascript disabled), nothing in method A or PHP can change it. Check by right-click "View Page Source", then find the line(s) containing the anchor elements, and ensure that the href is set properly for them. If so, you'll have to check your Javascript to see where it's being set/changed. – Will B. Feb 09 '19 at 11:37
  • Okay so I managed to swap over the logos - it's not the most elegant solution - but in the end, I swapped out the default wordpress logo img for the tagline which took care of that one, then I removed the 'text logo' from the php file and added a different class and then added an image psuedo class, thus swapping over the second image. It's working like a charm, thanks again – Mr Toad Feb 09 '19 at 12:47
0

You can use the following code in the page to change the image.

$(document).ready(function(){
    $( window ).scroll(function() {
    //change image css in here when scrolling
    if ($(window).scrollTop()==0) {
        //here you can set the initial logo when the screen comes back to the top
    }
      });
});
Yasii
  • 1,702
  • 1
  • 10
  • 15
  • Hi there, thank you for this - the issue I have though is that I am not actually swapping an image, it's essentially the same image but with different hrefs at different points. I can't seem to add two different logos in the php theme files so I have one image, then on scroll I hade the image and display a before pseudo class with text content. Because it's just a pseudo of the other, it behaves like one element - I hope that makes sense - what I need is to change one elements url. I could add the php to the original question – Mr Toad Feb 03 '19 at 09:50