Re-writing slugs to be prepended by word and hyphen - php

I'm working with a function in wordpress (though this isn't necessarily wordpress specific). WP won't allow slugs more than 20 characters long so I'm trying to work with a function that will do what I want. I'm trying to get this structure: www.site.com/classifieds/medical-jobs. My post types each have a respective slug: 'gd_jobs' has a 'jobs' slug and 'gd_offices' has an 'offices' slug.
The current function successfully gets the 'classifieds' part right:
function gd_snippet_option_post_types( $value, $key, $default ) {
$post_types = array( 'gd_jobs', 'gd_offices' );
$top_level_item = 'classifieds';
foreach( $post_types as $post_type ){
if ( ! empty( $value[ $post_type ] ) && ! str_contains( $value[ $post_type ]['rewrite']['slug'], 'classifieds') ) {
$value[ $post_type ]['has_archive'] = $top_level_item . '/' . $value[ $post_type ]['rewrite']['slug'];
$value[ $post_type ]['rewrite']['slug'] = $top_level_item . '/' . $value[ $post_type ]['rewrite']['slug'];
}
}
return $value;
}
add_filter( 'geodir_get_option_post_types', 'gd_snippet_option_post_types', 21, 3 );
So this gives me www.site.com/classifieds/jobs but when I try the following, it gives the same result instead of classifieds/medical-jobs
function gd_snippet_option_post_types( $value, $key, $default ) {
$post_types = array( 'gd_place', 'gd_jobs', 'gd_classifieds', 'gd_general', 'gd_equipment', 'gd_services' ); // Top level item. , 'gd_classifieds', 'gd_general', 'gd_equipment', 'gd_services'
$top_level_item = 'classifieds';
foreach( $post_types as $post_type ){
if ( ! empty( $value[ $post_type ] ) && ! str_contains( $value[ $post_type ]['rewrite']['slug'], 'classifieds') ) {
$value[ $post_type ]['has_archive'] = $top_level_item . '/medical-' . $value[ $post_type ]['rewrite']['slug'];
$value[ $post_type ]['rewrite']['slug'] = $top_level_item . '/medical-' . $value[ $post_type ]['rewrite']['slug'];
}
}
return $value;
}
add_filter( 'geodir_get_option_post_types', 'gd_snippet_option_post_types', 21, 3 );
Am I missing something? I'm not sure why the first one works fine but the simple addition won't show even after flushing permalinks

Related

WooCommerce recently view product count

If I am using the following code to track recently viewed products...
/**
* Track user woocommerce viewed products.
*/
function dorzki_wc_track_product_views() {
if( ! is_singular( 'product' ) || is_active_widget( false, false, 'woocommerce_recently_viewed_products', true ) ) {
return;
}
global $post;
if ( empty( $_COOKIE['woocommerce_recently_viewed'] ) ) {
$viewed_products = array();
} else {
$viewed_products = wp_parse_id_list( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) );
}
$keys = array_flip( $viewed_products );
if ( isset( $keys[ $post->ID ] ) ) {
unset( $viewed_products[ $keys[ $post->ID ] ] );
}
$viewed_products[] = $post->ID;
if ( count( $viewed_products ) > 15 ) {
array_shift( $viewed_products );
}
wc_setcookie( 'woocommerce_recently_viewed', implode( '|', $viewed_products ) );
}
add_action( 'template_redirect', 'dorzki_wc_track_product_views', 20 );
and this code to display recently view products...
/**
* Display recently viewed products.
*/
function dorzki_wc_display_products_viewed() {
if ( empty( $_COOKIE['woocommerce_recently_viewed'] ) ) {
return;
}
$total_products = apply_filters( 'loop_shop_columns', get_option( 'woocommerce_catalog_columns', 4 ) );
$viewed_products = wp_parse_id_list( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) );
$products = array_slice( $viewed_products, 0, $total_products );
$ids = implode( ',', $products );
echo "<h2>" . esc_html__( 'Recently Viewed Products', 'dorzki' ) . "</h2>";
echo do_shortcode( "[products ids='{$ids}']" );
}
add_action( 'woocommerce_after_cart', 'dorzki_wc_display_products_viewed' );
How can I obtain the 'count'? Ideally I would like to create a shortcode that will output how many products the user has viewed recently.
I've tried this and I 'think' it works??
function recently_count() {
$total_products = apply_filters( 'loop_shop_columns', get_option( 'woocommerce_catalog_columns', 4 ) );
$viewed_products = wp_parse_id_list( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) );
$products = array_slice( $viewed_products, 0, $total_products );
$ids = implode( ',', $products );
if ($ids == 0) {
echo '0';
}
else {
echo count($ids);
}
}
add_shortcode( 'recently_count', 'recently_count' );
To just count the number of recently viewed products and return that in a shortcode, then you just have to count the exploded array of the cookie value.
Also, remember that you never echo a shortcode output, it must be returned.
function recently_count() {
return isset( $_COOKIE['woocommerce_recently_viewed'] ) ? count( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) ) : 0;
}
add_shortcode( 'recently_count', 'recently_count' );
This will return an integer.

How to add filter to hide out of stock products when searching for Upsells and Cross-sells in admin panel on the Linked Products tab (in woocommerce)?

