The answer to this question can be found here.
So assuming that you can't add products to your cart if they don't exist you can get around the problem that way:
Create a simple product with the data you want (which will not be displayed on the e-shop) with these parameters:
- Catalog visibility: Hidden
- Manage stock?: No (do not check the "Enable stock management at product level" option)
- Stock status: In Stock
Get the post data from the form and with the add_to_cart
method add the custom data for the cart item. Then with the hook woocommerce_before_calculate_totals
set the custom data to the item in the cart (in your case: name and price).
See Store custom data using WC_Cart add_to_cart() method in Woocommerce 3 answer code to understand how to do it.
EXAMPLE
You will need to create an add-product-to-cart.php file. Add it inside the directory where functions.php is located (inside the child theme folder). In the add-product-to-cart.php file insert the following code:
<?php
// load the Wordpress classes (change the directory based on where you uploaded your PHP file, currently works if this file is inside the child theme folder)
include_once( __DIR__ . "/../../../wp-load.php" );
if ( isset( $_POST['add_to_cart'] ) && $_POST['add_to_cart'] ) {
global $woocommerce;
$name = $_POST['name'];
$qty = (int) $_POST['q'];
$price = (float) str_replace( ',', '.', $_POST['price'] );
// set the id of the product created
$product_id = 736;
// gets the custom fields to set
$cart_item_data['custom_price'] = $price;
$cart_item_data['custom_name'] = $name;
// adds the product to the cart with custom data
$woocommerce->cart->add_to_cart( $product_id, $qty, $variation_id = 0, $variation = array(), $cart_item_data );
}
?>
<main>
<form action="add-product-to-cart.php" method="POST" enctype="multipart/form-data">
<input type="text" name="name" placeholder="Name" required/>
<input typoe="text" name="q" placeholder="Quantity" required/>
<input type="text" name="price" placeholder="Price" required/>
<input type="submit" name="add_to_cart" value="Pievienot grozam" />
</form>
</main>
The page url will look like (for example):
yourdomain.com/wp-content/themes/storefront-child/add-product-to-cart.php
First of all add these lines in your child theme's functions.php to include the custom page add-product-to-cart.php
:
// load the contents of the add-product-to-cart.php file only on the respective page
if ( isset($_SERVER['REQUEST_URI']) ) {
if ( strpos($_SERVER['REQUEST_URI'], 'add-product-to-cart.php') !== false ) {
require_once( 'add-product-to-cart.php' );
}
}
Also always in the functions.php file add this code:
// set the price and change the name of the cart item based on the form values
add_action( 'woocommerce_before_calculate_totals', 'set_custom_cart_item_data', 10, 1 );
function set_custom_cart_item_data( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
foreach ( $cart->get_cart() as $cart_item ) {
// if custom name and price are set, modify the product in the cart
if ( isset( $cart_item['custom_price'] ) && isset( $cart_item['custom_name'] ) ) {
$cart_item['data']->set_price( $cart_item['custom_price'] );
$cart_item['data']->set_name( $cart_item['custom_name'] );
}
}
}
Finally, to force the change of the name and price of the items in the cart (especially in the mini cart) add this:
// update the price of the cart item (especially in the mini cart)
add_filter( 'woocommerce_cart_item_price', 'custom_cart_item_price', 10, 3 );
function custom_cart_item_price( $price, $cart_item, $cart_item_key ) {
if ( isset( $cart_item['custom_price'] ) ) {
return wc_price( $cart_item['custom_price'] );
}
return $price;
}
// update the name of the cart item (especially in the mini cart)
add_filter( 'woocommerce_cart_item_name', 'custom_cart_item_name', 10, 3 );
function custom_cart_item_name( $item_name, $cart_item, $cart_item_key ) {
if ( isset( $cart_item['custom_name'] ) ) {
return $cart_item['custom_name'];
}
return $item_name;
}
The code has been tested and works.
POSSIBLE PROBLEMS
If you want to load the header into your custom php file you shouldn't use the get_header()
function unless you check first to see if it has already been loaded.
The notice PHP Notice: Trying to get property 'order_awaiting_payment' of non-object in...
will be shown on all pages where the header is loaded twice (be it the frontend or the backend).
SOLUTION #1
You can use a control (to be inserted in the functions.php of your active theme) to load the content of the custom page only when this is present in the url (so by exclusion it will not be loaded in all other pages) If your page is named differently, replace add-product-to-cart.php with the name of your page:
It is the same function as above.
// load the contents of the add-product-to-cart.php file only on the respective page
if ( isset($_SERVER['REQUEST_URI']) ) {
if ( strpos($_SERVER['REQUEST_URI'], 'add-product-to-cart.php') !== false ) {
require_once( 'add-product-to-cart.php' );
}
}
SOLUTION #2
You can load the header by adding an include_once
just after the wp-load.php
load line inside the add-product-to-cart.php file:
<?php
// load the Wordpress classes (change the directory based on where you uploaded your PHP file, currently works if this file is inside the child theme folder)
include_once( __DIR__ . "/../../../wp-load.php" );
include_once( __DIR__ . "/../../../wp-blog-header.php");
...