diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb index 18c79f3cc..22922c6e5 100644 --- a/lib/liquid/standardfilters.rb +++ b/lib/liquid/standardfilters.rb @@ -3,6 +3,7 @@ require 'cgi' require 'base64' require 'bigdecimal' +require 'uri' module Liquid module StandardFilters @@ -99,6 +100,36 @@ def escape_once(input) input.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE) end + def url_add_param(input, key, value) + begin + uri = URI.parse(input) + uri.query = URI.encode_www_form( + URI.decode_www_form(uri.query || '') << [key, value] + ) + + uri.to_s + rescue URI::InvalidURIError + raise_property_error(input) + end + end + + def url_remove_param(input, key) + begin + uri = URI.parse(input) + query = URI.decode_www_form(uri.query || '').to_h + query.delete(key) + uri.query = if query.empty? + '' + else + URI.encode_www_form(query) + end + + uri.to_s + rescue URI::InvalidURIError + raise_property_error(input) + end + end + # @liquid_public_docs # @liquid_type filter # @liquid_category string diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb index b633024bd..d6862a36d 100644 --- a/test/integration/standard_filter_test.rb +++ b/test/integration/standard_filter_test.rb @@ -204,6 +204,30 @@ def test_base64_url_safe_decode assert_equal('Liquid error: invalid base64 provided to base64_url_safe_decode', exception.message) end + def test_url_add_param + assert_equal('https://shopify.com?foo=bar', @filters.url_add_param('https://shopify.com', 'foo', 'bar')) + assert_equal('https://shopify.com?foo=bar&baz=qux', @filters.url_add_param('https://shopify.com?foo=bar', 'baz', 'qux')) + assert_equal('https://shopify.com?foo=bar#baz', @filters.url_add_param('https://shopify.com#baz', 'foo', 'bar')) + assert_equal('not-an-url?foo=bar', @filters.url_add_param('not-an-url', 'foo', 'bar')) + assert_equal('not-an-url?foo=bar&baz=qux', @filters.url_add_param('not-an-url?foo=bar', 'baz', 'qux')) + assert_equal('not-an-url?foo=bar#baz', @filters.url_add_param('not-an-url#baz', 'foo', 'bar')) + assert_equal('?foo=bar', @filters.url_add_param('', 'foo', 'bar')) + assert_equal('?foo=bar&baz=qux', @filters.url_add_param('?foo=bar', 'baz', 'qux')) + assert_equal('?foo=bar#baz', @filters.url_add_param('#baz', 'foo', 'bar')) + end + + def test_url_remove_param + assert_equal('https://shopify.com?', @filters.url_remove_param('https://shopify.com?foo=bar', 'foo')) + assert_equal('https://shopify.com?foo=bar', @filters.url_remove_param('https://shopify.com?foo=bar&baz=qux', 'baz')) + assert_equal('https://shopify.com?#baz', @filters.url_remove_param('https://shopify.com?foo=bar#baz', 'foo')) + assert_equal('not-an-url?', @filters.url_remove_param('not-an-url', 'foo')) + assert_equal('not-an-url?foo=bar', @filters.url_remove_param('not-an-url?foo=bar&baz=qux', 'baz')) + assert_equal('not-an-url?#baz', @filters.url_remove_param('not-an-url#baz', 'foo')) + assert_equal('?', @filters.url_remove_param('?foo=bar', 'foo')) + assert_equal('?foo=bar', @filters.url_remove_param('?foo=bar&baz=qux', 'baz')) + assert_equal('?#baz', @filters.url_remove_param('?foo=bar#baz', 'foo')) + end + def test_url_encode assert_equal('foo%2B1%40example.com', @filters.url_encode('foo+1@example.com')) assert_equal('1', @filters.url_encode(1))