On a single product, inside the admin panel, on the Linked Products tab (on woocommerce), i can set up Up-Sells and Cross-Sells Products. I can add the product i wish to link to by searching for it.
At the moment search gives all products, even the ones that are out of stock. I would like if i write down an id of a product that is out of stock, it won't appear on the list.
The function that is responsible for json result is
public static function json_search_products_and_variations() {
self::json_search_products( '', true );
}
public static function json_search_products( $term = '', $include_variations = false ) {
check_ajax_referer( 'search-products', 'security' );
if ( empty( $term ) && isset( $_GET['term'] ) ) {
$term = (string) wc_clean( wp_unslash( $_GET['term'] ) );
}
if ( empty( $term ) ) {
wp_die();
}
if ( ! empty( $_GET['limit'] ) ) {
$limit = absint( $_GET['limit'] );
} else {
$limit = absint( apply_filters( 'woocommerce_json_search_limit', 30 ) );
}
$include_ids = ! empty( $_GET['include'] ) ? array_map( 'absint', (array) wp_unslash( $_GET['include'] ) ) : array();
$exclude_ids = ! empty( $_GET['exclude'] ) ? array_map( 'absint', (array) wp_unslash( $_GET['exclude'] ) ) : array();
$exclude_types = array();
if ( ! empty( $_GET['exclude_type'] ) ) {
// Support both comma-delimited and array format inputs.
$exclude_types = wp_unslash( $_GET['exclude_type'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( ! is_array( $exclude_types ) ) {
$exclude_types = explode( ',', $exclude_types );
}
// Sanitize the excluded types against valid product types.
foreach ( $exclude_types as &$exclude_type ) {
$exclude_type = strtolower( trim( $exclude_type ) );
}
$exclude_types = array_intersect(
array_merge( array( 'variation' ), array_keys( wc_get_product_types() ) ),
$exclude_types
);
}
$data_store = WC_Data_Store::load( 'product' );
$ids = $data_store->search_products( $term, '', (bool) $include_variations, false, $limit, $include_ids, $exclude_ids );
$products = array();
foreach ( $ids as $id ) {
$product_object = wc_get_product( $id );
if ( ! wc_products_array_filter_readable( $product_object ) ) {
continue;
}
$formatted_name = $product_object->get_formatted_name();
$managing_stock = $product_object->managing_stock();
if ( in_array( $product_object->get_type(), $exclude_types, true ) ) {
continue;
}
if ( $managing_stock && ! empty( $_GET['display_stock'] ) ) {
$stock_amount = $product_object->get_stock_quantity();
/* Translators: %d stock amount */
$formatted_name .= ' – ' . sprintf( __( 'Stock: %d', 'woocommerce' ), wc_format_stock_quantity_for_display( $stock_amount, $product_object ) );
}
$products[ $product_object->get_id() ] = rawurldecode( $formatted_name );
}
wp_send_json( apply_filters( 'woocommerce_json_search_found_products', $products ) );
}
Before wp_send_json(...) how can i exclude from $products array the outofstock products?
Before
$products[ $product_object->get_id() ] = rawurldecode( $formatted_name );
the code
if ('outofstock' === $product_object->get_stock_status()){
continue;
}
worked for me.

Remove custom postype base slug and prefix permalink with custom taxonomy + post title or just post title

What I want to achieve seems pretty trivial still the solution is yet to be found:
I want to be able to avoid having the slug of the custom postype, (ie. article) and have in the permalink the custom taxonomy's (ie. site_topic) and its term (ie. blog) or if not set avoid having it and have just the normal title.
What's been tried so far to change the permalink structure:
(it does work in the dashboard swapping links as needed but the pages when visited result in a 404, and yes permalinks have been flushed at each edit).
function ms_post_types_permalink_edit( $permalink, $post, $leavename ) {
if ( in_array( $post->post_type, [ 'article', 'template' ] ) || 'publish' == $post->post_status ) {
$terms = wp_get_object_terms( $post->ID, 'site_topic' );
if( $terms ){
return str_replace( '/' . $post->post_type . '/', '/' . $terms[0]->slug . '/', $permalink );
}
return str_replace( '/' . $post->post_type . '/', '/', $permalink );
}
return str_replace( '/' . $post->post_type . '/', '/', $permalink );
}
add_filter( 'post_type_link', 'ms_post_types_permalink_edit', 10, 3 );
What we would like to achieve is a working permalink structure that works in both cases for these custom postypes while retaining the normal permalink structure for the rest of the postypes:
domain.com/custom-taxonomy-term/custom-post-title
domain.com/post-title
As a bonus the custom postype has the following in its registration:
....
'rewrite' => [
'with_front' => false,
'slug' => false,
]
....
What I also tried in combination with the above is both the following or a combination of them at once:
function ms_post_types_rewrite_rule() {
add_rewrite_rule('article/([^/]*)/?$', 'index.php?article=$matches[1]', 'top');
add_rewrite_rule('article/([^/]*)/([^/]*)?$', 'index.php?site_topic=$matches[1]&article="$matches[2]', 'top');
}
add_action('init', 'ms_post_types_rewrite_rule');
and
function ms_pre_get_posts( $query ) {
if ( ! $query->is_main_query() ) {
return;
}
if ( 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
return;
}
if ( ! empty( $query->query['name'] ) ) {
$query->set( 'post_type', [ 'article' ] );
}
}
add_action( 'pre_get_posts', 'ms_pre_get_posts' );
Use below code in your active themes function.php file
function remove_ra_slug( $post_link, $post, $leavename ) {
$terms = get_the_terms( $post->ID, 'site_topic' );
if ( !empty( $terms ) ){
// get the first term
$term = array_shift( $terms );
if ( 'article' != $post->post_type || 'publish' != $post->post_status ) {
return $post_link;
}
$post_link = str_replace( '/' . $post->post_type . '/', '/' . $terms->slug . '/', $post_link );
}
return $post_link;
}
add_filter( 'post_type_link', 'remove_ra_slug', 10, 3 );
Just removing the slug isn't enough. Right now, you'll get a 404 page because WordPress only expects posts and pages to behave this way. You'll also need to add the following:
function parse_ra_request( $query ) {
if ( ! $query->is_main_query() || 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
return;
}
if ( ! empty( $query->query['name'] ) ) {
$query->set( 'post_type', array( 'article' ) );
}
}
add_action( 'pre_get_posts', 'parse_ra_request' );
Tested and works well

Adding multiple items to WooCommerce cart at once

I have 3 IDs of the different items that I want to add to my shopping cart.
I could use https://url.com/shop/cart/?add-to-cart=3001 but when I want to add 3 items I can't do it. Is there any function/script I can add to add this ability to my shopping website?
I tried to add an & after the add-to-cart and tried to add a new value but GETs get overridden right?:
https://url.com/shop/cart/?add-to-cart=3001&add-to-cart=2002&add-to-cart=1001
I found the answer!
Simply add the following script to your theme's functions.php:
function woocommerce_maybe_add_multiple_products_to_cart() {
// Make sure WC is installed, and add-to-cart qauery arg exists, and contains at least one comma.
if ( ! class_exists( 'WC_Form_Handler' ) || empty( $_REQUEST['add-to-cart'] ) || false === strpos( $_REQUEST['add-to-cart'], ',' ) ) {
return;
}
// Remove WooCommerce's hook, as it's useless (doesn't handle multiple products).
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 );
$product_ids = explode( ',', $_REQUEST['add-to-cart'] );
$count = count( $product_ids );
$number = 0;
foreach ( $product_ids as $product_id ) {
if ( ++$number === $count ) {
// Ok, final item, let's send it back to woocommerce's add_to_cart_action method for handling.
$_REQUEST['add-to-cart'] = $product_id;
return WC_Form_Handler::add_to_cart_action();
}
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $product_id ) );
$was_added_to_cart = false;
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
continue;
}
$add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $adding_to_cart->product_type, $adding_to_cart );
/*
* Sorry.. if you want non-simple products, you're on your own.
*
* Related: WooCommerce has set the following methods as private:
* WC_Form_Handler::add_to_cart_handler_variable(),
* WC_Form_Handler::add_to_cart_handler_grouped(),
* WC_Form_Handler::add_to_cart_handler_simple()
*
* Why you gotta be like that WooCommerce?
*/
if ( 'simple' !== $add_to_cart_handler ) {
continue;
}
// For now, quantity applies to all products.. This could be changed easily enough, but I didn't need this feature.
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
wc_add_to_cart_message( array( $product_id => $quantity ), true );
}
}
}
// Fire before the WC_Form_Handler::add_to_cart_action callback.
add_action( 'wp_loaded', 'woocommerce_maybe_add_multiple_products_to_cart', 15 );
And then you can simply use http://shop.com/shop/cart/?add-to-cart=3001,3282 to add multiple items at once. Put a comma between different IDs.
Thanks to dsgnwrks for the solution.
In case anyone else comes by looking for this function like I did. I updated the top comment's code allowing it to work with woocommerce 3.5.3
// adds support for multi add to cart for 3rd party cart plugin
function woocommerce_maybe_add_multiple_products_to_cart() {
// Make sure WC is installed, and add-to-cart qauery arg exists, and contains at least one comma.
if ( ! class_exists( 'WC_Form_Handler' ) || empty( $_REQUEST['add-to-cart'] ) || false === strpos( $_REQUEST['add-to-cart'], ',' ) ) {
return;
}
// Remove WooCommerce's hook, as it's useless (doesn't handle multiple products).
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 );
$product_ids = explode( ',', $_REQUEST['add-to-cart'] );
$count = count( $product_ids );
$number = 0;
foreach ( $product_ids as $product_id ) {
if ( ++$number === $count ) {
// Ok, final item, let's send it back to woocommerce's add_to_cart_action method for handling.
$_REQUEST['add-to-cart'] = $product_id;
return WC_Form_Handler::add_to_cart_action();
}
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $product_id ) );
$was_added_to_cart = false;
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
continue;
}
// only works for simple atm
if ( $adding_to_cart->is_type( 'simple' ) ) {
// quantity applies to all products atm
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
wc_add_to_cart_message( array( $product_id => $quantity ), true );
}
}
}
}
add_action( 'wp_loaded', 'woocommerce_maybe_add_multiple_products_to_cart', 15 );
Thanks to #thatgerhard and dsgnwrks
I found a solution for support variations:
function woocommerce_maybe_add_multiple_products_to_cart() {
// Make sure WC is installed, and add-to-cart qauery arg exists, and contains at least one comma.
if ( ! class_exists( 'WC_Form_Handler' ) || empty( $_REQUEST['add-to-cart'] ) || false === strpos( $_REQUEST['add-to-cart'], ',' ) ) {
return;
}
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 );
$product_ids = explode( ',', $_REQUEST['add-to-cart'] );
$count = count( $product_ids );
$number = 0;
foreach ( $product_ids as $product_id ) {
if ( ++$number === $count ) {
// Ok, final item, let's send it back to woocommerce's add_to_cart_action method for handling.
$_REQUEST['add-to-cart'] = $product_id;
return WC_Form_Handler::add_to_cart_action();
}
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $product_id ) );
$was_added_to_cart = false;
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
continue;
}
if ( $adding_to_cart->is_type( 'simple' ) ) {
// quantity applies to all products atm
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
wc_add_to_cart_message( array( $product_id => $quantity ), true );
}
} else {
$variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( wp_unslash( $_REQUEST['variation_id'] ) );
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ) ); // WPCS: sanitization ok.
$missing_attributes = array();
$variations = array();
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
continue;
}
// If the $product_id was in fact a variation ID, update the variables.
if ( $adding_to_cart->is_type( 'variation' ) ) {
$variation_id = $product_id;
$product_id = $adding_to_cart->get_parent_id();
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
continue;
}
}
// Gather posted attributes.
$posted_attributes = array();
foreach ( $adding_to_cart->get_attributes() as $attribute ) {
if ( ! $attribute['is_variation'] ) {
continue;
}
$attribute_key = 'attribute_' . sanitize_title( $attribute['name'] );
if ( isset( $_REQUEST[ $attribute_key ] ) ) {
if ( $attribute['is_taxonomy'] ) {
// Don't use wc_clean as it destroys sanitized characters.
$value = sanitize_title( wp_unslash( $_REQUEST[ $attribute_key ] ) );
} else {
$value = html_entity_decode( wc_clean( wp_unslash( $_REQUEST[ $attribute_key ] ) ), ENT_QUOTES, get_bloginfo( 'charset' ) ); // WPCS: sanitization ok.
}
$posted_attributes[ $attribute_key ] = $value;
}
}
// If no variation ID is set, attempt to get a variation ID from posted attributes.
if ( empty( $variation_id ) ) {
$data_store = WC_Data_Store::load( 'product' );
$variation_id = $data_store->find_matching_product_variation( $adding_to_cart, $posted_attributes );
}
// Do we have a variation ID?
if ( empty( $variation_id ) ) {
throw new Exception( __( 'Please choose product options…', 'woocommerce' ) );
}
// Check the data we have is valid.
$variation_data = wc_get_product_variation_attributes( $variation_id );
foreach ( $adding_to_cart->get_attributes() as $attribute ) {
if ( ! $attribute['is_variation'] ) {
continue;
}
// Get valid value from variation data.
$attribute_key = 'attribute_' . sanitize_title( $attribute['name'] );
$valid_value = isset( $variation_data[ $attribute_key ] ) ? $variation_data[ $attribute_key ]: '';
/**
* If the attribute value was posted, check if it's valid.
*
* If no attribute was posted, only error if the variation has an 'any' attribute which requires a value.
*/
if ( isset( $posted_attributes[ $attribute_key ] ) ) {
$value = $posted_attributes[ $attribute_key ];
// Allow if valid or show error.
if ( $valid_value === $value ) {
$variations[ $attribute_key ] = $value;
} elseif ( '' === $valid_value && in_array( $value, $attribute->get_slugs() ) ) {
// If valid values are empty, this is an 'any' variation so get all possible values.
$variations[ $attribute_key ] = $value;
} else {
throw new Exception( sprintf( __( 'Invalid value posted for %s', 'woocommerce' ), wc_attribute_label( $attribute['name'] ) ) );
}
} elseif ( '' === $valid_value ) {
$missing_attributes[] = wc_attribute_label( $attribute['name'] );
}
}
if ( ! empty( $missing_attributes ) ) {
throw new Exception( sprintf( _n( '%s is a required field', '%s are required fields', count( $missing_attributes ), 'woocommerce' ), wc_format_list_of_items( $missing_attributes ) ) );
}
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations );
if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) ) {
wc_add_to_cart_message( array( $product_id => $quantity ), true );
}
}
}
}
add_action( 'wp_loaded', 'woocommerce_maybe_add_multiple_products_to_cart', 15 );
Here I had forced $_REQUEST[ 'add-to-cart' ] to take the intended product id. Overwriting global variable doesn't sound good approach but it keeps DRY approach and also make all native function available to user.
add_action( 'wp_loaded', 'add_multiple_to_cart_action', 20 );
function add_multiple_to_cart_action() {
if ( ! isset( $_REQUEST['multiple-item-to-cart'] ) || false === strpos( wp_unslash( $_REQUEST['multiple-item-to-cart'] ), '|' ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
return;
}
wc_nocache_headers();
$product_ids = apply_filters( 'woocommerce_add_to_cart_product_id', wp_unslash( $_REQUEST['multiple-item-to-cart'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$product_ids = explode( '|', $product_ids );
if( ! is_array( $product_ids ) ) return;
$product_ids = array_map( 'absint', $product_ids );
$was_added_to_cart = false;
$last_product_id = end($product_ids);
//stop re-direction
add_filter( 'woocommerce_add_to_cart_redirect', '__return_false' );
foreach ($product_ids as $index => $product_id ) {
$product_id = absint( $product_id );
if( empty( $product_id ) ) continue;
$_REQUEST['add-to-cart'] = $product_id;
if( $product_id === $last_product_id ) {
add_filter( 'option_woocommerce_cart_redirect_after_add', function() {
return 'yes';
} );
} else {
add_filter( 'option_woocommerce_cart_redirect_after_add', function() {
return 'no';
} );
}
WC_Form_Handler::add_to_cart_action();
}
}
Example:
https://your-domain/cart?multiple-item-to-cart=68|69
Thanks
Same answer as others, with support for multiple quantities.
Example url: http://store.amitbend.com/cart/?add-to-cart=188,187,189&quantities=3,2,1
function woocommerce_maybe_add_multiple_products_to_cart() {
// Make sure WC is installed, and add-to-cart qauery arg exists, and contains at least one comma.
if ( ! class_exists( 'WC_Form_Handler' ) || empty( $_REQUEST['add-to-cart'] ) || false === strpos( $_REQUEST['add-to-cart'], ',' ) ) {
return;
}
// Remove WooCommerce's hook, as it's useless (doesn't handle multiple products).
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 );
$product_ids = explode( ',', $_REQUEST['add-to-cart'] );
$quantities = explode( ',', $_REQUEST['quantities'] );
$count = count( $product_ids );
$number = 0;
foreach ( $product_ids as $product_id ) {
if ( ++$number === $count ) {
// Ok, final item, let's send it back to woocommerce's add_to_cart_action method for handling.
$_REQUEST['add-to-cart'] = $product_id;
return WC_Form_Handler::add_to_cart_action();
}
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $product_id ) );
$was_added_to_cart = false;
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
continue;
}
$add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $adding_to_cart->product_type, $adding_to_cart );
/*
* Sorry.. if you want non-simple products, you're on your own.
*
* Related: WooCommerce has set the following methods as private:
* WC_Form_Handler::add_to_cart_handler_variable(),
* WC_Form_Handler::add_to_cart_handler_grouped(),
* WC_Form_Handler::add_to_cart_handler_simple()
*
* Why you gotta be like that WooCommerce?
*/
if ( 'simple' !== $add_to_cart_handler ) {
continue;
}
// $_REQUEST['quantity'] = ! empty( $id_and_quantity[1] ) ? absint( $id_and_quantity[1] ) : 1;
$_REQUEST['quantity'] = ! empty( $quantities[$number] ) ? absint( $quantities[$number] ) : 1;
$quantity = empty( $quantities[$number - 1] ) ? 1 : wc_stock_amount( $quantities[$number - 1] );
// $quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
wc_add_to_cart_message( array( $product_id => $quantity ), true );
}
}
}
// Fire before the WC_Form_Handler::add_to_cart_action callback.
add_action( 'wp_loaded', 'woocommerce_maybe_add_multiple_products_to_cart', 15 );
// remove "added to cart" notice
add_filter( 'wc_add_to_cart_message_html', '__return_false' );
The correct syntax is
add-to-cart=product1id:quantity,product2id:quantity
This is the code
https://www.webroomtech.com/woocommerce-add-multiple-products-to-cart-via-url/
They don't show this syntax for quantities on the tutorial, I found it looking at the code.
WooCommerce 4.0, an easier way to do this is to use the template_redirect hook which fires early off in the process. In theory you could decode a URL and add multiple items to cart or POST a form and process the POST. The simplest form is:
add_action( 'template_redirect', function() {
if( ! isset( $_POST['products'] ) ) {
return;
}
$products = array_filter( $_POST['products'] );
foreach( $products as $product_id => $quantity ) {
WC()->cart->add_to_cart( $product_id, $quantity );
}
} );
If you don't want to code anything, you can create a grouped product with all the products you want to add to the cart added as Linked Products.
Then the url will be as follow:
https://url.com/shop/cart/?add-to-cart=3001&quantity[2002]=1&quantity[1001]=1
3001 = Grouped Product id
2002 = Linked Product1 id
1001 = Linked Product2 id
Don't forget to specify quantities.
Also, you can change the catalog visibility to "hidden" so that grouped product doesn't appear in your store.
I took a different approach to this. Instead of killing the WC_Form_Handler, I use it! I have it run for each product. This seems simpler to me.
You can use this alone, or also with the regular add-to-cart.
http://example.com?add-more-to-cart=1000,10001,10002
http://example.com?add-to-cart=1000&add-more-to-cart=10001,10002
class add_more_to_cart {
private $prevent_redirect = false; //used to prevent WC from redirecting if we have more to process
function __construct() {
if ( ! isset( $_REQUEST[ 'add-more-to-cart' ] ) ) return; //don't load if we don't have to
$this->prevent_redirect = 'no'; //prevent WC from redirecting so we can process additional items
add_action( 'wp_loaded', [ $this, 'add_more_to_cart' ], 21 ); //fire after WC does, so we just process extra ones
add_action( 'pre_option_woocommerce_cart_redirect_after_add', [ $this, 'intercept_option' ], 9000 ); //intercept the WC option to force no redirect
}
function intercept_option() {
return $this->prevent_redirect;
}
function add_more_to_cart() {
$product_ids = explode( ',', $_REQUEST['add-more-to-cart'] );
$count = count( $product_ids );
$number = 0;
foreach ( $product_ids as $product_id ) {
if ( ++$number === $count ) $this->prevent_redirect = false; //this is the last one, so let WC redirect if it wants to.
$_REQUEST['add-to-cart'] = $product_id; //set the next product id
WC_Form_Handler::add_to_cart_action(); //let WC run its own code
}
}
}
new add_more_to_cart;
support variations and quantities using add-to-cart and quantities
// Make sure WC is installed, and add-to-cart qauery arg exists, and contains at least one comma.
if ( ! class_exists( 'WC_Form_Handler' ) || empty( $_REQUEST['add-to-cart'] ) || false === strpos( $_REQUEST['add-to-cart'], ',' ) ) {
return;
}
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 );
$product_ids = explode( ',', $_REQUEST['add-to-cart'] );
$quantities = explode( ',', $_REQUEST['quantities'] );
$count = count( $product_ids );
$number = 0;
foreach ( $product_ids as $product_id ) {
if ( ++$number === $count ) {
// Ok, final item, let's send it back to woocommerce's add_to_cart_action method for handling.
$_REQUEST['add-to-cart'] = $product_id;
return WC_Form_Handler::add_to_cart_action();
}
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $product_id ) );
$was_added_to_cart = false;
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
continue;
}
if ( $adding_to_cart->is_type( 'simple' ) ) {
$_REQUEST['quantity'] = ! empty( $quantities[$number] ) ? absint( $quantities[$number] ) : 1;
$quantity = empty( $quantities[$number - 1] ) ? 1 : wc_stock_amount( $quantities[$number - 1] );
// quantity applies to all products atm
//$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
wc_add_to_cart_message( array( $product_id => $quantity ), true );
}
} else {
$variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( wp_unslash( $_REQUEST['variation_id'] ) );
$quantity = empty( $quantities[$number - 1] ) ? 1 : wc_stock_amount( wp_unslash( $quantities[$number - 1] ) ); // WPCS: sanitization ok.
$missing_attributes = array();
$variations = array();
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
continue;
}
// If the $product_id was in fact a variation ID, update the variables.
if ( $adding_to_cart->is_type( 'variation' ) ) {
$variation_id = $product_id;
$product_id = $adding_to_cart->get_parent_id();
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
continue;
}
}
// Gather posted attributes.
$posted_attributes = array();
foreach ( $adding_to_cart->get_attributes() as $attribute ) {
if ( ! $attribute['is_variation'] ) {
continue;
}
$attribute_key = 'attribute_' . sanitize_title( $attribute['name'] );
if ( isset( $_REQUEST[ $attribute_key ] ) ) {
if ( $attribute['is_taxonomy'] ) {
// Don't use wc_clean as it destroys sanitized characters.
$value = sanitize_title( wp_unslash( $_REQUEST[ $attribute_key ] ) );
} else {
$value = html_entity_decode( wc_clean( wp_unslash( $_REQUEST[ $attribute_key ] ) ), ENT_QUOTES, get_bloginfo( 'charset' ) ); // WPCS: sanitization ok.
}
$posted_attributes[ $attribute_key ] = $value;
}
}
// If no variation ID is set, attempt to get a variation ID from posted attributes.
if ( empty( $variation_id ) ) {
$data_store = WC_Data_Store::load( 'product' );
$variation_id = $data_store->find_matching_product_variation( $adding_to_cart, $posted_attributes );
}
// Do we have a variation ID?
if ( empty( $variation_id ) ) {
throw new Exception( __( 'Please choose product options…', 'woocommerce' ) );
}
// Check the data we have is valid.
$variation_data = wc_get_product_variation_attributes( $variation_id );
foreach ( $adding_to_cart->get_attributes() as $attribute ) {
if ( ! $attribute['is_variation'] ) {
continue;
}
// Get valid value from variation data.
$attribute_key = 'attribute_' . sanitize_title( $attribute['name'] );
$valid_value = isset( $variation_data[ $attribute_key ] ) ? $variation_data[ $attribute_key ]: '';
/**
* If the attribute value was posted, check if it's valid.
*
* If no attribute was posted, only error if the variation has an 'any' attribute which requires a value.
*/
if ( isset( $posted_attributes[ $attribute_key ] ) ) {
$value = $posted_attributes[ $attribute_key ];
// Allow if valid or show error.
if ( $valid_value === $value ) {
$variations[ $attribute_key ] = $value;
} elseif ( '' === $valid_value && in_array( $value, $attribute->get_slugs() ) ) {
// If valid values are empty, this is an 'any' variation so get all possible values.
$variations[ $attribute_key ] = $value;
} else {
throw new Exception( sprintf( __( 'Invalid value posted for %s', 'woocommerce' ), wc_attribute_label( $attribute['name'] ) ) );
}
} elseif ( '' === $valid_value ) {
$missing_attributes[] = wc_attribute_label( $attribute['name'] );
}
}
if ( ! empty( $missing_attributes ) ) {
throw new Exception( sprintf( _n( '%s is a required field', '%s are required fields', count( $missing_attributes ), 'woocommerce' ), wc_format_list_of_items( $missing_attributes ) ) );
}
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations );
if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) ) {
wc_add_to_cart_message( array( $product_id => $quantity ), true );
}
}
}
}
I've tried these solutions but nothing worked since init ran a few times and the products were adding a few times as well so the quantities were off.
In addition, I wanted to have the ability to add a coupon from the URL as well...
/*
* Init function
* 1. Apply coupon code from URL
* 2. Add to cart: Multiple products add via URL
*/
function nd_template_redirect() {
if( !isset( WC()->session ) || ( isset( WC()->session ) && !WC()->session->has_session() ) ) {
WC()->session->set_customer_session_cookie( true );
}
$product_ids = array();
$quantities = array();
if( isset( $_GET['add-to-cart'] ) ) {
if( false !== strpos( $_GET['add-to-cart'], ',' ) ) {
$product_ids = explode( ',', $_GET['add-to-cart'] );
}
}
if( isset( $_GET['quantity'] ) ) {
if( false !== strpos( $_GET['quantity'], ',' ) ) {
$quantities = explode( ',', $_GET['quantity'] );
}
}
if( !empty( $product_ids ) ) {
$products = array();
for( $i = 0; $i < count( $product_ids ); $i++ ) {
if( isset( $product_ids[ $i ] ) ) {
$products[ $product_ids[ $i ] ] = isset( $quantities[ $i ] ) ? $quantities[ $i ] : 1;
}
}
if( !empty( $products ) ) {
foreach( $products as $key => $value ) {
WC()->cart->add_to_cart( $key, $value );
}
}
}
if( isset( $_GET['coupon_code'] ) && empty( WC()->session->get( 'added_coupon_code' ) ) ) {
$coupon_code = esc_attr( $_GET['coupon_code'] );
if( !empty( $coupon_code ) && !WC()->cart->has_discount( $coupon_code ) ) {
WC()->cart->add_discount( $coupon_code );
WC()->session->set( 'added_coupon_code', true );
}
}
}
add_action( 'template_redirect', 'nd_template_redirect' );
/*
* Clear session variables on thank you page.
*/
function nd_woocommerce_thankyou( $order_id ) {
WC()->session->__unset( 'added_coupon_code' );
WC()->session->__unset( 'added_products_to_cart' );
}
add_action( 'woocommerce_thankyou', 'nd_woocommerce_thankyou' );
Example usage:
https://example.com/cart/?add-to-cart=19737,19713&quantity=2,1&coupon_code=TEST
A few notes:
This works with or without quantity and coupon code parameters, if you choose to omit them the quantity of the products that will be added to the cart will be 1.
The product ids have to be separated using commas without spaces.
Match the product ids with the quantity in the correct order, in this example 2 units of product 19737 will be added to the cart.
This solution works only for URLs that send the user to the cart page.
Considering correct syntax that would be the following to create the correct url.
www.website.com/cart/add-to-cart=[product1id]:[quantity],[product2id]:[quantity]
As I am extracting the product ID from a shortcode, and the quantity from another shortcode, how do I tell the system that if it is empty, don't show it.
The formula works fine, maybe because I use shortcode it fails and returns 0 which becomes 1, the code works for all quantity fields that have a value inserted, the url if it sees that it has no value, it returns 0 and adds the product as quantity 1.
function webroom_add_multiple_products_to_cart( $url = false ) {
// Make sure WC is installed, and add-to-cart qauery arg exists, and contains at least one comma.
if ( ! class_exists( 'WC_Form_Handler' ) || empty( $_REQUEST['add-to-cart'] ) || false === strpos( $_REQUEST['add-to-cart'], ',' ) ) {
return;
}
// Remove WooCommerce's hook, as it's useless (doesn't handle multiple products).
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 );
$product_ids = explode( ',', $_REQUEST['add-to-cart'] );
$count = count( $product_ids );
$number = 0;
foreach ( $product_ids as $id_and_quantity ) {
// Check for quantities defined in curie notation (<product_id>:<product_quantity>)
$id_and_quantity = explode( ':', $id_and_quantity );
$product_id = $id_and_quantity[0];
$_REQUEST['quantity'] = ! empty( $id_and_quantity[1] ) ? absint( $id_and_quantity[1] ) : 1;
if ( ++$number === $count ) {
// Ok, final item, let's send it back to woocommerce's add_to_cart_action method for handling.
$_REQUEST['add-to-cart'] = $product_id;
return WC_Form_Handler::add_to_cart_action( $url );
}
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $product_id ) );
$was_added_to_cart = false;
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
continue;
}
$add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $adding_to_cart->get_type(), $adding_to_cart );
// Variable product handling
if ( 'variable' === $add_to_cart_handler ) {
woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_variable', $product_id );
// Grouped Products
} elseif ( 'grouped' === $add_to_cart_handler ) {
woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_grouped', $product_id );
// Custom Handler
} elseif ( has_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler ) ){
do_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler, $url );
// Simple Products
} else {
woo_hack_invoke_private_method( 'WC_Form_Handler', 'add_to_cart_handler_simple', $product_id );
}
}
}
// Fire before the WC_Form_Handler::add_to_cart_action callback.
add_action( 'wp_loaded', 'webroom_add_multiple_products_to_cart', 15 );
/**
* Invoke class private method
*
* #since 0.1.0
*
* #param string $class_name
* #param string $methodName
*
* #return mixed
*/
function woo_hack_invoke_private_method( $class_name, $methodName ) {
if ( version_compare( phpversion(), '5.3', '<' ) ) {
throw new Exception( 'PHP version does not support ReflectionClass::setAccessible()', __LINE__ );
}
$args = func_get_args();
unset( $args[0], $args[1] );
$reflection = new ReflectionClass( $class_name );
$method = $reflection->getMethod( $methodName );
$method->setAccessible( true );
//$args = array_merge( array( $class_name ), $args );
$args = array_merge( array( $reflection ), $args );
return call_user_func_array( array( $method, 'invoke' ), $args );
}
Here I found the code and then I discovered this chat where they were talking about the same thing.

Issues with PHP classes and WordPress

I am currently trying to add new options to the Rename wp-login.php because it is barely being updated. The owner also allowed me to add new options to it.
The plugin functionality allows you to 'rename' /wp-admin/ and wp-login.php to a different location. I barely have any knowledge about PHP classes and, you guessed it, the whole plugin is basically created using PHP classes.
What I am trying to do:
When the field is empty, revert everything to /wp-admin/. Basically a disable option; I've got that, but when the field is left blank and you'll save it, it saves the value which was entered before. That's a problem; It should be empty when you save it blank.
Currently the field is in the "Permalinks" section of the settings menu, but I want to put the option in a custom page.
Also, how does this plugin saves the value of the field? I can't find anything, not even a register_setting function.
When I say 'the field', I'm talking about this field: <input id="rwl-page-input" type="text" name="rwl_page" value="' . $this->new_login_slug() . '">
Code is as follows:
<?php
if ( defined( 'ABSPATH' ) && ! class_exists( 'Rename_WP_Login' ) ) {
class Rename_WP_Login {
private $wp_login_php;
private function basename() {
return plugin_basename( __FILE__ );
}
private function path() {
return trailingslashit( dirname( __FILE__ ) );
}
private function use_trailing_slashes() {
return '/' === substr( get_option( 'permalink_structure' ), -1, 1 );
}
private function user_trailingslashit( $string ) {
return $this->use_trailing_slashes() ? trailingslashit( $string ) : untrailingslashit( $string );
}
private function wp_template_loader() {
global $pagenow;
$pagenow = 'index.php';
if ( ! defined( 'WP_USE_THEMES' ) ) {
define( 'WP_USE_THEMES', true );
}
wp();
if ( $_SERVER['REQUEST_URI'] === $this->user_trailingslashit( str_repeat( '-/', 10 ) ) ) {
$_SERVER['REQUEST_URI'] = $this->user_trailingslashit( '/wp-login-php/' );
}
require_once ABSPATH . WPINC . '/template-loader.php';
die;
}
private function new_login_slug() {
if (
( $slug = get_option( 'rwl_page' ) ) || (
is_multisite() &&
is_plugin_active_for_network( $this->basename() ) &&
( $slug = get_site_option( 'rwl_page', 'login' ) )
) ||
( $slug = 'login' )
) {
return $slug;
}
}
public function new_login_url( $scheme = null ) {
if ( get_option( 'permalink_structure' ) ) {
return $this->user_trailingslashit( home_url( '/', $scheme ) . $this->new_login_slug() );
} else {
return home_url( '/', $scheme ) . '?' . $this->new_login_slug();
}
}
public function __construct() {
register_activation_hook( $this->basename(), array( $this, 'activate' ) );
register_uninstall_hook( $this->basename(), array( 'Rename_WP_Login', 'uninstall' ) );
add_action( 'admin_init', array( $this, 'admin_init' ) );
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
add_action( 'network_admin_notices', array( $this, 'admin_notices' ) );
if ( is_multisite() && ! function_exists( 'is_plugin_active_for_network' ) ) {
require_once ABSPATH . '/wp-admin/includes/plugin.php';
}
add_filter( 'plugin_action_links_' . $this->basename(), array( $this, 'plugin_action_links' ) );
if ( is_multisite() && is_plugin_active_for_network( $this->basename() ) ) {
add_filter( 'network_admin_plugin_action_links_' . $this->basename(), array( $this, 'plugin_action_links' ) );
add_action( 'wpmu_options', array( $this, 'wpmu_options' ) );
add_action( 'update_wpmu_options', array( $this, 'update_wpmu_options' ) );
}
add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 1 );
add_action( 'wp_loaded', array( $this, 'wp_loaded' ) );
add_filter( 'site_url', array( $this, 'site_url' ), 10, 4 );
add_filter( 'network_site_url', array( $this, 'network_site_url' ), 10, 3 );
add_filter( 'wp_redirect', array( $this, 'wp_redirect' ), 10, 2 );
add_filter( 'site_option_welcome_email', array( $this, 'welcome_email' ) );
remove_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );
}
public function activate() {
add_option( 'rwl_redirect', '1' );
}
public static function uninstall() {
global $wpdb;
if ( is_multisite() ) {
$blogs = $wpdb->get_col( "SELECT blog_id FROM {$wpdb->blogs}" );
if ( $blogs ) {
foreach ( $blogs as $blog ) {
switch_to_blog( $blog );
delete_option( 'rwl_page' );
}
restore_current_blog();
}
delete_site_option( 'rwl_page' );
} else {
delete_option( 'rwl_page' );
}
}
public function wpmu_options() {
echo (
'<h3>' .
_x( 'Rename wp-login.php', 'Text string for settings page', 'rename-wp-login' ) .
'</h3>' .
'<p>' .
__( 'This option allows you to set a networkwide default, which can be overridden by individual sites. Simply go to to the site’s permalink settings to change the url.', 'rename-wp-login' ) .
'</p>' .
'<table class="form-table">' .
'<tr valign="top">' .
'<th scope="row">' .
__( 'Networkwide default', 'rename-wp-login' ) .
'</th>' .
'<td>' .
'<input id="rwl-page-input" type="text" name="rwl_page" value="' . get_site_option( 'rwl_page', 'login' ) . '">' .
'</td>' .
'</tr>' .
'</table>'
);
}
public function update_wpmu_options() {
if (
( $rwl_page = sanitize_title_with_dashes( $_POST['rwl_page'] ) ) &&
strpos( $rwl_page, 'wp-login' ) === false &&
! in_array( $rwl_page, $this->forbidden_slugs() )
) {
update_site_option( 'rwl_page', $rwl_page );
}
}
public function admin_init() {
global $pagenow;
add_settings_section(
'rename-wp-login-section',
_x( 'Rename wp-login.php', 'Text string for settings page', 'rename-wp-login' ),
array( $this, 'rwl_section_desc' ),
'permalink'
);
add_settings_field(
'rwl-page',
'<label for="rwl-page">' . __( 'Login url', 'rename-wp-login' ) . '</label>',
array( $this, 'rwl_page_input' ),
'permalink',
'rename-wp-login-section'
);
if ( isset( $_POST['rwl_page'] ) && $pagenow === 'options-permalink.php' ) {
if (
( $rwl_page = sanitize_title_with_dashes( $_POST['rwl_page'] ) ) &&
strpos( $rwl_page, 'wp-login' ) === false &&
! in_array( $rwl_page, $this->forbidden_slugs() )
) {
if ( is_multisite() && $rwl_page === get_site_option( 'rwl_page', 'login' ) ) {
delete_option( 'rwl_page' );
} else {
update_option( 'rwl_page', $rwl_page );
}
}
}
if ( get_option( 'rwl_redirect' ) ) {
delete_option( 'rwl_redirect' );
if ( is_multisite() && is_super_admin() && is_plugin_active_for_network( $this->basename() ) ) {
$redirect = network_admin_url( 'settings.php#rwl-page-input' );
} else {
$redirect = admin_url( 'options-permalink.php#rwl-page-input' );
}
wp_safe_redirect( $redirect );
die;
}
}
public function rwl_section_desc() {
if ( is_multisite() && is_super_admin() && is_plugin_active_for_network( $this->basename() ) ) {
echo (
'<p>' .
sprintf(
__( 'To set a networkwide default, go to %s.', 'rename-wp-login' ),
'<a href="' . esc_url( network_admin_url( 'settings.php#rwl-page-input' ) ) . '">' .
__( 'Network Settings', 'rename-wp-login' ) .
'</a>'
) .
'</p>'
);
}
}
public function rwl_page_input() {
if ( get_option( 'permalink_structure' ) ) {
echo '<code>' . trailingslashit( home_url() ) . '</code> <input id="rwl-page-input" type="text" name="rwl_page" value="' . $this->new_login_slug() . '">' . ( $this->use_trailing_slashes() ? ' <code>/</code>' : '' );
} else {
echo '<code>' . trailingslashit( home_url() ) . '?</code> <input id="rwl-page-input" type="text" name="rwl_page" value="' . $this->new_login_slug() . '">';
}
}
public function admin_notices() {
global $pagenow;
if ( ! is_network_admin() && $pagenow === 'options-permalink.php' && isset( $_GET['settings-updated'] ) ) {
echo '<div class="notice notice-success is-dismissible"><p>' . sprintf( __( 'Your login page is now here: %s. Bookmark this page!', 'rename-wp-login' ), '<strong>' . $this->new_login_url() . '</strong>' ) . '</p></div>';
}
}
public function plugin_action_links( $links ) {
if ( is_network_admin() && is_plugin_active_for_network( $this->basename() ) ) {
array_unshift( $links,
'<a href="' . esc_url( network_admin_url( 'settings.php#rwl-page-input' ) ) . '">' .
__( 'Settings', 'rename-wp-login' ) .
'</a>'
);
} elseif ( ! is_network_admin() ) {
array_unshift( $links,
'<a href="' . esc_url( admin_url( 'options-permalink.php#rwl-page-input' ) ) . '">' .
__( 'Settings', 'rename-wp-login' ) .
'</a>'
);
}
return $links;
}
public function plugins_loaded() {
global $pagenow;
load_plugin_textdomain( 'rename-wp-login' );
if (
! is_multisite() && (
strpos( $_SERVER['REQUEST_URI'], 'wp-signup' ) !== false ||
strpos( $_SERVER['REQUEST_URI'], 'wp-activate' ) !== false
)
) {
wp_die( __( 'This feature is not enabled.', 'rename-wp-login' ), '', array( 'response' => 403 ) );
}
$request = parse_url( $_SERVER['REQUEST_URI'] );
if ( (
strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false ||
untrailingslashit( $request['path'] ) === site_url( 'wp-login', 'relative' )
) &&
! is_admin()
) {
$this->wp_login_php = true;
$_SERVER['REQUEST_URI'] = $this->user_trailingslashit( '/' . str_repeat( '-/', 10 ) );
$pagenow = 'index.php';
} elseif (
untrailingslashit( $request['path'] ) === home_url( $this->new_login_slug(), 'relative' ) || (
! get_option( 'permalink_structure' ) &&
isset( $_GET[$this->new_login_slug()] ) &&
empty( $_GET[$this->new_login_slug()] )
) ) {
$pagenow = 'wp-login.php';
}
}
public function wp_loaded() {
global $pagenow;
if ( is_admin() && ! is_user_logged_in() && ! defined( 'DOING_AJAX' ) ) {
wp_die( __( 'You must log in to access the admin area.', 'rename-wp-login' ), '', array( 'response' => 403 ) );
}
$request = parse_url( $_SERVER['REQUEST_URI'] );
if (
$pagenow === 'wp-login.php' &&
$request['path'] !== $this->user_trailingslashit( $request['path'] ) &&
get_option( 'permalink_structure' )
) {
wp_safe_redirect( $this->user_trailingslashit( $this->new_login_url() ) . ( ! empty( $_SERVER['QUERY_STRING'] ) ? '?' . $_SERVER['QUERY_STRING'] : '' ) );
die;
} elseif ( $this->wp_login_php ) {
if (
( $referer = wp_get_referer() ) &&
strpos( $referer, 'wp-activate.php' ) !== false &&
( $referer = parse_url( $referer ) ) &&
! empty( $referer['query'] )
) {
parse_str( $referer['query'], $referer );
if (
! empty( $referer['key'] ) &&
( $result = wpmu_activate_signup( $referer['key'] ) ) &&
is_wp_error( $result ) && (
$result->get_error_code() === 'already_active' ||
$result->get_error_code() === 'blog_taken'
) ) {
wp_safe_redirect( $this->new_login_url() . ( ! empty( $_SERVER['QUERY_STRING'] ) ? '?' . $_SERVER['QUERY_STRING'] : '' ) );
die;
}
}
$this->wp_template_loader();
} elseif ( $pagenow === 'wp-login.php' ) {
global $error, $interim_login, $action, $user_login;
#require_once ABSPATH . 'wp-login.php';
die;
}
}
public function site_url( $url, $path, $scheme, $blog_id ) {
return $this->filter_wp_login_php( $url, $scheme );
}
public function network_site_url( $url, $path, $scheme ) {
return $this->filter_wp_login_php( $url, $scheme );
}
public function wp_redirect( $location, $status ) {
return $this->filter_wp_login_php( $location );
}
public function filter_wp_login_php( $url, $scheme = null ) {
if ( strpos( $url, 'wp-login.php' ) !== false ) {
if ( is_ssl() ) {
$scheme = 'https';
}
$args = explode( '?', $url );
if ( isset( $args[1] ) ) {
parse_str( $args[1], $args );
$url = add_query_arg( $args, $this->new_login_url( $scheme ) );
} else {
$url = $this->new_login_url( $scheme );
}
}
return $url;
}
public function welcome_email( $value ) {
return str_replace( 'wp-login.php', trailingslashit( get_site_option( 'rwl_page', 'login' ) ), $value );
}
public function forbidden_slugs() {
$wp = new WP;
return array_merge( $wp->public_query_vars, $wp->private_query_vars );
}
}
new Rename_WP_Login;
}
I would really, really appreciate it if anyone can help me out with this!
The first
Also, how does this plugin saves the value of the field? I can't find anything, not even a register_setting function.
This plugin save the value by this function:
public function update_wpmu_options() {
if (
( $rwl_page = sanitize_title_with_dashes( $_POST['rwl_page'] ) ) &&
strpos( $rwl_page, 'wp-login' ) === false &&
! in_array( $rwl_page, $this->forbidden_slugs() )
) {
update_site_option( 'rwl_page', $rwl_page );
}
}
You can read more at: update_site_option
In admin_init function have
add_settings_field(
'rwl-page',
'<label for="rwl-page">' . __( 'Login url', 'rename-wp-login' ) . '</label>',
array( $this, 'rwl_page_input' ),
'permalink',
'rename-wp-login-section'
);
This function will get value saved. If you let the field blank this value won't be update. That's why you got old value of it.
If you want revert all to old version you can remove this plugin.
Hope it can help.
I'm just coder had try this plugin not dev it. xD

Categories